diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 10038a80e..4d96b77ff 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -240,6 +240,10 @@ Main::Main(QWidget *parent) : #if !ETH_FATDB removeDockWidget(ui->dockWidget_accounts); +#endif +#if !ETH_EVMJIT + ui->jitvm->setEnabled(false); + ui->jitvm->setChecked(false); #endif installWatches(); startTimer(100); @@ -805,6 +809,7 @@ void Main::readSettings(bool _skipGeometry) ui->usePrivate->setChecked(m_privateChain.size()); ui->verbosity->setValue(s.value("verbosity", 1).toInt()); ui->jitvm->setChecked(s.value("jitvm", true).toBool()); + on_jitvm_triggered(); ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html on_urlEdit_returnPressed(); @@ -1240,7 +1245,9 @@ void Main::refreshBlockCount() { auto d = ethereum()->blockChain().details(); 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("%10/%11%12 hashes %3 importing %4 ready %5 verifying %6 unverified %7 future %8 unknown %9 bad %1 #%2") + .arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.importing).arg(b.verified).arg(b.verifying).arg(b.unverified).arg(b.future).arg(b.unknown).arg(b.bad).arg(h.received).arg(h.estimated ? "~" : "").arg(h.total)); } void Main::on_turboMining_triggered() @@ -2114,14 +2121,14 @@ void Main::on_reencryptKey_triggered() auto pw = [&](){ auto p = QInputDialog::getText(this, "Re-Encrypt Key", "Enter the original password for this key.\nHint: " + QString::fromStdString(m_keyManager.hint(a)), QLineEdit::Password, QString()).toStdString(); if (p.empty()) - throw UnknownPassword(); + throw PasswordUnknown(); return p; }; while (!(password.empty() ? m_keyManager.recode(a, SemanticPassword::Master, pw, kdf) : m_keyManager.recode(a, password, hint, pw, kdf))) if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) return; } - catch (UnknownPassword&) {} + catch (PasswordUnknown&) {} } } @@ -2137,13 +2144,13 @@ void Main::on_reencryptAll_triggered() while (!m_keyManager.recode(a, SemanticPassword::Existing, [&](){ auto p = QInputDialog::getText(nullptr, "Re-Encrypt Key", QString("Enter the original password for key %1.\nHint: %2").arg(QString::fromStdString(pretty(a))).arg(QString::fromStdString(m_keyManager.hint(a))), QLineEdit::Password, QString()).toStdString(); if (p.empty()) - throw UnknownPassword(); + throw PasswordUnknown(); return p; }, (KDF)kdfs.indexOf(kdf))) if (QMessageBox::question(this, "Re-Encrypt Key", "Password given is incorrect. Would you like to try again?", QMessageBox::Retry, QMessageBox::Cancel) == QMessageBox::Cancel) return; } - catch (UnknownPassword&) {} + catch (PasswordUnknown&) {} } void Main::on_go_triggered() diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 193f8e364..efff89d2b 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -238,7 +238,7 @@ private: void installNameRegWatch(); void installBalancesWatch(); - virtual void timerEvent(QTimerEvent*); + virtual void timerEvent(QTimerEvent*) override; void refreshNetwork(); void refreshMining(); diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 7aeafec41..241df4e06 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -39,17 +39,17 @@ class NatspecHandler: public NatSpecFace ~NatspecHandler(); /// 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 std::string retrieve(dev::h256 const& _contractHash) const override; /// 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 /// user notice for that transaction. /// @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 - 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: ldb::ReadOptions m_readOptions; diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index e61092f33..fd466e475 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -360,7 +360,7 @@ void Transact::rejigData() return; } else - gasNeeded = (qint64)min(ethereum()->gasLimitRemaining(), ((b - value()) / gasPrice())); + gasNeeded = (qint64)min(ethereum()->gasLimitRemaining(), ((b - value()) / max(gasPrice(), 1))); // Dry-run execution to determine gas requirement and any execution errors Address to; diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index eb8588ceb..53535a489 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -21,7 +21,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE") if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -fcolor-diagnostics -Qunused-arguments -DBOOST_ASIO_HAS_CLANG_LIBCXX") diff --git a/eth/main.cpp b/eth/main.cpp index 7a85141f4..5497a2cda 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -84,15 +84,24 @@ void interactiveHelp() << " minestop Stops mining." << endl << " mineforce Forces mining, even when there are no transactions." << endl << " block Gives the current block height." << endl + << " blockhashfromnumber Gives the block hash with the givne number." << endl + << " numberfromblockhash Gives the block number with the given hash." << endl + << " blockqueue Gives the current block queue status." << endl + << " findblock Searches for the block in the blockchain and blockqueue." << endl + << " firstunknown Gives the first unknown block from the blockqueue." << endl + << " retryunknown retries to import all unknown blocks from the blockqueue." << endl << " accounts Gives information on all owned accounts (balances, mining beneficiary and default signer)." << endl << " newaccount Creates a new account with the given name." << endl << " transact Execute a given transaction." << endl + << " txcreate Execute a given contract creation transaction." << endl << " send Execute a given transaction with current secret." << endl << " contract Create a new contract with current secret." << endl << " peers List the peers that are connected" << endl #if ETH_FATDB || !ETH_TRUE << " listaccounts List the accounts on the network." << endl << " listcontracts List the contracts on the network." << endl + << " balanceat
Gives the balance of the given account." << endl + << " codeat
Gives the code of the given account." << endl #endif << " setsigningkey Set the address with which to sign transactions." << endl << " setaddress Set the coinbase (mining payout) address." << endl @@ -125,6 +134,7 @@ void help() << " --session-sign-key
Sign all transactions with the key of the given address for this session only." << endl << " --master Give the master password for the key store." << endl << " --password Give a password for a private key." << endl + << " --sentinel Set the sentinel for reporting bad blocks or chain issues." << endl << endl << "Client transacting:" << endl /*<< " -B,--block-fees Set the block fee profit in the reference unit e.g. ยข (default: 15)." << endl @@ -137,6 +147,7 @@ void help() << " -a,--address Set the coinbase (mining payout) address to addr (default: auto)." << endl << " -m,--mining 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 + << " --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 << " -G,--opencl When mining use the GPU via OpenCL." << endl << " --opencl-platform 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; WithExisting killChain = WithExisting::Trust; bool jit = false; + string sentinel; /// Networking params. string clientName; @@ -293,6 +305,7 @@ int main(int argc, char** argv) /// Mining params unsigned mining = 0; bool forceMining = false; + bool mineOnWrongChain = false; Address signingKey; Address sessionKey; Address beneficiary = signingKey; @@ -375,6 +388,10 @@ int main(int argc, char** argv) mode = OperationMode::Export; 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) { string m = argv[++i]; @@ -670,6 +687,8 @@ int main(int argc, char** argv) nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(), netPrefs, &nodesState); + web3.ethereum()->setMineOnBadChain(mineOnWrongChain); + web3.ethereum()->setSentinel(sentinel); auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") @@ -961,9 +980,88 @@ int main(int argc, char** argv) cout << "Current mining beneficiary:" << endl << beneficiary << endl; cout << "Current signing account:" << endl << signingKey << endl; } + else if (c && cmd == "blockhashfromnumber") + { + if (iss.peek() != -1) + { + unsigned number; + iss >> number; + cout << " hash of block: " << c->hashFromNumber(number).hex() << endl; + } + } + else if (c && cmd == "numberfromblockhash") + { + if (iss.peek() != -1) + { + string stringHash; + iss >> stringHash; + + h256 hash = h256(fromHex(stringHash)); + cout << " number of block: " << c->numberFromHash(hash) << endl; + } + } else if (c && cmd == "block") { - cout << "Current block: " <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") { @@ -1077,6 +1175,64 @@ int main(int argc, char** argv) else cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA"; } + else if (c && cmd == "txcreate") + { + auto const& bc =c->blockChain(); + auto h = bc.currentHash(); + auto blockData = bc.block(h); + BlockInfo info(blockData); + if (iss.peek() != -1) + { + u256 amount; + u256 gasPrice; + u256 gas; + string sechex; + string sdata; + + iss >> amount >> gasPrice >> gas >> sechex >> sdata; + + if (!gasPrice) + gasPrice = gasPricer->bid(priority); + + cnote << "Data:"; + cnote << sdata; + bytes data = dev::eth::parseData(sdata); + cnote << "Bytes:"; + string sbd = asString(data); + bytes bbd = asBytes(sbd); + stringstream ssbd; + ssbd << bbd; + cnote << ssbd.str(); + int ssize = sechex.length(); + u256 minGas = (u256)Transaction::gasRequired(data, 0); + if (gas < minGas) + cwarn << "Minimum gas amount is" << minGas; + else if (ssize < 40) + { + if (ssize > 0) + cwarn << "Invalid secret length:" << ssize; + } + else + { + try + { + Secret secret = h256(fromHex(sechex)); + cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl; + } + catch (BadHexCharacter& _e) + { + cwarn << "invalid hex character, transaction rejected"; + cwarn << boost::diagnostic_information(_e); + } + catch (...) + { + cwarn << "transaction rejected"; + } + } + } + else + cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET INIT"; + } #if ETH_FATDB else if (c && cmd == "listcontracts") { @@ -1100,6 +1256,43 @@ int main(int argc, char** argv) cout << ss << endl; } } + else if (c && cmd == "balanceat") + { + if (iss.peek() != -1) + { + string stringHash; + iss >> stringHash; + + Address address = h160(fromHex(stringHash)); + + cout << "balance of " << stringHash << " is: " << toString(c->balanceAt(address)) << endl; + } + } + // TODO implement << operator for std::unorderd_map +// else if (c && cmd == "storageat") +// { +// if (iss.peek() != -1) +// { +// string stringHash; +// iss >> stringHash; + +// Address address = h160(fromHex(stringHash)); + +// cout << "storage at " << stringHash << " is: " << c->storageAt(address) << endl; +// } +// } + else if (c && cmd == "codeat") + { + if (iss.peek() != -1) + { + string stringHash; + iss >> stringHash; + + Address address = h160(fromHex(stringHash)); + + cout << "code at " << stringHash << " is: " << toHex(c->codeAt(address)) << endl; + } + } #endif else if (c && cmd == "send") { diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index 639e1d4f4..d2ec13b2a 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -102,6 +102,7 @@ public: List, New, Import, + ImportWithAddress, Export, Recode, Kill @@ -159,6 +160,13 @@ public: m_inputs = strings(1, argv[++i]); m_name = argv[++i]; } + else if ((arg == "-i" || arg == "--import-with-address") && i + 3 < argc) + { + m_mode = OperationMode::ImportWithAddress; + m_inputs = strings(1, argv[++i]); + m_address = Address(argv[++i]); + m_name = argv[++i]; + } else if (arg == "--export") m_mode = OperationMode::Export; else if (arg == "--recode") @@ -314,6 +322,33 @@ public: cout << " ICAP: " << ICAP(k.address()).encoded() << endl; break; } + case OperationMode::ImportWithAddress: + { + string const& i = m_inputs[0]; + h128 u; + bytes b; + b = fromHex(i); + if (b.size() != 32) + { + std::string s = contentsString(i); + b = fromHex(s); + if (b.size() != 32) + u = wallet.store().importKey(i); + } + if (!u && b.size() == 32) + u = wallet.store().importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); + if (!u) + { + cerr << "Cannot import " << i << " not a file or secret." << endl; + break; + } + wallet.importExisting(u, m_name, m_address); + cout << "Successfully imported " << i << ":" << endl; + cout << " Name: " << m_name << endl; + cout << " Address: " << m_address << endl; + cout << " UUID: " << toUUID(u) << endl; + break; + } case OperationMode::List: { vector bare; @@ -369,6 +404,7 @@ public: << " -l,--list List all keys available in wallet." << endl << " -n,--new Create a new key with given name and add it in the wallet." << endl << " -i,--import [||] Import keys from given source and place in wallet." << endl + << " --import-with-address [||]
Import keys from given source with given address and place in wallet." << endl << " -e,--export [
| , ... ] Export given keys." << endl << " -r,--recode [
|| , ... ] Decrypt and re-encrypt given keys." << endl << "Wallet configuration:" << endl @@ -418,8 +454,9 @@ private: string m_lockHint; bool m_icap = true; - /// Creating + /// Creating/importing string m_name; + Address m_address; /// Importing strings m_inputs; diff --git a/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt index d364f6ed1..df828bc47 100644 --- a/ethminer/CMakeLists.txt +++ b/ethminer/CMakeLists.txt @@ -5,7 +5,10 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) +if (JSONRPC) +include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) +endif() set(EXECUTABLE ethminer) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 6a42dd774..245b97ceb 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -127,6 +127,11 @@ public: cerr << "Bad " << arg << " option: " << argv[i] << endl; throw BadArgument(); } + else if (arg == "--list-devices") + { + ProofOfWork::GPUMiner::listDevices(); + exit(0); + } else if (arg == "--use-chunks") { dagChunks = 4; @@ -175,7 +180,7 @@ public: m_minerType = MinerType::CPU; 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; m_minerType = MinerType::CPU; diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 5193168a4..68161526d 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -18,7 +18,7 @@ namespace eth extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below -bytesConstRef JitVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) +bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) { using namespace jit; @@ -33,7 +33,7 @@ bytesConstRef JitVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, ui { cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter"; m_fallbackVM = VMFactory::create(VMKind::Interpreter); - return m_fallbackVM->go(io_gas, _ext, _onOp, _step); + return m_fallbackVM->execImpl(io_gas, _ext, _onOp); } m_data.gas = static_cast(io_gas); @@ -51,7 +51,7 @@ bytesConstRef JitVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, ui m_data.timestamp = static_cast(_ext.currentBlock.timestamp); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); - m_data.codeHash = eth2llvm(sha3(_ext.code)); + m_data.codeHash = eth2llvm(_ext.codeHash); auto env = reinterpret_cast(&_ext); auto exitCode = m_engine.run(&m_data, env); diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h index e6864f885..e97abd83b 100644 --- a/evmjit/libevmjit-cpp/JitVM.h +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -11,7 +11,7 @@ namespace eth class JitVM: public VMFace { public: - virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) override final; private: jit::RuntimeData m_data; diff --git a/json_spirit/json_spirit_writer_template.h b/json_spirit/json_spirit_writer_template.h index dbd0f45da..5376ef476 100644 --- a/json_spirit/json_spirit_writer_template.h +++ b/json_spirit/json_spirit_writer_template.h @@ -25,13 +25,9 @@ namespace json_spirit return 'A' - 10 + ch; } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-local-typedefs") template< class String_type > String_type non_printable_to_string( unsigned int c ) { - typedef typename String_type::value_type Char_type; - String_type result( 6, '\\' ); result[1] = 'u'; @@ -43,7 +39,6 @@ namespace json_spirit return result; } -#pragma GCC diagnostic pop template< typename Char_type, class String_type > bool add_esc_char( Char_type c, String_type& s ) diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index cb9b94de8..3dc3fd280 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -28,7 +28,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.23"; +char const* Version = "0.9.24"; const u256 UndefinedU256 = ~(u256)0; diff --git a/libdevcore/CommonData.cpp b/libdevcore/CommonData.cpp index f8d8c172f..2d6333f26 100644 --- a/libdevcore/CommonData.cpp +++ b/libdevcore/CommonData.cpp @@ -67,7 +67,7 @@ std::string dev::randomWord() return ret; } -int dev::fromHex(char _i) +int dev::fromHex(char _i, WhenError _throw) { if (_i >= '0' && _i <= '9') return _i - '0'; @@ -75,7 +75,10 @@ int dev::fromHex(char _i) return _i - 'a' + 10; if (_i >= 'A' && _i <= 'F') return _i - 'A' + 10; - BOOST_THROW_EXCEPTION(BadHexCharacter() << errinfo_invalidSymbol(_i)); + if (_throw == WhenError::Throw) + BOOST_THROW_EXCEPTION(BadHexCharacter() << errinfo_invalidSymbol(_i)); + else + return -1; } bytes dev::fromHex(std::string const& _s, WhenError _throw) @@ -85,33 +88,26 @@ bytes dev::fromHex(std::string const& _s, WhenError _throw) ret.reserve((_s.size() - s + 1) / 2); if (_s.size() % 2) - try - { - ret.push_back(fromHex(_s[s++])); - } - catch (...) - { - ret.push_back(0); - // msvc does not support it -#ifndef BOOST_NO_EXCEPTIONS - cwarn << boost::current_exception_diagnostic_information(); -#endif - if (_throw == WhenError::Throw) - throw; - } + { + int h = fromHex(_s[s++], WhenError::DontThrow); + if (h != -1) + ret.push_back(h); + else if (_throw == WhenError::Throw) + throw BadHexCharacter(); + else + return bytes(); + } for (unsigned i = s; i < _s.size(); i += 2) - try - { - ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1]))); - } - catch (...){ - ret.push_back(0); -#ifndef BOOST_NO_EXCEPTIONS - cwarn << boost::current_exception_diagnostic_information(); -#endif - if (_throw == WhenError::Throw) - throw; - } + { + int h = fromHex(_s[i], WhenError::DontThrow); + int l = fromHex(_s[i + 1], WhenError::DontThrow); + if (h != -1 && l != -1) + ret.push_back((byte)(h * 16 + l)); + else if (_throw == WhenError::Throw) + throw BadHexCharacter(); + else + return bytes(); + } return ret; } diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index e1d8d7bdb..ddc00e09f 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -61,7 +61,7 @@ std::string toHex(_T const& _data, int _w = 2, HexPrefix _prefix = HexPrefix::Do /// Converts a (printable) ASCII hex character into the correspnding integer value. /// @example fromHex('A') == 10 && fromHex('f') == 15 && fromHex('5') == 5 -int fromHex(char _i); +int fromHex(char _i, WhenError _throw); /// Converts a (printable) ASCII hex string into the corresponding byte stream. /// @example fromHex("41626261") == asBytes("Abba") diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 025568efa..b0bab7d81 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -30,7 +30,8 @@ namespace dev { -// base class for all exceptions + +/// Base class for all exceptions. struct Exception: virtual std::exception, virtual boost::exception { Exception(std::string _message = std::string()): m_message(std::move(_message)) {} @@ -40,20 +41,26 @@ private: std::string m_message; }; -struct BadHexCharacter: virtual Exception {}; -struct RLPException: virtual Exception {}; -struct BadCast: virtual RLPException {}; -struct BadRLP: virtual RLPException {}; -struct OversizeRLP: virtual RLPException {}; -struct UndersizeRLP: virtual RLPException {}; -struct NoNetworking: virtual Exception {}; -struct NoUPnPDevice: virtual Exception {}; -struct RootNotFound: virtual Exception {}; -struct BadRoot: virtual Exception {}; -struct FileError: virtual Exception {}; -struct Overflow: virtual Exception {}; +#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { const char* what() const noexcept override { return #X; } } + +/// Base class for all RLP exceptions. +struct RLPException: virtual Exception { RLPException(std::string _message = std::string()): Exception(_message) {} }; +#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { const char* what() const noexcept override { return #X; } } + +DEV_SIMPLE_EXCEPTION_RLP(BadCast); +DEV_SIMPLE_EXCEPTION_RLP(BadRLP); +DEV_SIMPLE_EXCEPTION_RLP(OversizeRLP); +DEV_SIMPLE_EXCEPTION_RLP(UndersizeRLP); + +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 FailedInvariant: virtual Exception {}; struct ExternalFunctionFailure: virtual Exception { public: ExternalFunctionFailure(std::string _f): Exception("Function " + _f + "() failed.") {} }; // error information to be added to exceptions @@ -66,5 +73,7 @@ using errinfo_min = boost::error_info; using errinfo_max = boost::error_info; using RequirementError = boost::tuple; using errinfo_hash256 = boost::error_info; -using HashMismatchError = boost::tuple; +using errinfo_required_h256 = boost::error_info; +using errinfo_got_h256 = boost::error_info; +using Hash256RequirementError = boost::tuple; } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 9b25837af..88bc0fe95 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -113,7 +113,7 @@ public: /// @returns an abridged version of the hash as a user-readable hex string. std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } - /// @returns an abridged version of the hash as a user-readable hex string. + /// @returns the hash as a user-readable hex string. std::string hex() const { return toHex(ref()); } /// @returns a mutable byte vector_ref to the object's data. diff --git a/libdevcore/Log.cpp b/libdevcore/Log.cpp index f28a2c6b9..1e5c2d8ab 100644 --- a/libdevcore/Log.cpp +++ b/libdevcore/Log.cpp @@ -40,6 +40,14 @@ mutex x_logOverride; /// or equal to the currently output verbosity (g_logVerbosity). static map 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): m_ch(_ch) { diff --git a/libdevcore/Log.h b/libdevcore/Log.h index ce0db17fe..e732ac73c 100644 --- a/libdevcore/Log.h +++ b/libdevcore/Log.h @@ -73,6 +73,9 @@ public: LogOverride(bool _value): LogOverrideAux(&typeid(Channel), _value) {} }; +bool isChannelVisible(std::type_info const* _ch, bool _default); +template 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. /// Not thread-safe, use with caution! struct VerbosityHolder diff --git a/libdevcore/MemoryDB.cpp b/libdevcore/MemoryDB.cpp index 2cf56475b..f71931bdd 100644 --- a/libdevcore/MemoryDB.cpp +++ b/libdevcore/MemoryDB.cpp @@ -32,7 +32,9 @@ const char* DBWarn::name() { return "TDB"; } std::unordered_map MemoryDB::get() const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif std::unordered_map ret; for (auto const& i: m_main) if (!m_enforceRefs || i.second.second > 0) @@ -44,8 +46,10 @@ MemoryDB& MemoryDB::operator=(MemoryDB const& _c) { if (this == &_c) return *this; +#if DEV_GUARDED_DB ReadGuard l(_c.x_this); WriteGuard l2(x_this); +#endif m_main = _c.m_main; m_aux = _c.m_aux; return *this; @@ -53,7 +57,9 @@ MemoryDB& MemoryDB::operator=(MemoryDB const& _c) std::string MemoryDB::lookup(h256 const& _h) const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif auto it = m_main.find(_h); if (it != m_main.end()) { @@ -67,7 +73,9 @@ std::string MemoryDB::lookup(h256 const& _h) const bool MemoryDB::exists(h256 const& _h) const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif auto it = m_main.find(_h); if (it != m_main.end() && (!m_enforceRefs || it->second.second > 0)) return true; @@ -76,7 +84,9 @@ bool MemoryDB::exists(h256 const& _h) const void MemoryDB::insert(h256 const& _h, bytesConstRef _v) { +#if DEV_GUARDED_DB WriteGuard l(x_this); +#endif auto it = m_main.find(_h); if (it != m_main.end()) { @@ -92,7 +102,9 @@ void MemoryDB::insert(h256 const& _h, bytesConstRef _v) bool MemoryDB::kill(h256 const& _h) { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif if (m_main.count(_h)) { if (m_main[_h].second > 0) @@ -117,9 +129,38 @@ bool MemoryDB::kill(h256 const& _h) return false; } +bytes MemoryDB::lookupAux(h256 const& _h) const +{ +#if DEV_GUARDED_DB + ReadGuard l(x_this); +#endif + auto it = m_aux.find(_h); + if (it != m_aux.end() && (!m_enforceRefs || it->second.second)) + return it->second.first; + return bytes(); +} + +void MemoryDB::removeAux(h256 const& _h) +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + m_aux[_h].second = false; +} + +void MemoryDB::insertAux(h256 const& _h, bytesConstRef _v) +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + m_aux[_h] = make_pair(_v.toBytes(), true); +} + void MemoryDB::purge() { +#if DEV_GUARDED_DB WriteGuard l(x_this); +#endif for (auto it = m_main.begin(); it != m_main.end(); ) if (it->second.second) ++it; @@ -129,7 +170,9 @@ void MemoryDB::purge() h256Hash MemoryDB::keys() const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif h256Hash ret; for (auto const& i: m_main) if (i.second.second) diff --git a/libdevcore/MemoryDB.h b/libdevcore/MemoryDB.h index 169682815..a39c0efd0 100644 --- a/libdevcore/MemoryDB.h +++ b/libdevcore/MemoryDB.h @@ -57,14 +57,16 @@ public: bool kill(h256 const& _h); void purge(); - bytes lookupAux(h256 const& _h) const { ReadGuard l(x_this); auto it = m_aux.find(_h); if (it != m_aux.end() && (!m_enforceRefs || it->second.second)) return it->second.first; return bytes(); } - void removeAux(h256 const& _h) { WriteGuard l(x_this); m_aux[_h].second = false; } - void insertAux(h256 const& _h, bytesConstRef _v) { WriteGuard l(x_this); m_aux[_h] = make_pair(_v.toBytes(), true); } + bytes lookupAux(h256 const& _h) const; + void removeAux(h256 const& _h); + void insertAux(h256 const& _h, bytesConstRef _v); h256Hash keys() const; protected: +#if DEV_GUARDED_DB mutable SharedMutex x_this; +#endif std::unordered_map> m_main; std::unordered_map> m_aux; diff --git a/libdevcore/RangeMask.h b/libdevcore/RangeMask.h index bdf00e687..7c402fc98 100644 --- a/libdevcore/RangeMask.h +++ b/libdevcore/RangeMask.h @@ -219,6 +219,14 @@ public: 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: UnsignedRange m_all; std::map m_ranges; diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 814f8309e..4ebd6a04b 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -37,7 +37,7 @@ using namespace dev::crypto; static Secp256k1 s_secp256k1; -bool dev::SignatureStruct::isValid() const +bool dev::SignatureStruct::isValid() const noexcept { if (v > 1 || r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || @@ -54,7 +54,7 @@ Public dev::toPublic(Secret const& _secret) { Public p; s_secp256k1.toPublic(_secret, p); - return std::move(p); + return p; } Address dev::toAddress(Public const& _public) @@ -230,7 +230,7 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash) if (!s || !_hash || !_priv) BOOST_THROW_EXCEPTION(InvalidState()); - return std::move(s); + return s; } h256 Nonce::get(bool _commit) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 10bcdd067..7bb51e563 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -51,7 +51,7 @@ struct SignatureStruct operator Signature() const { return *(h520 const*)this; } /// @returns true if r,s,v values are valid, otherwise false - bool isValid() const; + bool isValid() const noexcept; h256 r; h256 s; diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index b701fed8d..40eae10f1 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -61,7 +61,7 @@ bytes Secp256k1::eciesKDF(Secret _z, bytes _s1, unsigned kdByteLen) } k.resize(kdByteLen); - return move(k); + return k; } void Secp256k1::encryptECIES(Public const& _k, bytes& io_cipher) @@ -264,7 +264,6 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Element x; { - Guard l(x_curve); m_curve.DecodePoint(x, encodedpoint, 33); if (!m_curve.VerifyPoint(x)) return recovered; @@ -286,7 +285,6 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Point p; byte recoveredbytes[65]; { - Guard l(x_curve); // todo: make generator member p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator()); m_curve.EncodePoint(recoveredbytes, p, false); diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index ca8a2e6b5..377da8754 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -59,7 +59,7 @@ namespace crypto 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)); } diff --git a/libdevcrypto/OverlayDB.cpp b/libdevcrypto/OverlayDB.cpp index 80c901635..a6aa684f2 100644 --- a/libdevcrypto/OverlayDB.cpp +++ b/libdevcrypto/OverlayDB.cpp @@ -50,7 +50,9 @@ void OverlayDB::commit() { ldb::WriteBatch batch; // cnote << "Committing nodes to disk DB:"; +#if DEV_GUARDED_DB DEV_READ_GUARDED(x_this) +#endif { for (auto const& i: m_main) { @@ -83,7 +85,9 @@ void OverlayDB::commit() cwarn << "Sleeping for" << (i + 1) << "seconds, then retrying."; this_thread::sleep_for(chrono::seconds(i + 1)); } +#if DEV_GUARDED_DB DEV_WRITE_GUARDED(x_this) +#endif { m_aux.clear(); m_main.clear(); @@ -95,7 +99,7 @@ bytes OverlayDB::lookupAux(h256 const& _h) const { bytes ret = MemoryDB::lookupAux(_h); if (!ret.empty() || !m_db) - return move(ret); + return ret; std::string v; bytes b = _h.asBytes(); b.push_back(255); // for aux @@ -107,7 +111,9 @@ bytes OverlayDB::lookupAux(h256 const& _h) const void OverlayDB::rollback() { +#if DEV_GUARDED_DB WriteGuard l(x_this); +#endif m_main.clear(); } @@ -116,7 +122,7 @@ std::string OverlayDB::lookup(h256 const& _h) const std::string ret = MemoryDB::lookup(_h); if (ret.empty() && m_db) 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 diff --git a/libdevcrypto/SecretStore.cpp b/libdevcrypto/SecretStore.cpp index 11ff98bf6..b9d4ccfc6 100644 --- a/libdevcrypto/SecretStore.cpp +++ b/libdevcrypto/SecretStore.cpp @@ -164,7 +164,7 @@ void SecretStore::load(std::string const& _keysPath) h128 SecretStore::readKey(std::string const& _file, bool _deleteFile) { - cdebug << "Reading" << _file; + cnote << "Reading" << _file; return readKeyContent(contentsString(_file), _deleteFile ? _file : string()); } diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index f501d9642..2bdcfcd9a 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -127,7 +127,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) return devices.size(); } -bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId) +bool ethash_cl_miner::haveSufficientGPUMemory() { std::vector platforms; cl::Platform::get(&platforms); @@ -136,15 +136,25 @@ bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId) ETHCL_LOG("No OpenCL platforms found."); 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 platforms; + cl::Platform::get(&platforms); + if (_platformId >= platforms.size()) + return false; std::vector devices; unsigned platform_num = std::min(_platformId, platforms.size() - 1); platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) - { - ETHCL_LOG("No OpenCL devices found."); return false; - } for (cl::Device const& device: devices) { @@ -168,6 +178,39 @@ bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId) return false; } +void ethash_cl_miner::listDevices() +{ + std::vector 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 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 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() + "\n"; + ++i; + } + ETHCL_LOG(outString); +} + void ethash_cl_miner::finish() { if (m_queue()) diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index cdc4cf07f..4d5317186 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -35,7 +35,10 @@ public: static unsigned get_num_platforms(); static unsigned get_num_devices(unsigned _platformId = 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( uint8_t const* _dag, diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 0e125b607..69da52b09 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -139,7 +139,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const mixHash = _header[field = 13].toHash(RLP::VeryStrict); nonce = _header[field = 14].toHash(RLP::VeryStrict); } - catch (Exception const& _e) { _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. 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)) - 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) { @@ -224,7 +240,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const for (auto const& t: txs) 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())); if (sha3Uncles != sha3(root[2].data())) diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 63f4a19f9..618703e22 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -112,25 +112,26 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - cwarn << EthRedBold << "========================================================================"; - cwarn << EthRedBold << "== Software Failure " + _err + string(max(0, 44 - _err.size()), ' ') + " =="; + string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; + string const c_space = c_border + string(76, ' ') + c_border; + stringstream ss; + ss << c_line << endl; + ss << c_space << endl; + ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; + ss << c_space << endl; string bin = toString(_bi.number); - cwarn << EthRedBold << ("== Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " =="); - cwarn << EthRedBold << "========================================================================"; + ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; + ss << c_space << endl; + ss << c_line; + cwarn << "\n" + ss.str(); } void badBlock(bytesConstRef _block, string const& _err) { - badBlockInfo(BlockInfo(_block, CheckNothing), _err); - cwarn << " Block:" << toHex(_block); - cwarn << " Block RLP:" << RLP(_block); -} - -void badBlockHeader(bytesConstRef _header, string const& _err) -{ - badBlockInfo(BlockInfo::fromHeader(_header, CheckNothing), _err); - cwarn << " Header:" << toHex(_header); - cwarn << " Header RLP:" << RLP(_header);; + BlockInfo bi; + DEV_IGNORE_EXCEPTIONS(bi = BlockInfo(_block, CheckNothing)); + badBlockInfo(bi, _err); } } diff --git a/libethcore/Common.h b/libethcore/Common.h index 87ebffab7..131feed4b 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -156,8 +156,6 @@ struct TransactionSkeleton u256 gasPrice = UndefinedU256; }; -void badBlockHeader(bytesConstRef _header, std::string const& _err); -inline void badBlockHeader(bytes const& _header, std::string const& _err) { badBlockHeader(&_header, _err); } void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 0ea09a5bc..f4a8c25c4 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -340,6 +340,7 @@ void Ethash::GPUMiner::workLoop() if (shouldStop()) { delete m_miner; + m_miner = nullptr; return; } cnote << "Awaiting DAG"; @@ -354,6 +355,8 @@ void Ethash::GPUMiner::workLoop() } catch (cl::Error const& _e) { + delete m_miner; + m_miner = nullptr; cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")"; } } @@ -364,11 +367,6 @@ void Ethash::GPUMiner::pause() stopWorking(); } -bool Ethash::GPUMiner::haveSufficientGPUMemory() -{ - return ethash_cl_miner::haveSufficientGPUMemory(s_platformId); -} - std::string Ethash::GPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); @@ -379,6 +377,16 @@ unsigned Ethash::GPUMiner::getNumDevices() 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 } diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 68c21c609..99df1dc71 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -87,10 +87,11 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); - static bool haveSufficientGPUMemory() { return false; } static void setDefaultPlatform(unsigned) {} static void setDagChunks(unsigned) {} static void setDefaultDevice(unsigned) {} + static void listDevices() {} + static bool haveSufficientMemory() { return false; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: void kickOff() override @@ -117,8 +118,9 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } static std::string platformInfo(); - static bool haveSufficientGPUMemory(); static unsigned getNumDevices(); + static void listDevices(); + static bool haveSufficientMemory(); static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 9362e4fed..b411ea416 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -35,46 +35,45 @@ using errinfo_field = boost::error_info; using errinfo_data = boost::error_info; using errinfo_nonce = boost::error_info; using errinfo_difficulty = boost::error_info; +using errinfo_target = boost::error_info; +using errinfo_seedHash = boost::error_info; +using errinfo_mixHash = boost::error_info; +using errinfo_ethashResult = boost::error_info>; using BadFieldError = boost::tuple; -struct DatabaseAlreadyOpen: virtual dev::Exception {}; -struct OutOfGasBase: virtual dev::Exception {}; -struct NotEnoughAvailableSpace: virtual dev::Exception {}; -struct NotEnoughCash: virtual dev::Exception {}; -struct GasPriceTooLow: virtual dev::Exception {}; -struct BlockGasLimitReached: virtual dev::Exception {}; -struct NoSuchContract: virtual dev::Exception {}; -struct ContractAddressCollision: virtual dev::Exception {}; -struct FeeTooSmall: virtual dev::Exception {}; -struct TooMuchGasUsed: virtual dev::Exception {}; -struct ExtraDataTooBig: virtual dev::Exception {}; -struct InvalidSignature: virtual dev::Exception {}; -struct InvalidBlockFormat: virtual dev::Exception {}; -struct InvalidUnclesHash: virtual dev::Exception {}; -struct InvalidUncle: virtual dev::Exception {}; -struct TooManyUncles: virtual dev::Exception {}; -struct UncleTooOld: virtual dev::Exception {}; -struct UncleIsBrother: virtual dev::Exception {}; -struct UncleInChain: virtual dev::Exception {}; -struct DuplicateUncleNonce: virtual dev::Exception {}; -struct InvalidStateRoot: virtual dev::Exception {}; -struct InvalidGasUsed: virtual dev::Exception {}; -struct InvalidTransactionsHash: virtual dev::Exception {}; -struct InvalidTransaction: virtual dev::Exception {}; -struct InvalidDifficulty: virtual dev::Exception {}; -struct InvalidGasLimit: virtual dev::Exception {}; -struct InvalidTransactionGasUsed: virtual dev::Exception {}; -struct InvalidTransactionsStateRoot: virtual dev::Exception {}; -struct InvalidReceiptsStateRoot: virtual dev::Exception {}; -struct InvalidTimestamp: virtual dev::Exception {}; -struct InvalidLogBloom: virtual dev::Exception {}; -struct InvalidNonce: virtual dev::Exception {}; -struct InvalidBlockHeaderItemCount: virtual dev::Exception {}; -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 {}; +DEV_SIMPLE_EXCEPTION(OutOfGasBase); +DEV_SIMPLE_EXCEPTION(OutOfGasIntrinsic); +DEV_SIMPLE_EXCEPTION(NotEnoughAvailableSpace); +DEV_SIMPLE_EXCEPTION(NotEnoughCash); +DEV_SIMPLE_EXCEPTION(GasPriceTooLow); +DEV_SIMPLE_EXCEPTION(BlockGasLimitReached); +DEV_SIMPLE_EXCEPTION(FeeTooSmall); +DEV_SIMPLE_EXCEPTION(TooMuchGasUsed); +DEV_SIMPLE_EXCEPTION(ExtraDataTooBig); +DEV_SIMPLE_EXCEPTION(InvalidSignature); +DEV_SIMPLE_EXCEPTION(InvalidBlockFormat); +DEV_SIMPLE_EXCEPTION(InvalidUnclesHash); +DEV_SIMPLE_EXCEPTION(TooManyUncles); +DEV_SIMPLE_EXCEPTION(UncleTooOld); +DEV_SIMPLE_EXCEPTION(UncleIsBrother); +DEV_SIMPLE_EXCEPTION(UncleInChain); +DEV_SIMPLE_EXCEPTION(InvalidStateRoot); +DEV_SIMPLE_EXCEPTION(InvalidGasUsed); +DEV_SIMPLE_EXCEPTION(InvalidTransactionsRoot); +DEV_SIMPLE_EXCEPTION(InvalidDifficulty); +DEV_SIMPLE_EXCEPTION(InvalidGasLimit); +DEV_SIMPLE_EXCEPTION(InvalidReceiptsStateRoot); +DEV_SIMPLE_EXCEPTION(InvalidTimestamp); +DEV_SIMPLE_EXCEPTION(InvalidLogBloom); +DEV_SIMPLE_EXCEPTION(InvalidNonce); +DEV_SIMPLE_EXCEPTION(InvalidBlockHeaderItemCount); +DEV_SIMPLE_EXCEPTION(InvalidBlockNonce); +DEV_SIMPLE_EXCEPTION(InvalidParentHash); +DEV_SIMPLE_EXCEPTION(InvalidNumber); + +DEV_SIMPLE_EXCEPTION(DatabaseAlreadyOpen); +DEV_SIMPLE_EXCEPTION(DAGCreationFailure); +DEV_SIMPLE_EXCEPTION(DAGComputeFailure); + } } diff --git a/libethcore/KeyManager.cpp b/libethcore/KeyManager.cpp index 182201301..4430a588e 100644 --- a/libethcore/KeyManager.cpp +++ b/libethcore/KeyManager.cpp @@ -89,18 +89,18 @@ bool KeyManager::load(std::string const& _pass) for (auto const& i: s[1]) { m_keyInfo[m_addrLookup[(Address)i[0]] = (h128)i[1]] = KeyInfo((h256)i[2], (std::string)i[3]); - cdebug << toString((Address)i[0]) << toString((h128)i[1]) << toString((h256)i[2]) << (std::string)i[3]; +// cdebug << toString((Address)i[0]) << toString((h128)i[1]) << toString((h256)i[2]) << (std::string)i[3]; } for (auto const& i: s[2]) m_passwordInfo[(h256)i[0]] = (std::string)i[1]; m_password = (string)s[3]; } - cdebug << hashPassword(m_password) << toHex(m_password); +// cdebug << hashPassword(m_password) << toHex(m_password); m_cachedPasswords[hashPassword(m_password)] = m_password; - cdebug << hashPassword(asString(m_key.ref())) << m_key.hex(); +// cdebug << hashPassword(asString(m_key.ref())) << m_key.hex(); m_cachedPasswords[hashPassword(asString(m_key.ref()))] = asString(m_key.ref()); - cdebug << hashPassword(_pass) << _pass; +// cdebug << hashPassword(_pass) << _pass; m_cachedPasswords[m_master = hashPassword(_pass)] = _pass; return true; } @@ -141,7 +141,7 @@ std::string KeyManager::getPassword(h256 const& _passHash, function const& _pass = DontKnowThrow) const; Secret secret(h128 const& _uuid, std::function const& _pass = DontKnowThrow) const; diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 67e42d7c8..1d53e73f9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -42,13 +43,14 @@ #include "GenesisInfo.h" #include "State.h" #include "Defaults.h" + using namespace std; using namespace dev; using namespace dev::eth; namespace js = json_spirit; #define ETH_CATCH 1 -#define ETH_TIMED_IMPORTS 0 +#define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 const char* BlockChainDebug::name() { return EthBlue "8" EthWhite " <>"; } @@ -307,7 +309,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st { // _bq.tick(*this); - vector> blocks; + VerifiedBlocks blocks; _bq.drain(blocks, _max); h256s fresh; @@ -320,7 +322,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; DEV_TIMED_ABOVE(Block import, 500) - r = import(block.first, block.second, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); fresh += r.first; dead += r.second; } @@ -329,14 +331,23 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st cwarn << "ODD: Import queue contains block with unknown parent." << LogTag::Error << boost::current_exception_diagnostic_information(); // NOTE: don't reimport since the queue should guarantee everything in the right order. // Can't continue - chain bad. - badBlocks.push_back(block.first.hash()); + badBlocks.push_back(block.verified.info.hash()); + } + catch (dev::eth::FutureTime) + { + 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.verified.info.hash()); } - catch (Exception const& _e) + catch (Exception& ex) { - cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << LogTag::Error << diagnostic_information(_e); + 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. // Can't continue - chain bad. - badBlocks.push_back(block.first.hash()); + badBlocks.push_back(block.verified.info.hash()); } } return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); @@ -346,7 +357,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(_block, _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -360,8 +371,10 @@ pair BlockChain::attemptImport(bytes const& _block, O { 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())); } } @@ -369,28 +382,28 @@ pair BlockChain::attemptImport(bytes const& _block, O ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir) { // VERIFY: populates from the block and checks the block is internally coherent. - BlockInfo bi; + VerifiedBlockRef block; #if ETH_CATCH try #endif { - bi.populate(&_block); - bi.verifyInternals(&_block); + block = verifyBlock(_block, m_onBad); } #if ETH_CATCH - catch (Exception const& _e) + catch (Exception& ex) { - clog(BlockChainNote) << " Malformed block: " << diagnostic_information(_e); - _e << errinfo_comment("Malformed block "); + clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block); throw; } #endif - return import(bi, _block, _db, _ir); + return import(block, _db, _ir); } -ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir) +ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -405,28 +418,28 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla #endif // Check block doesn't already exist first! - if (isKnown(_bi.hash()) && (_ir & ImportRequirements::DontHave)) + if (isKnown(_block.info.hash()) && (_ir & ImportRequirements::DontHave)) { - clog(BlockChainNote) << _bi.hash() << ": Not new."; + clog(BlockChainNote) << _block.info.hash() << ": Not new."; BOOST_THROW_EXCEPTION(AlreadyHaveBlock()); } // Work out its number as the parent's number + 1 - if (!isKnown(_bi.parentHash)) + if (!isKnown(_block.info.parentHash)) { - clog(BlockChainNote) << _bi.hash() << ": Unknown parent " << _bi.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_bi.parentHash); + auto pd = details(_block.info.parentHash); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_bi.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_bi.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _bi.number; + auto parentBlock = block(_block.info.parentHash); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -434,14 +447,14 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla } // Check it's not crazy - if (_bi.timestamp > (u256)time(0)) + if (_block.info.timestamp > (u256)time(0)) { - clog(BlockChainChat) << _bi.hash() << ": Future time " << _bi.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } - clog(BlockChainChat) << "Attempting import of " << _bi.hash() << "..."; + clog(BlockChainChat) << "Attempting import of " << _block.info.hash() << "..."; #if ETH_TIMED_IMPORTS preliminaryChecks = t.elapsed(); @@ -461,7 +474,7 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(&_block, _bi, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this, _ir); BlockLogBlooms blb; BlockReceipts br; @@ -470,14 +483,8 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla blb.blooms.push_back(s.receipt(i).bloom()); br.receipts.push_back(s.receipt(i)); } - try { - s.cleanup(true); - } - catch (BadRoot) - { - cwarn << "BadRoot error. Retrying import later."; - BOOST_THROW_EXCEPTION(FutureTime()); - } + + s.cleanup(true); td = pd.totalDifficulty + tdIncrease; @@ -497,22 +504,22 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_bi.parentHash); + details(_block.info.parentHash); DEV_WRITE_GUARDED(x_details) - m_details[_bi.parentHash].children.push_back(_bi.hash()); + m_details[_block.info.parentHash].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); t.restart(); #endif - blocksBatch.Put(toSlice(_bi.hash()), (ldb::Slice)ref(_block)); + blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_bi.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); - extrasBatch.Put(toSlice(_bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _bi.parentHash, {}).rlp())); - extrasBatch.Put(toSlice(_bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); - extrasBatch.Put(toSlice(_bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); #if ETH_TIMED_IMPORTS || !ETH_TRUE writing = t.elapsed(); @@ -520,30 +527,25 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla #endif } #if ETH_CATCH - catch (InvalidNonce const& _e) + catch (BadRoot& ex) { - clog(BlockChainNote) << " Malformed block: " << diagnostic_information(_e); - _e << errinfo_comment("Malformed block "); - throw; + cwarn << "BadRoot error. Retrying import later."; + BOOST_THROW_EXCEPTION(FutureTime()); } - catch (Exception const& _e) + catch (Exception& ex) { - clog(BlockChainWarn) << " Malformed block: " << diagnostic_information(_e); - _e << errinfo_comment("Malformed block "); - clog(BlockChainWarn) << "Block: " << _bi.hash(); - clog(BlockChainWarn) << _bi; - clog(BlockChainWarn) << "Block parent: " << _bi.parentHash; - clog(BlockChainWarn) << BlockInfo(block(_bi.parentHash)); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block.block.toBytes()); throw; } #endif StructuredLogger::chainReceivedNewBlock( - _bi.headerHash(WithoutNonce).abridged(), - _bi.nonce.abridged(), + _block.info.headerHash(WithoutNonce).abridged(), + _block.info.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _bi.parentHash.abridged() + _block.info.parentHash.abridged() ); // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; @@ -556,8 +558,8 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _bi.parentHash); - route.push_back(_bi.hash()); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be if (common != last) @@ -569,8 +571,8 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i) { BlockInfo tbi; - if (*i == _bi.hash()) - tbi = _bi; + if (*i == _block.info.hash()) + tbi = _block.info; else tbi = BlockInfo(block(*i)); @@ -597,7 +599,7 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla h256s newTransactionAddresses; { bytes blockBytes; - RLP blockRLP(*i == _bi.hash() ? _block : (blockBytes = block(*i))); + RLP blockRLP(*i == _block.info.hash() ? _block.block : &(blockBytes = block(*i))); TransactionAddress ta; ta.blockHash = tbi.hash(); for (ta.index = 0; ta.index < blockRLP[1].itemCount(); ++ta.index) @@ -613,17 +615,17 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // FINALLY! change our best hash. { - newLastBlockHash = _bi.hash(); - newLastBlockNumber = (unsigned)_bi.number; + newLastBlockHash = _block.info.hash(); + newLastBlockNumber = (unsigned)_block.info.number; } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _bi.number << "). Has" << (details(_bi.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _bi.headerHash(WithoutNonce).abridged(), - _bi.nonce.abridged(), + _block.info.headerHash(WithoutNonce).abridged(), + _block.info.nonce.abridged(), currentHash().abridged(), - _bi.parentHash.abridged() + _block.info.parentHash.abridged() ); } else @@ -634,24 +636,26 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla m_blocksDB->Write(m_writeOptions, &blocksBatch); m_extrasDB->Write(m_writeOptions, &extrasBatch); - if (isKnown(_bi.hash()) && !details(_bi.hash())) +#if ETH_PARANOIA || !ETH_TRUE + if (isKnown(_block.info.hash()) && !details(_block.info.hash())) { clog(BlockChainDebug) << "Known block just inserted has no details."; - clog(BlockChainDebug) << "Block:" << _bi; + clog(BlockChainDebug) << "Block:" << _block.info; clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); } try { - State canary(_db, *this, _bi.hash(), ImportRequirements::DontHave); + State canary(_db, *this, _block.info.hash(), ImportRequirements::DontHave); } catch (...) { clog(BlockChainDebug) << "Failed to initialise State object form imported block."; - clog(BlockChainDebug) << "Block:" << _bi; + clog(BlockChainDebug) << "Block:" << _block.info; clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); } +#endif if (m_lastBlockHash != newLastBlockHash) DEV_WRITE_GUARDED(x_lastBlockHash) @@ -667,12 +671,16 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla #if ETH_TIMED_IMPORTS checkBest = t.elapsed(); - cnote << "Import took:" << total.elapsed(); - cnote << "preliminaryChecks:" << preliminaryChecks; - cnote << "enactment:" << enactment; - cnote << "collation:" << collation; - cnote << "writing:" << writing; - cnote << "checkBest:" << checkBest; + if (total.elapsed() > 1.0) + { + cnote << "SLOW IMPORT:" << _block.info.hash(); + cnote << " Import took:" << total.elapsed(); + cnote << " preliminaryChecks:" << preliminaryChecks; + cnote << " enactment:" << enactment; + cnote << " collation:" << collation; + cnote << " writing:" << writing; + cnote << " checkBest:" << checkBest; + } #endif if (!route.empty()) @@ -1054,3 +1062,63 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } + +VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +{ + VerifiedBlockRef res; + try + { + Strictness strictNess = Strictness::CheckEverything; + if (_ir & ~ImportRequirements::ValidNonce) + strictNess = Strictness::IgnoreNonce; + + res.info.populate(_block, strictNess); + res.info.verifyInternals(&_block); + } + catch (Exception& ex) + { + ex << errinfo_now(time(0)); + ex << errinfo_block(_block); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + for (auto const& uncle: r[2]) + { + try + { + BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); + } + catch (Exception& ex) + { + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + for (auto const& tr: r[1]) + { + try + { + res.transactions.push_back(Transaction(tr.data(), CheckTransaction::Everything)); + } + catch (Exception& ex) + { + ex << errinfo_transactionIndex(i); + ex << errinfo_block(_block); + throw; + } + ++i; + } + res.block = bytesConstRef(&_block); + return move(res); +} + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index a67ec9a9c..1aa15b856 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -40,6 +40,7 @@ #include "Account.h" #include "Transaction.h" #include "BlockQueue.h" +#include "VerifiedBlock.h" namespace ldb = leveldb; namespace std @@ -120,7 +121,7 @@ public: /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(BlockInfo const& _bi, bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -256,6 +257,12 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); + /// Verify block and prepare it for enactment + static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); + + /// Change the function that is called with a bad block. + template void setOnBad(T const& _t) { m_onBad = _t; } + private: static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); } @@ -335,6 +342,8 @@ private: ldb::ReadOptions m_readOptions; ldb::WriteOptions m_writeOptions; + std::function m_onBad; ///< Called if we have a block that doesn't verify. + friend std::ostream& operator<<(std::ostream& _out, BlockChain const& _bc); }; diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 360bf915e..f055f911a 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -22,10 +22,11 @@ #include "BlockQueue.h" #include #include -#include #include #include #include "BlockChain.h" +#include "VerifiedBlock.h" +#include "State.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -71,62 +72,14 @@ void BlockQueue::verifierBody() m_unverified.pop_front(); BlockInfo bi; bi.mixHash = work.first; - m_verifying.push_back(make_pair(bi, bytes())); + m_verifying.push_back(VerifiedBlock { VerifiedBlockRef { bytesConstRef(), move(bi), Transactions() }, bytes() }); } - std::pair res; - swap(work.second, res.second); - try { - try { - res.first.populate(res.second, CheckEverything, work.first); - res.first.verifyInternals(&res.second); - } - catch (InvalidBlockNonce&) - { - 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()); - throw; - } - - RLP r(&res.second); - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (InvalidNonce&) - { - 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()); - throw; - } - } + VerifiedBlock res; + swap(work.second, res.blockData); + try + { + res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); } catch (...) { @@ -141,7 +94,7 @@ void BlockQueue::verifierBody() unique_lock l(m_verification); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->first.mixHash == work.first) + if (it->verified.info.mixHash == work.first) { m_verifying.erase(it); goto OK1; @@ -154,12 +107,12 @@ void BlockQueue::verifierBody() bool ready = false; { unique_lock l(m_verification); - if (m_verifying.front().first.mixHash == work.first) + if (m_verifying.front().verified.info.mixHash == work.first) { // we're next! m_verifying.pop_front(); m_verified.push_back(move(res)); - while (m_verifying.size() && !m_verifying.front().second.empty()) + while (m_verifying.size() && !m_verifying.front().blockData.empty()) { m_verified.push_back(move(m_verifying.front())); m_verifying.pop_front(); @@ -169,7 +122,7 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.first.mixHash == work.first) + if (i.verified.info.mixHash == work.first) { i = move(res); goto OK; @@ -277,15 +230,15 @@ bool BlockQueue::doneDrain(h256s const& _bad) m_drainingSet.clear(); if (_bad.size()) { - vector> old; + vector old; DEV_GUARDED(m_verification) swap(m_verified, old); for (auto& b: old) { - if (m_knownBad.count(b.first.parentHash)) + if (m_knownBad.count(b.verified.info.parentHash)) { - m_knownBad.insert(b.first.hash()); - m_readySet.erase(b.first.hash()); + m_knownBad.insert(b.verified.info.hash()); + m_readySet.erase(b.verified.info.hash()); } else DEV_GUARDED(m_verification) @@ -348,7 +301,7 @@ QueueStatus BlockQueue::blockStatus(h256 const& _h) const QueueStatus::Unknown; } -void BlockQueue::drain(std::vector>& o_out, unsigned _max) +void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) { WriteGuard l(m_lock); DEV_INVARIANT_CHECK; @@ -364,7 +317,7 @@ void BlockQueue::drain(std::vector>& o_out, unsigned for (auto const& bs: o_out) { // TODO: @optimise use map rather than vector & set. - auto h = bs.first.hash(); + auto h = bs.verified.info.hash(); m_drainingSet.insert(h); m_readySet.erase(h); } @@ -421,6 +374,7 @@ void BlockQueue::retryAllUnknown() std::ostream& dev::eth::operator<<(std::ostream& _out, BlockQueueStatus const& _bqs) { + _out << "importing: " << _bqs.importing << endl; _out << "verified: " << _bqs.verified << endl; _out << "verifying: " << _bqs.verifying << endl; _out << "unverified: " << _bqs.unverified << endl; diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index 45043559b..0e3e640b1 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -31,6 +31,7 @@ #include #include #include +#include "VerifiedBlock.h" namespace dev { @@ -45,6 +46,7 @@ struct BlockQueueChannel: public LogChannel { static const char* name(); static struct BlockQueueStatus { + size_t importing; size_t verified; size_t verifying; size_t unverified; @@ -81,7 +83,7 @@ public: /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. - void drain(std::vector>& o_out, unsigned _max); + void drain(std::vector& o_out, unsigned _max); /// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them. /// @returns true iff there are additional blocks ready to be processed. @@ -103,13 +105,15 @@ public: h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); } /// Get some infomration on the current status. - BlockQueueStatus status() const { ReadGuard l(m_lock); Guard l2(m_verification); return BlockQueueStatus{m_verified.size(), m_verifying.size(), m_unverified.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } + BlockQueueStatus status() const { ReadGuard l(m_lock); Guard l2(m_verification); return BlockQueueStatus{m_drainingSet.size(), m_verified.size(), m_verifying.size(), m_unverified.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } /// Get some infomration on the given block's status regarding us. QueueStatus blockStatus(h256 const& _h) const; template Handler onReady(T const& _t) { return m_onReady.add(_t); } + template void setOnBad(T const& _t) { m_onBad = _t; } + private: void noteReady_WITH_LOCK(h256 const& _b); @@ -128,12 +132,14 @@ private: mutable Mutex m_verification; ///< Mutex that allows writing to m_verified, m_verifying and m_unverified. std::condition_variable m_moreToVerify; ///< Signaled when m_unverified has a new entry. - std::vector> m_verified; ///< List of blocks, in correct order, verified and ready for chain-import. - std::deque> m_verifying; ///< List of blocks being verified; as long as the second component (bytes) is empty, it's not finished. + std::vector m_verified; ///< List of blocks, in correct order, verified and ready for chain-import. + std::deque m_verifying; ///< List of blocks being verified; as long as the second component (bytes) is empty, it's not finished. std::deque> m_unverified; ///< List of blocks, in correct order, ready for verification. std::vector m_verifiers; ///< Threads who only verify. bool m_deleting = false; ///< Exit condition for verifiers. + + std::function m_onBad; ///< Called if we have a block that doesn't verify. }; std::ostream& operator<<(std::ostream& _out, BlockQueueStatus const& _s); diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 8203402cb..6598e1bd7 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -14,6 +14,10 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) include_directories(${LEVELDB_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) @@ -30,6 +34,13 @@ target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} secp256k1) +if (JSONRPC) + target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES}) + target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) + if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) + endif() +endif() if (CMAKE_COMPILER_IS_MINGW) target_link_libraries(${EXECUTABLE} ssp shlwapi) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 46fbbdfb1..029a0041c 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -25,9 +25,16 @@ #include #include #include +#if ETH_JSONRPC || !ETH_TRUE +#include +#include +#endif #include #include #include +#if ETH_JSONRPC || !ETH_TRUE +#include "Sentinel.h" +#endif #include "Defaults.h" #include "Executive.h" #include "EthereumHost.h" @@ -80,6 +87,113 @@ void VersionChecker::setOk() } } +void Client::onBadBlock(Exception& _ex) +{ + // BAD BLOCK!!! + bytes const* block = boost::get_error_info(_ex); + if (!block) + { + cwarn << "ODD: onBadBlock called but exception has no block in it."; + return; + } + + badBlock(*block, _ex.what()); + +#if ETH_JSONRPC || !ETH_TRUE + 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); + + // add the various hints. + if (unsigned const* uncleIndex = boost::get_error_info(_ex)) + { + // uncle that failed. + report["hints"]["uncleIndex"] = *uncleIndex; + } + else if (unsigned const* txIndex = boost::get_error_info(_ex)) + { + // transaction that failed. + report["hints"]["transactionIndex"] = *txIndex; + } + else + { + // general block failure. + } + + if (string const* vmtraceJson = boost::get_error_info(_ex)) + Json::Reader().parse(*vmtraceJson, report["hints"]["vmtrace"]); + if (vector const* receipts = boost::get_error_info(_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(_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(_ex)) \ + report["hints"][#X] = toString(*n) +#define DEV_HINT_ERRINFO_HASH(X) \ + if (auto const* n = boost::get_error_info(_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(name); + DEV_HINT_ERRINFO(field); + DEV_HINT_ERRINFO(data); + DEV_HINT_ERRINFO_HASH(nonce); + DEV_HINT_ERRINFO(difficulty); + DEV_HINT_ERRINFO(target); + DEV_HINT_ERRINFO_HASH(seedHash); + DEV_HINT_ERRINFO_HASH(mixHash); + if (tuple const* r = boost::get_error_info(_ex)) + { + report["hints"]["ethashResult"]["value"] = get<0>(*r).hex(); + report["hints"]["ethashResult"]["mixHash"] = get<1>(*r).hex(); + } + DEV_HINT_ERRINFO(required); + DEV_HINT_ERRINFO(got); + DEV_HINT_ERRINFO_HASH(required_LogBloom); + DEV_HINT_ERRINFO_HASH(got_LogBloom); + DEV_HINT_ERRINFO_HASH(required_h256); + DEV_HINT_ERRINFO_HASH(got_h256); + + cwarn << ("Report: \n" + Json::StyledWriter().write(report)); + + if (!m_sentinel.empty()) + { + jsonrpc::HttpClient client(m_sentinel); + Sentinel rpc(client); + try + { + rpc.eth_badBlock(report); + } + catch (...) + { + cwarn << "Error reporting to sentinel. Sure the address" << m_sentinel << "is correct?"; + } + } +#endif +} + void BasicGasPricer::update(BlockChain const& _bc) { unsigned c = 0; @@ -174,7 +288,7 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for } Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth"), + Worker("eth", 0), m_vc(_dbPath), m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), m_gp(_gp), @@ -185,6 +299,8 @@ Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string c 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_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_gp->update(m_bc); @@ -206,6 +322,18 @@ Client::~Client() 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) { if (auto h = m_host.lock()) @@ -429,9 +557,10 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 temp = m_postMine; temp.addBalance(_from, _value + _gasPrice * _gas); Executive e(temp, LastHashes(), 0); + e.setResultRecipient(ret); if (!e.call(_dest, _from, _value, _gasPrice, &_data, _gas)) e.go(); - ret = e.executionResult(); + e.finalize(); } catch (...) { @@ -447,6 +576,9 @@ ProofOfWork::WorkPackage Client::getWork() bool oldShould = shouldServeWork(); 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 (!oldShould && shouldServeWork()) onPostStateChanged(); @@ -604,11 +736,22 @@ bool Client::remoteActive() const 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) m_working.commitToMine(m_bc); DEV_READ_GUARDED(x_working) @@ -617,20 +760,21 @@ void Client::onPostStateChanged() m_postMine = m_working; m_miningInfo = m_postMine.info(); } - m_farm.setWork(m_miningInfo); - Ethash::ensurePrecomputed(m_bc.number()); - } - m_remoteWorking = false; -} + if (m_wouldMine) + { + m_farm.setWork(m_miningInfo); + if (m_turboMining) + m_farm.startGPU(); + else + m_farm.startCPU(); -void Client::startMining() -{ - if (m_turboMining) - m_farm.startGPU(); - else - m_farm.startCPU(); - onPostStateChanged(); + m_farm.setWork(m_miningInfo); + Ethash::ensurePrecomputed(m_bc.number()); + } + } + if (!m_wouldMine) + m_farm.stop(); } void Client::noteChanged(h256Hash const& _filters) @@ -745,3 +889,9 @@ void Client::flushTransactions() { doWork(); } + +HashChainStatus Client::hashChainStatus() const +{ + auto h = m_host.lock(); + return h ? h->status() : HashChainStatus { 0, 0, false }; +} diff --git a/libethereum/Client.h b/libethereum/Client.h index 5132b5a30..2de6e9403 100644 --- a/libethereum/Client.h +++ b/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()); /// 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] dev::eth::State state(unsigned _txi, h256 _block) const; @@ -156,10 +156,14 @@ public: CanonBlockChain const& blockChain() const { return m_bc; } /// Get some information on the block queue. 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: - 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. bool miningParanoia() const { return m_paranoia; } @@ -174,14 +178,26 @@ public: /// Enable/disable GPU mining. 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. /// NOT thread-safe - call it & stopMining only from a single thread void startMining() override; /// Stop mining. /// NOT thread-safe - void stopMining() override { m_farm.stop(); } + void stopMining() override { m_wouldMine = false; rejigMining(); } /// Are we mining now? bool isMining() const override { return m_farm.isMining(); } + /// Are we mining now? + bool wouldMine() const override { return m_wouldMine; } /// The hashrate... uint64_t hashrate() const override; /// Check the progress of the mining. @@ -213,6 +229,8 @@ public: void retryUnkonwn() { m_bq.retryAllUnknown(); } /// Get a report of activity. 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: /// InterfaceStub methods @@ -249,6 +267,9 @@ private: /// Called when Worker is exiting. 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. /// Called by either submitWork() or in our main thread through syncBlockQueue(). void onChainChanged(ImportRoute const& _ir); @@ -278,6 +299,10 @@ private: /// @returns true only if it's worth bothering to prep the mining block. 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. CanonBlockChain m_bc; ///< Maintains block database. 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_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_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? mutable std::chrono::system_clock::time_point m_lastGarbageCollection; @@ -317,6 +344,8 @@ private: Mutex x_signalled; std::atomic m_syncTransactionQueue = {false}; std::atomic m_syncBlockQueue = {false}; + + std::string m_sentinel; }; } diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 8dc666bb5..6a2c76c0b 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -400,17 +400,16 @@ h256s ClientBase::pendingHashes() const return h256s() + postMine().pendingHashes(); } - StateDiff ClientBase::diff(unsigned _txi, h256 _block) const { 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 { 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 diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 2b271b1df..b2afe3597 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -132,8 +132,8 @@ public: virtual Transactions pending() const override; virtual h256s pendingHashes() const override; - ImportResult injectTransaction(bytes const& _rlp) override { prepareForTransaction(); return m_tq.import(_rlp); } - ImportResult injectBlock(bytes const& _block); + virtual ImportResult injectTransaction(bytes const& _rlp) override { prepareForTransaction(); return m_tq.import(_rlp); } + virtual ImportResult injectBlock(bytes const& _block) override; using Interface::diff; virtual StateDiff diff(unsigned _txi, h256 _block) const override; @@ -143,9 +143,6 @@ public: virtual Addresses addresses(BlockNumber _block) const override; virtual u256 gasLimitRemaining() const override; - /// Set the coinbase address - virtual void setAddress(Address _us) = 0; - /// Get the coinbase address virtual Address address() const override; @@ -154,6 +151,7 @@ public: virtual void startMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::startMining")); } virtual void stopMining() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::stopMining")); } 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 MiningProgress miningProgress() const override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::miningProgress")); } virtual ProofOfWork::WorkPackage getWork() override { BOOST_THROW_EXCEPTION(InterfaceNotSupported("ClientBase::getWork")); } diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h index a2f4a2e7c..1515c844d 100644 --- a/libethereum/CommonNet.h +++ b/libethereum/CommonNet.h @@ -38,14 +38,16 @@ namespace eth #if ETH_DEBUG static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send. -static const unsigned c_maxHashesAsk = 2048; ///< Maximum number of hashes GetBlockHashes will ever ask for. +static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for. static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. -static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const unsigned c_maxBlocksAsk = 8; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const unsigned c_maxPayload = 262144; ///< Maximum size of packet for us to send. #else static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send. static const unsigned c_maxHashesAsk = 2048; ///< Maximum number of hashes GetBlockHashes will ever ask for. static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const unsigned c_maxPayload = 262144; ///< Maximum size of packet for us to send. #endif class BlockChain; @@ -82,5 +84,12 @@ enum class Syncing Done }; +struct HashChainStatus +{ + unsigned total; + unsigned received; + bool estimated; +}; + } } diff --git a/libethereum/DownloadMan.cpp b/libethereum/DownloadMan.cpp index 3e33f3eb5..5e68e3c49 100644 --- a/libethereum/DownloadMan.cpp +++ b/libethereum/DownloadMan.cpp @@ -80,7 +80,6 @@ HashDownloadSub::HashDownloadSub(HashDownloadMan& _man): m_man(&_man) { WriteGuard l(m_man->x_subs); m_asked = RangeMask(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount); - m_attempted = RangeMask(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount); m_man->m_subs.insert(this); } @@ -98,7 +97,6 @@ void HashDownloadSub::resetFetch() Guard l(m_fetch); m_remaining = 0; m_asked = RangeMask(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount); - m_attempted = RangeMask(m_man->m_chainStart, m_man->m_chainStart + m_man->m_chainCount); } unsigned HashDownloadSub::nextFetch(unsigned _n) @@ -110,10 +108,9 @@ unsigned HashDownloadSub::nextFetch(unsigned _n) if (!m_man || m_man->chainEmpty()) return 0; - m_asked = (~(m_man->taken() + m_attempted)).lowest(_n); + m_asked = (~(m_man->taken())).lowest(_n); if (m_asked.empty()) - m_asked = (~(m_man->taken(true) + m_attempted)).lowest(_n); - m_attempted += m_asked; + m_asked = (~(m_man->taken(true))).lowest(_n); return *m_asked.begin(); } diff --git a/libethereum/DownloadMan.h b/libethereum/DownloadMan.h index 3e1a071c9..0c27e84ea 100644 --- a/libethereum/DownloadMan.h +++ b/libethereum/DownloadMan.h @@ -187,7 +187,6 @@ public: bool askedContains(unsigned _i) const { Guard l(m_fetch); return m_asked.contains(_i); } RangeMask const& asked() const { return m_asked; } - RangeMask const& attemped() const { return m_attempted; } private: void resetFetch(); // Called by DownloadMan when we need to reset the download. @@ -196,7 +195,6 @@ private: mutable Mutex m_fetch; unsigned m_remaining; RangeMask m_asked; - RangeMask m_attempted; }; class HashDownloadMan @@ -255,6 +253,11 @@ public: return m_got.full(); } + unsigned gotCount() const + { + return m_got.size(); + } + size_t chainSize() const { ReadGuard l(m_lock); return m_chainCount; } size_t chainEmpty() const { ReadGuard l(m_lock); return m_chainCount == 0; } void foreachSub(std::function const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); } @@ -274,3 +277,4 @@ private: } } + diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 3965a214e..a5a03297f 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -237,7 +237,7 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash) void EthereumHost::onPeerStatus(EthereumPeer* _peer) { - Guard l(x_sync); + RecursiveGuard l(x_sync); if (_peer->m_genesisHash != m_chain.genesisHash()) _peer->disable("Invalid genesis hash"); else if (_peer->m_protocolVersion != protocolVersion() && _peer->m_protocolVersion != c_oldProtocolVersion) @@ -252,10 +252,13 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer) { if (_peer->m_protocolVersion != protocolVersion()) estimatePeerHashes(_peer); - else if (_peer->m_latestBlockNumber > m_chain.number()) - _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); + else + { + if (_peer->m_latestBlockNumber > m_chain.number()) + _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); } } @@ -265,7 +268,7 @@ void EthereumHost::estimatePeerHashes(EthereumPeer* _peer) BlockInfo block = m_chain.info(); time_t lastBlockTime = (block.hash() == m_chain.genesisHash()) ? 1428192000 : (time_t)block.timestamp; time_t now = time(0); - unsigned blockCount = 1000; + unsigned blockCount = 30000; if (lastBlockTime > now) clog(NetWarn) << "Clock skew? Latest block is in the future"; else @@ -276,7 +279,7 @@ void EthereumHost::estimatePeerHashes(EthereumPeer* _peer) void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) { - Guard l(x_sync); + RecursiveGuard l(x_sync); assert(_peer->m_asking == Asking::Nothing); onPeerHashes(_peer, _hashes, false); } @@ -285,13 +288,23 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool { 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; } + unsigned knowns = 0; unsigned unknowns = 0; h256s neededBlocks; - bool syncByNumber = !m_syncingLatestHash; + unsigned firstNumber = _peer->m_syncHashNumber - _hashes.size(); for (unsigned i = 0; i < _hashes.size(); ++i) { _peer->addRating(1); @@ -321,8 +334,11 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool } else knowns++; + if (!syncByNumber) m_syncingLatestHash = h; + else + _peer->m_hashSub.noteHash(firstNumber + i, 1); } if (syncByNumber) { @@ -368,13 +384,14 @@ void EthereumHost::onPeerDoneHashes(EthereumPeer* _peer, bool _localChain) { m_man.resetToChain(m_hashes); m_hashes.clear(); + m_hashMan.reset(m_chain.number() + 1); } continueSync(); } void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) { - Guard l(x_sync); + RecursiveGuard l(x_sync); assert(_peer->m_asking == Asking::Nothing); unsigned itemCount = _r.itemCount(); clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); @@ -384,6 +401,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) // Got to this peer's latest block - just give up. clog(NetNote) << "Finishing blocks fetch..."; // NOTE: need to notify of giving up on chain-hashes, too, altering state as necessary. + _peer->m_sub.doneFetch(); _peer->setIdle(); return; } @@ -450,7 +468,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) { - Guard l(x_sync); + RecursiveGuard l(x_sync); if (isSyncing_UNSAFE()) { clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; @@ -462,7 +480,7 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { - Guard l(x_sync); + RecursiveGuard l(x_sync); if (isSyncing_UNSAFE()) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; @@ -549,6 +567,18 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) } } +void EthereumHost::onPeerAborting(EthereumPeer* _peer) +{ + RecursiveGuard l(x_sync); + if (_peer->isConversing()) + { + _peer->setIdle(); + if (_peer->isCriticalSyncing()) + _peer->setRude(); + continueSync(); + } +} + void EthereumHost::continueSync() { clog(NetAllDetail) << "Getting help with downloading hashes and blocks"; @@ -562,22 +592,37 @@ void EthereumHost::continueSync() void EthereumHost::continueSync(EthereumPeer* _peer) { assert(_peer->m_asking == Asking::Nothing); - bool otherPeerSync = false; + bool otherPeerV60Sync = false; + bool otherPeerV61Sync = false; if (m_needSyncHashes && peerShouldGrabChain(_peer)) { foreachPeer([&](EthereumPeer* _p) { - if (_p != _peer && _p->m_asking == Asking::Hashes && _p->m_protocolVersion != protocolVersion()) - otherPeerSync = true; // Already have a peer downloading hash chain with old protocol, do nothing + if (_p != _peer && _p->m_asking == Asking::Hashes) + { + 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(); 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 + } else { // Restart/continue sync in single peer mode @@ -586,17 +631,33 @@ void EthereumHost::continueSync(EthereumPeer* _peer) m_syncingLatestHash =_peer->m_latestHash; 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 && peerCanHelp(_peer)) // Check if this peer can help with downloading blocks _peer->requestBlocks(); else _peer->setIdle(); } +bool EthereumHost::peerCanHelp(EthereumPeer* _peer) const +{ + (void)_peer; + return true; +} + bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const { + // this is only good for deciding whether to go ahead and grab a particular peer's hash chain, + // yet it's being used in determining whether to allow a peer help with downloading an existing + // chain of blocks. auto td = _peer->m_totalDifficulty; auto lh = m_syncingLatestHash; auto ctd = m_chain.details().totalDifficulty; @@ -609,6 +670,10 @@ bool EthereumHost::peerShouldGrabBlocks(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(); unsigned n = m_chain.number(); u256 td = m_chain.details().totalDifficulty; @@ -638,3 +703,12 @@ bool EthereumHost::isSyncing_UNSAFE() const }); return syncing; } + +HashChainStatus EthereumHost::status() +{ + RecursiveGuard l(x_sync); + if (m_syncingV61) + return HashChainStatus { static_cast(m_hashMan.chainSize()), static_cast(m_hashMan.gotCount()), false }; + return HashChainStatus { m_estimatedHashes - 30000, static_cast(m_hashes.size()), true }; +} + diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 8ca815a17..df17b1e4e 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -70,8 +70,8 @@ public: void reset(); DownloadMan const& downloadMan() const { return m_man; } - bool isSyncing() const { Guard l(x_sync); return isSyncing_UNSAFE(); } - bool isBanned(p2p::NodeId _id) const { return !!m_banned.count(_id); } + bool isSyncing() const { RecursiveGuard l(x_sync); return isSyncing_UNSAFE(); } + bool isBanned(p2p::NodeId const& _id) const { return !!m_banned.count(_id); } void noteNewTransactions() { m_newTransactions = true; } void noteNewBlocks() { m_newBlocks = true; } @@ -82,10 +82,12 @@ public: 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 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; } HashDownloadMan& hashDownloadMan() { return m_hashMan; } BlockChain const& chain() { return m_chain; } + HashChainStatus status(); static unsigned const c_oldProtocolVersion; @@ -122,6 +124,7 @@ private: void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete); bool peerShouldGrabBlocks(EthereumPeer* _peer) const; bool peerShouldGrabChain(EthereumPeer* _peer) const; + bool peerCanHelp(EthereumPeer* _peer) const; void estimatePeerHashes(EthereumPeer* _peer); BlockChain const& m_chain; @@ -141,12 +144,14 @@ private: bool m_newTransactions = 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_needSyncBlocks = true; ///< Indicates if we still need to download some blocks 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. - 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. }; } diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index d6b0b50c3..8167baeda 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "BlockChain.h" #include "EthereumHost.h" #include "TransactionQueue.h" @@ -40,6 +41,7 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap m_hashSub(host()->hashDownloadMan()), m_peerCapabilityVersion(_cap.second) { + session()->addNote("manners", isRude() ? "RUDE" : "nice"); m_syncHashNumber = host()->chain().number() + 1; requestStatus(); } @@ -50,10 +52,20 @@ EthereumPeer::~EthereumPeer() abortSync(); } +bool EthereumPeer::isRude() const +{ + return repMan().isRude(*session(), name()); +} + +void EthereumPeer::setRude() +{ + repMan().noteRude(*session(), name()); + session()->addNote("manners", "RUDE"); +} + void EthereumPeer::abortSync() { - if (isSyncing()) - setIdle(); + host()->onPeerAborting(this); } EthereumHost* EthereumPeer::host() const @@ -105,6 +117,7 @@ void EthereumPeer::requestHashes() { assert(m_asking == Asking::Nothing); m_syncHashNumber = m_hashSub.nextFetch(c_maxHashesAsk); + m_syncHash = h256(); setAsking(Asking::Hashes); RLPStream s; prep(s, GetBlockHashesByNumberPacket, 2) << m_syncHashNumber << c_maxHashesAsk; @@ -119,13 +132,15 @@ void EthereumPeer::requestHashes(h256 const& _lastHash) RLPStream s; prep(s, GetBlockHashesPacket, 2) << _lastHash << c_maxHashesAsk; clog(NetMessageDetail) << "Requesting block hashes staring from " << _lastHash; + m_syncHash = _lastHash; + m_syncHashNumber = 0; sealAndSend(s); } void EthereumPeer::requestBlocks() { setAsking(Asking::Blocks); - auto blocks = m_sub.nextFetch(c_maxBlocksAsk); + auto blocks = m_sub.nextFetch(isRude() ? 1 : c_maxBlocksAsk); if (blocks.size()) { RLPStream s; @@ -145,7 +160,7 @@ void EthereumPeer::setAsking(Asking _a) m_lastAsk = chrono::system_clock::now(); session()->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?"); - session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : "")); + session()->addNote("sync", string(isCriticalSyncing() ? "ONGOING" : "holding") + (needsSyncing() ? " & needed" : "")); } void EthereumPeer::tick() @@ -155,11 +170,16 @@ void EthereumPeer::tick() session()->disconnect(PingTimeout); } -bool EthereumPeer::isSyncing() const +bool EthereumPeer::isConversing() const { return m_asking != Asking::Nothing; } +bool EthereumPeer::isCriticalSyncing() const +{ + return m_asking == Asking::Hashes || m_asking == Asking::State || (m_asking == Asking::Blocks && m_protocolVersion == 60); +} + bool EthereumPeer::interpret(unsigned _id, RLP const& _r) { try @@ -175,8 +195,16 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) m_genesisHash = _r[4].toHash(); if (m_peerCapabilityVersion == host()->protocolVersion()) { - m_protocolVersion = host()->protocolVersion(); - m_latestBlockNumber = _r[5].toInt(); + if (_r.itemCount() != 6) + { + clog(NetImpolite) << "Peer does not support PV61+ status extension."; + m_protocolVersion = EthereumHost::c_oldProtocolVersion; + } + else + { + m_protocolVersion = host()->protocolVersion(); + m_latestBlockNumber = _r[5].toInt(); + } } clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << m_genesisHash << "/" << m_latestBlockNumber << ", TD:" << m_totalDifficulty << "=" << m_latestHash; @@ -240,12 +268,10 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) setAsking(Asking::Nothing); h256s hashes(itemCount); for (unsigned i = 0; i < itemCount; ++i) - { hashes[i] = _r[i].toHash(); - m_hashSub.noteHash(m_syncHashNumber + i, 1); - } - m_syncHashNumber += itemCount; + if (m_syncHashNumber > 0) + m_syncHashNumber += itemCount; host()->onPeerHashes(this, hashes); break; } @@ -263,7 +289,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) // return the requested blocks. bytes rlp; unsigned n = 0; - for (unsigned i = 0; i < min(count, c_maxBlocks); ++i) + for (unsigned i = 0; i < min(count, c_maxBlocks) && rlp.size() < c_maxPayload; ++i) { auto h = _r[i].toHash(); if (host()->chain().isKnown(h)) @@ -286,7 +312,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) case BlocksPacket: { if (m_asking != Asking::Blocks) - clog(NetWarn) << "Peer giving us blocks when we didn't ask for them."; + clog(NetImpolite) << "Peer giving us blocks when we didn't ask for them."; else { setAsking(Asking::Nothing); diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index 94dc60501..a12b7a197 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -82,6 +82,12 @@ public: /// Request blocks. Uses block download manager. void requestBlocks(); + /// Check if this node is rude. + bool isRude() const; + + /// Set that it's a rude node. + void setRude(); + private: using p2p::Capability::sealAndSend; @@ -101,10 +107,13 @@ private: void setAsking(Asking _g); /// Do we presently need syncing with this peer? - bool needsSyncing() const { return !!m_latestHash; } + bool needsSyncing() const { return !isRude() && !!m_latestHash; } + + /// Are we presently in the process of communicating with this peer? + bool isConversing() const; - /// Are we presently syncing with this peer? - bool isSyncing() const; + /// Are we presently in a critical part of the syncing process with this peer? + bool isCriticalSyncing() const; /// Runs period checks to check up on the peer. void tick(); @@ -128,8 +137,9 @@ private: /// 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. - 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_expectedHashes = 0; ///< Estimated upper bound of hashes to expect from this peer. + 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. DownloadSub m_sub; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index c2830729d..4e741795c 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -19,6 +19,9 @@ #include "Executive.h" #include +#if ETH_JSONRPC || !ETH_TRUE +#include +#endif #include #include #include @@ -34,6 +37,101 @@ using namespace dev::eth; const char* VMTraceChannel::name() { return "EVM"; } 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(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): m_s(_s), m_lastHashes(_bc.lastHashes((unsigned)_s.info().number - 1)), @@ -45,11 +143,6 @@ u256 Executive::gasUsed() const return m_t.gas() - m_gas; } -ExecutionResult Executive::executionResult() const -{ - return ExecutionResult(gasUsed(), m_excepted, m_newAddress, m_out, m_codeDeposit, m_ext ? m_ext->sub.refunds : 0, m_depositSize, m_gasForDeposit); -} - void Executive::accrueSubState(SubState& _parentContext) { if (m_ext) @@ -73,7 +166,7 @@ void Executive::initialize(Transaction const& _transaction) if (!m_t.checkPayment()) { 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())); } @@ -146,8 +239,7 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co else { m_gas = (u256)(_p.gas - g); - m_precompiledOut = it->second.exec(_p.data); - m_out = &m_precompiledOut; + it->second.exec(_p.data, _p.out); } } else @@ -155,9 +247,10 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co m_gas = _p.gas; if (m_s.addressHasCode(_p.codeAddress)) { - m_vm = VMFactory::create(); + m_outRef = _p.out; // Save ref to expected output buffer to be used in go() bytes const& c = m_s.code(_p.codeAddress); - m_ext = make_shared(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth); + h256 codeHash = m_s.codeHash(_p.codeAddress); + m_ext = make_shared(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, codeHash, m_depth); } } @@ -177,10 +270,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g // Execute _init. if (!_init.empty()) - { - m_vm = VMFactory::create(); - m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth); - } + m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), m_depth); m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress), Account::ContractConception); m_s.transferBalance(_sender, m_newAddress, _endowment); @@ -211,56 +301,50 @@ 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(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) { - if (m_vm) + if (m_ext) { #if ETH_TIMED_EXECUTIONS boost::timer t; #endif try { - m_out = m_vm->go(m_gas, *m_ext, _onOp); - + auto vm = VMFactory::create(); if (m_isCreation) { - m_gasForDeposit = m_gas; - m_depositSize = m_out.size(); - if (m_out.size() * c_createDataGas <= m_gas) + auto out = vm->exec(m_gas, *m_ext, _onOp); + if (m_res) + { + m_res->gasForDeposit = m_gas; + m_res->depositSize = out.size(); + } + if (out.size() * c_createDataGas <= m_gas) { - m_codeDeposit = CodeDeposit::Success; - m_gas -= m_out.size() * c_createDataGas; + if (m_res) + m_res->codeDeposit = CodeDeposit::Success; + m_gas -= out.size() * c_createDataGas; } else { - - m_codeDeposit = CodeDeposit::Failed; - m_out.reset(); + if (m_res) + m_res->codeDeposit = CodeDeposit::Failed; + out.clear(); } - m_s.m_cache[m_newAddress].setCode(m_out.toBytes()); + if (m_res) + m_res->output = out; // copy output to execution result + m_s.m_cache[m_newAddress].setCode(std::move(out)); // FIXME: Set only if Success? + } + else + { + if (m_res) + { + m_res->output = vm->exec(m_gas, *m_ext, _onOp); // take full output + bytesConstRef{&m_res->output}.copyTo(m_outRef); + } + else + vm->exec(m_gas, *m_ext, m_outRef, _onOp); // take only expected output } - } - catch (StepsDone const&) - { - return false; } catch (VMException const& _e) { @@ -314,4 +398,12 @@ void Executive::finalize() // Logs.. if (m_ext) m_logs = m_ext->sub.logs; + + if (m_res) // Collect results + { + m_res->gasUsed = gasUsed(); + m_res->excepted = m_excepted; // TODO: m_except is used only in ExtVM::call + m_res->newAddress = m_newAddress; + m_res->gasRefunded = m_ext ? m_ext->sub.refunds : 0; + } } diff --git a/libethereum/Executive.h b/libethereum/Executive.h index d5d1baf87..e2c910cd0 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -25,6 +25,11 @@ #include #include "Transaction.h" +namespace Json +{ + class Value; +} + namespace dev { namespace eth @@ -38,6 +43,19 @@ struct Manifest; 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; }; +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 m_lastInst; + std::shared_ptr m_trace; +}; + /** * @brief Message-call/contract-creation executor; useful for executing transactions. * @@ -112,30 +130,25 @@ public: /// @returns gas remaining after the transaction/operation. Valid after the transaction has been executed. u256 gas() const { return m_gas; } - /// @returns output data of the transaction/operation. - bytesConstRef out() const { return m_out; } + /// @returns the new address for the created contract in the CREATE operation. h160 newAddress() const { return m_newAddress; } /// @returns true iff the operation ended with a VM exception. bool excepted() const { return m_excepted != TransactionException::None; } - /// Get the above in an amalgamated fashion. - ExecutionResult executionResult() const; + /// Collect execution results in the result storage provided. + void setResultRecipient(ExecutionResult& _res) { m_res = &_res; } private: State& m_s; ///< The state to which this operation/transaction is applied. LastHashes m_lastHashes; std::shared_ptr m_ext; ///< The VM externality object for the VM execution or null if no VM is required. - std::unique_ptr m_vm; ///< The VM object or null if no VM is required. - bytes m_precompiledOut; ///< Used for the output when there is no VM for a contract (i.e. precompiled). - bytesConstRef m_out; ///< The copyable output. + bytesRef m_outRef; ///< Reference to "expected output" buffer. + ExecutionResult* m_res = nullptr; ///< Optional storage for execution results. Address m_newAddress; ///< The address of the created contract in the case of create() being called. unsigned m_depth = 0; ///< The context's call-depth. bool m_isCreation = false; ///< True if the transaction creates a contract, or if create() is called. - unsigned m_depositSize = 0; ///< Amount of code of the creation's attempted deposit. - u256 m_gasForDeposit; ///< Amount of gas remaining for the code deposit phase. - CodeDeposit m_codeDeposit = CodeDeposit::None; ///< True if an attempted deposit failed due to lack of gas. TransactionException m_excepted = TransactionException::None; ///< Details if the VM's execution resulted in an exception. u256 m_gas = 0; ///< The gas for EVM code execution. Initial amount before go() execution, final amount after go() execution. diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index 488d8e4b7..782d4d79c 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -35,7 +35,6 @@ bool ExtVM::call(CallParameters& _p) e.accrueSubState(sub); } _p.gas = e.gas(); - e.out().copyTo(_p.out); return !e.excepted(); } diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index babff4edf..853787493 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace { public: /// Full constructor. - ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0): - ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache) + ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, h256 const& _codeHash, unsigned _depth = 0): + ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _codeHash, _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache) { m_s.ensureCached(_myAddress, true, true); } diff --git a/libethereum/Interface.h b/libethereum/Interface.h index f7253ad29..636f73fbf 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -196,6 +196,8 @@ public: virtual void stopMining() = 0; /// Are we mining now? virtual bool isMining() const = 0; + /// Would we like to mine now? + virtual bool wouldMine() const = 0; /// Current hash rate. virtual uint64_t hashrate() const = 0; diff --git a/libethereum/Precompiled.cpp b/libethereum/Precompiled.cpp index 0e80949fe..780a8210f 100644 --- a/libethereum/Precompiled.cpp +++ b/libethereum/Precompiled.cpp @@ -31,7 +31,10 @@ using namespace std; using namespace dev; using namespace dev::eth; -static bytes ecrecoverCode(bytesConstRef _in) +namespace +{ + +void ecrecoverCode(bytesConstRef _in, bytesRef _out) { struct inType { @@ -44,47 +47,53 @@ static bytes ecrecoverCode(bytesConstRef _in) memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); h256 ret; - - if ((u256)in.v > 28) - return ret.asBytes(); - SignatureStruct sig(in.r, in.s, (byte)((int)(u256)in.v - 27)); - if (!sig.isValid()) - return ret.asBytes(); - - try + u256 v = (u256)in.v; + if (v >= 27 && v <= 28) { - ret = dev::sha3(recover(sig, in.hash)); + SignatureStruct sig(in.r, in.s, (byte)((int)v - 27)); + if (sig.isValid()) + { + try + { + Public rec = recover(sig, in.hash); + if (rec) + ret = dev::sha3(rec); + else + return; + } + catch (...) { return; } + } } - catch (...) {} memset(ret.data(), 0, 12); - return ret.asBytes(); + ret.ref().copyTo(_out); } -static bytes sha256Code(bytesConstRef _in) +void sha256Code(bytesConstRef _in, bytesRef _out) { - return sha256(_in).asBytes(); + sha256(_in).ref().copyTo(_out); } -static bytes ripemd160Code(bytesConstRef _in) +void ripemd160Code(bytesConstRef _in, bytesRef _out) { - return h256(ripemd160(_in), h256::AlignRight).asBytes(); + h256(ripemd160(_in), h256::AlignRight).ref().copyTo(_out); } -static bytes identityCode(bytesConstRef _in) +void identityCode(bytesConstRef _in, bytesRef _out) { - return _in.toBytes(); + _in.copyTo(_out); } -static const std::unordered_map c_precompiled = -{ - { 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }}, - { 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }}, - { 3, { [](bytesConstRef i) -> bigint { return c_ripemd160Gas + (i.size() + 31) / 32 * c_ripemd160WordGas; }, ripemd160Code }}, - { 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }} -}; +} std::unordered_map const& dev::eth::precompiled() { + static const std::unordered_map c_precompiled = + { + { 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }}, + { 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }}, + { 3, { [](bytesConstRef i) -> bigint { return c_ripemd160Gas + (i.size() + 31) / 32 * c_ripemd160WordGas; }, ripemd160Code }}, + { 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }} + }; return c_precompiled; } diff --git a/libethereum/Precompiled.h b/libethereum/Precompiled.h index bded27386..b50e51ecd 100644 --- a/libethereum/Precompiled.h +++ b/libethereum/Precompiled.h @@ -34,7 +34,7 @@ namespace eth struct PrecompiledAddress { std::function gas; - std::function exec; + std::function exec; }; /// Info on precompiled contract accounts baked into the protocol. diff --git a/libethereum/Sentinel.h b/libethereum/Sentinel.h new file mode 100644 index 000000000..141a5ee58 --- /dev/null +++ b/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 + +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_ diff --git a/libethereum/Sentinel.json b/libethereum/Sentinel.json new file mode 100644 index 000000000..743e4ce44 --- /dev/null +++ b/libethereum/Sentinel.json @@ -0,0 +1,3 @@ +[ + { "name": "eth_badBlock", "params": [ {} ], "order": [], "returns": 0 } +] diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 92c84c9b3..464cba9d4 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -141,7 +141,7 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h, ImportRequire // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; - enact(&b, _bc, _ir); + enact(BlockChain::verifyBlock(b), _bc, _ir); } else { @@ -158,6 +158,7 @@ State::State(State const& _s): m_transactions(_s.m_transactions), m_receipts(_s.m_receipts), m_transactionSet(_s.m_transactionSet), + m_touched(_s.m_touched), m_cache(_s.m_cache), m_previousBlock(_s.m_previousBlock), 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; @@ -217,19 +218,29 @@ StateDiff State::diff(State const& _c) const auto trie = SecureTrieDB(const_cast(&m_db), rootHash()); auto trieD = SecureTrieDB(const_cast(&_c.m_db), _c.rootHash()); - for (auto i: trie) - ads.insert(i.first), trieAds.insert(i.first); - for (auto i: trieD) - ads.insert(i.first), trieAdsD.insert(i.first); - for (auto i: m_cache) + if (_quick) + { + trieAds = m_touched; + trieAdsD = _c.m_touched; + (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); - for (auto i: _c.m_cache) + for (auto const& i: _c.m_cache) ads.insert(i.first); // cnote << *this; // cnote << _c; - for (auto i: ads) + for (auto const& i: ads) { auto it = m_cache.find(i); auto itD = _c.m_cache.find(i); @@ -272,7 +283,7 @@ void State::ensureCached(std::unordered_map& _cache, Address _ 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(); } @@ -382,7 +393,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) { #if ETH_TIMED_ENACTMENTS boost::timer t; @@ -393,8 +404,8 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const #endif // Check family: - BlockInfo biParent = _bc.info(_bi.parentHash); - _bi.verifyParent(biParent); + BlockInfo biParent = _bc.info(_block.info.parentHash); + _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS populateVerify = t.elapsed(); @@ -410,7 +421,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const t.restart(); #endif - sync(_bc, _bi.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo(), _ir); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -450,6 +461,7 @@ void State::resetCurrent() m_receipts.clear(); m_transactionSet.clear(); m_cache.clear(); + m_touched.clear(); m_currentBlock = BlockInfo(); m_currentBlock.coinbaseAddress = m_ourAddress; m_currentBlock.timestamp = max(m_previousBlock.timestamp + 1, (u256)time(0)); @@ -577,101 +589,93 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); vector receipts; - ostringstream ss; + string ret; unsigned i = 0; for (auto const& tr: rlp[1]) { - ss << " VM Execution of transaction" << i << ":" << endl; - execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, Executive::standardTrace(ss)); + StandardTrace st; + 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; m_receipts.back().streamRLP(receiptRLP); receipts.push_back(receiptRLP.out()); ++i; - ss << endl; } - return ss.str(); + return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) { - // m_currentBlock is assumed to be prepopulated and reset. - - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + DEV_TIMED_FUNCTION_ABOVE(500); + // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == bi.parentHash); - assert(m_currentBlock.parentHash == bi.parentHash); + assert(m_previousBlock.hash() == _block.info.parentHash); + assert(m_currentBlock.parentHash == _block.info.parentHash); assert(rootHash() == m_previousBlock.stateRoot); #endif if (m_currentBlock.parentHash != m_previousBlock.hash()) + // Internal client error. BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = bi; - m_currentBlock.verifyInternals(_block); + m_currentBlock = _block.info; m_currentBlock.noteDirty(); // cnote << "playback begins:" << m_state.root(); // cnote << m_state; - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); - RLP rlp(_block); + LastHashes lh; + DEV_TIMED_ABOVE(lastHashes, 500) + lh = _bc.lastHashes((unsigned)m_previousBlock.number); + + RLP rlp(_block.block); vector receipts; // All ok with the block generally. Play back the transactions now... unsigned i = 0; - for (auto const& tr: rlp[1]) - { - try { - LogOverride o(false); - execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); - } - catch (...) + DEV_TIMED_ABOVE(txEcec, 500) + for (auto const& tr: _block.transactions) { - badBlock(_block, "Invalid transaction"); - cwarn << " Transaction Index:" << i; - LogOverride o(true); - execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); - throw; + try + { + LogOverride o(false); + execute(lh, tr); + } + catch (Exception& ex) + { + ex << errinfo_transactionIndex(i); + throw; + } + + RLPStream receiptRLP; + m_receipts.back().streamRLP(receiptRLP); + receipts.push_back(receiptRLP.out()); + ++i; } - RLPStream receiptRLP; - m_receipts.back().streamRLP(receiptRLP); - receipts.push_back(receiptRLP.out()); - ++i; - } + h256 receiptsRoot; + DEV_TIMED_ABOVE(receiptsRoot, 500) + receiptsRoot = orderedTrieRoot(receipts); - auto receiptsRoot = orderedTrieRoot(receipts); if (receiptsRoot != m_currentBlock.receiptsRoot) { - badBlock(_block, "Bad receipts state root"); - cwarn << " Received: " << toString(m_currentBlock.receiptsRoot); - cwarn << " Expected: " << toString(receiptsRoot) << " which is:"; - for (unsigned j = 0; j < i; ++j) - { - auto b = receipts[j]; - cwarn << j << ": "; - cwarn << " RLP: " << RLP(b); - cwarn << " Hex: " << toHex(b); - cwarn << " " << TransactionReceipt(&b); - } - cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir); - BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot()); + InvalidReceiptsStateRoot ex; + ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); + ex << errinfo_receipts(receipts); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); + BOOST_THROW_EXCEPTION(ex); } if (m_currentBlock.logBloom != logBloom()) { - badBlock(_block, "Bad log bloom"); - cwarn << " Receipt blooms:"; - for (unsigned j = 0; j < i; ++j) - { - auto b = receipts[j]; - cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex(); - } - cwarn << " Final bloom:" << m_currentBlock.logBloom.hex(); - BOOST_THROW_EXCEPTION(InvalidLogBloom()); + InvalidLogBloom ex; + ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); + ex << errinfo_receipts(receipts); + BOOST_THROW_EXCEPTION(ex); } // Initialise total difficulty calculation. @@ -680,72 +684,85 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) { - badBlock(_block, "Too many uncles"); - BOOST_THROW_EXCEPTION(TooManyUncles()); + TooManyUncles ex; + ex << errinfo_max(2); + ex << errinfo_got(rlp[2].itemCount()); + BOOST_THROW_EXCEPTION(ex); } vector rewarded; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + h256Hash excluded; + DEV_TIMED_ABOVE(allKin, 500) + excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); excluded.insert(m_currentBlock.hash()); - for (auto const& i: rlp[2]) - { - auto h = sha3(i.data()); - if (excluded.count(h)) + unsigned ii = 0; + DEV_TIMED_ABOVE(uncleCheck, 500) + for (auto const& i: rlp[2]) { - badBlock(_block, "Invalid uncle included"); - BOOST_THROW_EXCEPTION(UncleInChain() << errinfo_comment("Uncle in block already mentioned") << errinfo_data(toString(excluded)) << errinfo_hash256(sha3(i.data()))); - } - excluded.insert(h); + try + { + auto h = sha3(i.data()); + if (excluded.count(h)) + { + 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 uncleParent(_bc.block(uncle.parentHash)); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) - { - badBlock(_block, "Uncle too old"); - cwarn << " Uncle number: " << uncle.number; - cwarn << " Uncle parent number: " << uncleParent.number; - cwarn << " Block number: " << m_currentBlock.number; - BOOST_THROW_EXCEPTION(UncleTooOld()); - } - 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; - BOOST_THROW_EXCEPTION(UncleIsBrother()); - } - uncle.verifyParent(uncleParent); + BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); -// tdIncrease += uncle.difficulty; - rewarded.push_back(uncle); - } + BlockInfo uncleParent; + if (!_bc.isKnown(uncle.parentHash)) + BOOST_THROW_EXCEPTION(UnknownParent()); + uncleParent = BlockInfo(_bc.block(uncle.parentHash)); - applyRewards(rewarded); + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + { + UncleTooOld ex; + ex << errinfo_uncleNumber(uncle.number); + ex << errinfo_currentNumber(m_currentBlock.number); + BOOST_THROW_EXCEPTION(ex); + } + else if (uncle.number == m_currentBlock.number) + { + UncleIsBrother ex; + ex << errinfo_uncleNumber(uncle.number); + ex << errinfo_currentNumber(m_currentBlock.number); + BOOST_THROW_EXCEPTION(ex); + } + uncle.verifyParent(uncleParent); + + rewarded.push_back(uncle); + ++ii; + } + catch (Exception& ex) + { + ex << errinfo_uncleIndex(ii); + throw; + } + } + + DEV_TIMED_ABOVE(applyRewards, 500) + applyRewards(rewarded); // Commit all cached state changes to the state trie. - commit(); + DEV_TIMED_ABOVE(commit, 500) + commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) { - badBlock(_block, "Bad state root"); - cnote << " Given to be:" << m_currentBlock.stateRoot; - // TODO: Fix -// cnote << SecureTrieDB(&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(); - BOOST_THROW_EXCEPTION(InvalidStateRoot()); + BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); } if (m_currentBlock.gasUsed != gasUsed()) { // Rollback the trie. - badBlock(_block, "Invalid gas used"); m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); } @@ -823,7 +840,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(&block.out(), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -1122,6 +1139,8 @@ h256 State::codeHash(Address _contract) const { if (!addressHasCode(_contract)) return EmptySHA3; + if (m_cache[_contract].isFreshCode()) + return sha3(code(_contract)); return m_cache[_contract].codeHash(); } @@ -1160,6 +1179,8 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const return true; } +#define ETH_VMTIMER 1 + ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) { #if ETH_PARANOIA @@ -1171,6 +1192,8 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per // Create and initialize the executive. This will throw fairly cheaply and quickly if the // transaction is bad in any way. Executive e(*this, _lh, 0); + ExecutionResult res; + e.setResultRecipient(res); e.initialize(_t); // Uncommitting is a non-trivial operation - only do it once we've verified as much of the @@ -1185,9 +1208,26 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per #endif if (!e.execute()) #if ETH_VMTRACE + { + if (isChannelVisible()) + e.go(e.simpleTrace()); + else + e.go(_onOp); + } +#elif ETH_VMTIMER { (void)_onOp; - e.go(e.simpleTrace()); + boost::timer t; + unordered_map counts; + unsigned total = 0; + e.go([&](uint64_t, Instruction inst, bigint, bigint, bigint, VM*, ExtVMFace const*) { + counts[(byte)inst]++; + total++; + }); + cnote << total << "total in" << t.elapsed(); + for (auto const& c: {Instruction::SSTORE, Instruction::SLOAD, Instruction::CALL, Instruction::CREATE, Instruction::CALLCODE, Instruction::MSTORE8, Instruction::MSTORE, Instruction::MLOAD, Instruction::SHA3}) + cnote << instructionInfo(c).name << counts[(byte)c]; + cnote; } #else e.go(_onOp); @@ -1230,7 +1270,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per m_transactionSet.insert(e.t().sha3()); } - return e.executionResult(); + return res; } State State::fromPending(unsigned _i) const diff --git a/libethereum/State.h b/libethereum/State.h index 55d5cfb4c..771cdb6bf 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -46,8 +46,25 @@ namespace test { class ImportTest; class StateLoader; } namespace eth { +// Import-specific errinfos +using errinfo_uncleIndex = boost::error_info; +using errinfo_currentNumber = boost::error_info; +using errinfo_uncleNumber = boost::error_info; +using errinfo_unclesExcluded = boost::error_info; +using errinfo_block = boost::error_info; +using errinfo_now = boost::error_info; + +using errinfo_transactionIndex = boost::error_info; + +using errinfo_vmtrace = boost::error_info; +using errinfo_receipts = boost::error_info>; +using errinfo_required_LogBloom = boost::error_info; +using errinfo_got_LogBloom = boost::error_info; +using LogBloomRequirementError = boost::tuple; + class BlockChain; class State; +struct VerifiedBlockRef; struct StateChat: public LogChannel { static const char* name(); static const int verbosity = 4; }; struct StateTrace: public LogChannel { static const char* name(); static const int verbosity = 5; }; @@ -294,10 +311,12 @@ public: State fromPending(unsigned _i) const; /// @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). - 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. /// This basically involves wiping ourselves if we've been superceded and rebuilding from the transaction queue. @@ -308,7 +327,7 @@ public: /// Execute all transactions within a given block. /// @returns the additional total difficulty. - u256 enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); /// Returns back to a pristine state after having done a playback. /// @arg _fullCommit if true flush everything out to disk. If false, this effectively only validates @@ -349,7 +368,7 @@ private: /// Execute the given block, assuming it corresponds to m_currentBlock. /// Throws on failure. - u256 enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); + u256 enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir = ImportRequirements::Default); /// Finalise the block, applying the earned rewards. void applyRewards(std::vector const& _uncleBlockHeaders); @@ -371,6 +390,7 @@ private: TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts. h256Hash m_transactionSet; ///< The set of transaction hashes that we've included in the state. OverlayDB m_lastTx; + AddressHash m_touched; ///< Tracks all addresses touched by transactions so far. mutable std::unordered_map m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed. @@ -394,8 +414,9 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -void commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) +AddressHash commit(std::unordered_map const& _cache, DB& _db, SecureTrieDB& _state) { + AddressHash ret; for (auto const& i: _cache) if (i.second.isDirty()) { @@ -434,7 +455,9 @@ void commit(std::unordered_map const& _cache, DB& _db, SecureT _state.insert(i.first, &s.out()); } + ret.insert(i.first); } + return ret; } } diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index b8d8d64c1..58ecc44fa 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -39,29 +39,25 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _e return _out; } -std::string badTransaction(bytesConstRef _tx, string const& _err) -{ - stringstream ret; - ret << "========================================================================" << endl; - ret << "== Software Failure " << (_err + string(max(0, 44 - _err.size()), ' ')) << " ==" << endl; - ret << "== Guru Meditation " << sha3(_tx).abridged() << " ==" << endl; - ret << "========================================================================" << endl; - ret << " Transaction: " << toHex(_tx) << endl; - ret << " Transaction RLP: "; - try { - ret << RLP(_tx); - } - catch (Exception& _e) - { - ret << "Invalid: " << _e.what(); - } - ret << endl; - - return ret.str(); -} - -TransactionException dev::eth::toTransactionException(VMException const& _e) +TransactionException dev::eth::toTransactionException(Exception const& _e) { + // Basic Transaction exceptions + if (!!dynamic_cast(&_e)) + return TransactionException::BadRLP; + if (!!dynamic_cast(&_e)) + return TransactionException::OutOfGasIntrinsic; + if (!!dynamic_cast(&_e)) + return TransactionException::InvalidSignature; + // Executive exceptions + if (!!dynamic_cast(&_e)) + return TransactionException::OutOfGasBase; + if (!!dynamic_cast(&_e)) + return TransactionException::InvalidNonce; + if (!!dynamic_cast(&_e)) + return TransactionException::NotEnoughCash; + if (!!dynamic_cast(&_e)) + return TransactionException::BlockGasLimitReached; + // VM execution exceptions if (!!dynamic_cast(&_e)) return TransactionException::BadInstruction; if (!!dynamic_cast(&_e)) @@ -75,6 +71,28 @@ TransactionException dev::eth::toTransactionException(VMException const& _e) 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) { int field = 0; @@ -114,7 +132,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig) throw; } 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 diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 935b78c2a..e9b1cbf80 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -25,6 +25,7 @@ #include #include #include + namespace dev { namespace eth @@ -48,6 +49,8 @@ enum class TransactionException { None = 0, Unknown, + BadRLP, + OutOfGasIntrinsic, ///< Too little gas to pay for the base transaction cost. InvalidSignature, InvalidNonce, NotEnoughCash, @@ -69,30 +72,20 @@ enum class CodeDeposit 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. struct ExecutionResult { - ExecutionResult() = default; - ExecutionResult(u256 const& _gasUsed, TransactionException _excepted, Address const& _newAddress, bytesConstRef _output, CodeDeposit _codeDeposit, u256 const& _gasRefund, unsigned _depositSize, u256 const& _gasForDeposit): - gasUsed(_gasUsed), - excepted(_excepted), - newAddress(_newAddress), - output(_output.toBytes()), - codeDeposit(_codeDeposit), - gasRefunded(_gasRefund), - depositSize(_depositSize), - gasForDeposit(_gasForDeposit) - {} u256 gasUsed = 0; TransactionException excepted = TransactionException::Unknown; Address newAddress; bytes output; - CodeDeposit codeDeposit = CodeDeposit::None; + CodeDeposit codeDeposit = CodeDeposit::None; ///< Failed if an attempted deposit failed due to lack of gas. u256 gasRefunded = 0; - unsigned depositSize = 0; - u256 gasForDeposit; + unsigned depositSize = 0; ///< Amount of code of the creation's attempted deposit. + u256 gasForDeposit; ///< Amount of gas remaining for the code deposit phase. }; std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er); @@ -235,8 +228,5 @@ inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t) return _out; } -void badTransaction(bytesConstRef _tx, std::string const& _err); -inline void badTransaction(bytes const& _tx, std::string const& _err) { badTransaction(&_tx, _err); } - } } diff --git a/libethereum/VerifiedBlock.h b/libethereum/VerifiedBlock.h new file mode 100644 index 000000000..ddd808901 --- /dev/null +++ b/libethereum/VerifiedBlock.h @@ -0,0 +1,53 @@ +/* + 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 VerfiedBlock.h + * @author Gav Wood + * @date 2014 + */ + + +#include +#include + +#pragma once + +namespace dev +{ +namespace eth +{ + +class Transaction; + +/// @brief Verified block info, does not hold block data, but a reference instead +struct VerifiedBlockRef +{ + bytesConstRef block; ///< Block data reference + BlockInfo info; ///< Prepopulated block info + std::vector transactions; ///< Verified list of block transactions +}; + +/// @brief Verified block info, combines block data and verified info/transactions +struct VerifiedBlock +{ + VerifiedBlockRef verified; ///< Verified block structures + bytes blockData; ///< Block data +}; + +using VerifiedBlocks = std::vector; + +} +} diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp index ebef1fdb0..ad419d2a3 100644 --- a/libevm/ExtVMFace.cpp +++ b/libevm/ExtVMFace.cpp @@ -25,7 +25,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth): +ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth): myAddress(_myAddress), caller(_caller), origin(_origin), @@ -33,6 +33,7 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 gasPrice(_gasPrice), data(_data), code(_code), + codeHash(_codeHash), lastHashes(_lh), previousBlock(_previousBlock), currentBlock(_currentBlock), diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 6b35094bb..bb102bef3 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -130,7 +130,7 @@ public: ExtVMFace() = default; /// Full constructor. - ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth); + ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth); virtual ~ExtVMFace() = default; @@ -186,6 +186,7 @@ public: u256 gasPrice; ///< Price of gas (that we already paid). bytesConstRef data; ///< Current input data. bytes code; ///< Current code that is executing. + h256 codeHash; ///< SHA3 hash of the executing code LastHashes lastHashes; ///< Most recent 256 blocks' hashes. BlockInfo previousBlock; ///< The previous block's information. TODO: PoC-8: REMOVE BlockInfo currentBlock; ///< The current block's information. diff --git a/libevm/SmartVM.cpp b/libevm/SmartVM.cpp index d37abc1bf..12f2f7078 100644 --- a/libevm/SmartVM.cpp +++ b/libevm/SmartVM.cpp @@ -41,7 +41,7 @@ namespace } } -bytesConstRef SmartVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +bytesConstRef SmartVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) { auto codeHash = sha3(_ext.code); auto vmKind = VMKind::Interpreter; // default VM @@ -68,7 +68,7 @@ bytesConstRef SmartVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, // TODO: Selected VM must be kept only because it returns reference to its internal memory. // VM implementations should be stateless, without escaping memory reference. m_selectedVM = VMFactory::create(vmKind); - return m_selectedVM->go(io_gas, _ext, _onOp, _steps); + return m_selectedVM->execImpl(io_gas, _ext, _onOp); } } diff --git a/libevm/SmartVM.h b/libevm/SmartVM.h index cc198c0c2..fce7be21e 100644 --- a/libevm/SmartVM.h +++ b/libevm/SmartVM.h @@ -31,7 +31,7 @@ namespace eth class SmartVM: public VMFace { public: - virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) override final; private: std::unique_ptr m_selectedVM; diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 8c96a35b2..36fba6e43 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -45,166 +45,169 @@ static array metrics() return s_ret; } -bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +void VM::checkRequirements(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, Instruction _inst) { - // Reset leftovers from possible previous run - m_curPC = 0; - m_jumpDests.clear(); + static const auto c_metrics = metrics(); + auto& metric = c_metrics[static_cast(_inst)]; - m_stack.reserve((unsigned)c_stackLimit); + if (metric.gasPriceTier == InvalidTier) + BOOST_THROW_EXCEPTION(BadInstruction()); - unique_ptr callParams; + // FEES... + bigint runGas = c_tierStepGas[metric.gasPriceTier]; + bigint newTempSize = m_temp.size(); + bigint copySize = 0; - static const array c_metrics = metrics(); + // should work, but just seems to result in immediate errorless exit on initial execution. yeah. weird. + //m_onFail = std::function(onOperation); - auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; - auto gasForMem = [](bigint _size) -> bigint + require(metric.args, metric.ret); + + auto onOperation = [&]() { - bigint s = _size / 32; - return (bigint)c_memoryGas * s + s * s / c_quadCoeffDiv; + if (_onOp) + _onOp(m_steps, _inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, io_gas, this, &_ext); }; - if (m_jumpDests.empty()) - for (unsigned i = 0; i < _ext.code.size(); ++i) + auto memNeed = [](u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; + + 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) - m_jumpDests.push_back(i); - else if (_ext.code[i] >= (byte)Instruction::PUSH1 && _ext.code[i] <= (byte)Instruction::PUSH32) - i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1; + runGas = c_sstoreResetGas; + _ext.sub.refunds += c_sstoreRefundGas; } - u256 nextPC = m_curPC + 1; - auto osteps = _steps; - for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1) + else + 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... - Instruction inst = (Instruction)_ext.getCode(m_curPC); - auto metric = c_metrics[(int)inst]; - int gasPriceTier = metric.gasPriceTier; - - 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(onOperation); - - require(metric.args, metric.ret); - - auto onOperation = [&]() - { - if (_onOp) - _onOp(osteps - _steps - 1, 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; + 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::SLOAD: - runGas = c_sloadGas; - break; + case Instruction::CALL: + case Instruction::CALLCODE: + 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: - 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; + auto gasForMem = [](bigint _size) -> bigint + { + bigint s = _size / 32; + return (bigint)c_memoryGas * s + s * s / c_quadCoeffDiv; + }; - case Instruction::JUMPDEST: - runGas = 1; - break; + newTempSize = (newTempSize + 31) / 32 * 32; + if (newTempSize > m_temp.size()) + runGas += gasForMem(newTempSize) - gasForMem(m_temp.size()); + runGas += c_copyGas * ((copySize + 31) / 32); - case Instruction::LOG0: - 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; - } + onOperation(); - case Instruction::CALL: - case Instruction::CALLCODE: - 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; + if (io_gas < runGas) + BOOST_THROW_EXCEPTION(OutOfGas()); - 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:; - } + io_gas -= (u256)runGas; - newTempSize = (newTempSize + 31) / 32 * 32; - if (newTempSize > m_temp.size()) - runGas += gasForMem(newTempSize) - gasForMem(m_temp.size()); - runGas += c_copyGas * ((copySize + 31) / 32); + if (newTempSize > m_temp.size()) + m_temp.resize((size_t)newTempSize); +} - onOperation(); +bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) +{ + m_stack.reserve((unsigned)c_stackLimit); - if (io_gas < runGas) - BOOST_THROW_EXCEPTION(OutOfGas()); + for (size_t i = 0; i < _ext.code.size(); ++i) + { + 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 const& _validDests) + { + auto nextPC = static_cast(_dest); + if (!std::binary_search(_validDests.begin(), _validDests.end(), nextPC) || _dest > std::numeric_limits::max()) + BOOST_THROW_EXCEPTION(BadJumpDestination()); + return nextPC; + }; - if (newTempSize > m_temp.size()) - m_temp.resize((size_t)newTempSize); + m_steps = 0; + 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) { case Instruction::ADD: @@ -300,7 +303,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 case Instruction::SIGNEXTEND: if (m_stack.back() < 31) { - unsigned const testBit(m_stack.back() * 8 + 7); + auto testBit = static_cast(m_stack.back()) * 8 + 7; u256& number = m_stack[m_stack.size() - 2]; u256 mask = ((u256(1) << testBit) - 1); if (boost::multiprecision::bit_test(number, testBit)) @@ -481,7 +484,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 case Instruction::DUP15: 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]); break; } @@ -502,7 +505,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 case Instruction::SWAP15: case Instruction::SWAP16: { - unsigned n = (int)inst - (int)Instruction::SWAP1 + 2; + auto n = (unsigned)inst - (unsigned)Instruction::SWAP1 + 2; auto d = m_stack.back(); m_stack.back() = m_stack[m_stack.size() - n]; m_stack[m_stack.size() - n] = d; @@ -536,18 +539,12 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 m_stack.pop_back(); break; case Instruction::JUMP: - nextPC = m_stack.back(); - if (find(m_jumpDests.begin(), m_jumpDests.end(), (uint64_t)nextPC) == m_jumpDests.end() || nextPC > numeric_limits::max() ) - BOOST_THROW_EXCEPTION(BadJumpDestination()); + nextPC = verifyJumpDest(m_stack.back(), m_jumpDests); m_stack.pop_back(); break; case Instruction::JUMPI: if (m_stack[m_stack.size() - 2]) - { - nextPC = m_stack.back(); - if (find(m_jumpDests.begin(), m_jumpDests.end(), (uint64_t)nextPC) == m_jumpDests.end() || nextPC > numeric_limits::max() ) - BOOST_THROW_EXCEPTION(BadJumpDestination()); - } + nextPC = verifyJumpDest(m_stack.back(), m_jumpDests); m_stack.pop_back(); m_stack.pop_back(); break; @@ -599,7 +596,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 break; case Instruction::CREATE: { - u256 endowment = m_stack.back(); + auto endowment = m_stack.back(); m_stack.pop_back(); unsigned initOff = (unsigned)m_stack.back(); m_stack.pop_back(); @@ -615,16 +612,14 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 case Instruction::CALL: case Instruction::CALLCODE: { - if (!callParams) - callParams.reset(new CallParameters); - - callParams->gas = m_stack.back(); + CallParameters callParams; + callParams.gas = m_stack.back(); if (m_stack[m_stack.size() - 3] > 0) - callParams->gas += c_callStipend; + callParams.gas += c_callStipend; m_stack.pop_back(); - callParams->codeAddress = asAddress(m_stack.back()); + callParams.codeAddress = asAddress(m_stack.back()); m_stack.pop_back(); - callParams->value = m_stack.back(); + callParams.value = m_stack.back(); m_stack.pop_back(); unsigned inOff = (unsigned)m_stack.back(); @@ -636,19 +631,19 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 unsigned outSize = (unsigned)m_stack.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->senderAddress = _ext.myAddress; - callParams->receiveAddress = inst == Instruction::CALL ? callParams->codeAddress : callParams->senderAddress; - callParams->data = bytesConstRef(m_temp.data() + inOff, inSize); - callParams->out = bytesRef(m_temp.data() + outOff, outSize); - m_stack.push_back(_ext.call(*callParams)); + callParams.onOp = _onOp; + callParams.senderAddress = _ext.myAddress; + callParams.receiveAddress = inst == Instruction::CALL ? callParams.codeAddress : callParams.senderAddress; + callParams.data = bytesConstRef(m_temp.data() + inOff, inSize); + callParams.out = bytesRef(m_temp.data() + outOff, outSize); + m_stack.push_back(_ext.call(callParams)); } else m_stack.push_back(0); - io_gas += callParams->gas; + io_gas += callParams.gas; break; } case Instruction::RETURN: @@ -670,7 +665,5 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 } } - if (_steps == (uint64_t)-1) - BOOST_THROW_EXCEPTION(StepsDone()); return bytesConstRef(); } diff --git a/libevm/VM.h b/libevm/VM.h index 6f984ec5c..1931ad748 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -52,18 +52,20 @@ inline u256 fromAddress(Address _a) class VM: public VMFace { public: - virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) 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; } u256s const& stack() const { return m_stack; } 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 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; u256s m_stack; std::vector m_jumpDests; diff --git a/libevm/VMFace.h b/libevm/VMFace.h index d2a12e0ca..cba1c7287 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -25,8 +25,8 @@ namespace dev namespace eth { +#define ETH_SIMPLE_EXCEPTION_VM(X) struct X: virtual VMException { public X(): VMException(#X) {} }; struct VMException: virtual Exception {}; -struct StepsDone: virtual VMException {}; struct BreakPointHit: virtual VMException {}; struct BadInstruction: virtual VMException {}; struct BadJumpDestination: virtual VMException {}; @@ -43,7 +43,22 @@ public: VMFace(VMFace const&) = delete; VMFace& operator=(VMFace const&) = delete; - virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; + /// Execute EVM code by VM. + /// + /// @param _out Expected output + void exec(u256& io_gas, ExtVMFace& _ext, bytesRef _out, OnOpFunc const& _onOp = {}) + { + execImpl(io_gas, _ext, _onOp).copyTo(_out); + } + + /// The same as above but returns a copy of full output. + bytes exec(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}) + { + return execImpl(io_gas, _ext, _onOp).toVector(); + } + + /// VM implementation + virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) = 0; }; } diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 8642824f6..3557fc0ee 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -109,7 +109,7 @@ string Assembly::getLocationFromSources(StringMap const& _sourceCodes, SourceLoc if (newLinePos != string::npos) cut = cut.substr(0, newLinePos) + "..."; - return move(cut); + return cut; } ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap const& _sourceCodes) const diff --git a/libevmcore/Exceptions.h b/libevmcore/Exceptions.h index 72af277df..f520ade5f 100644 --- a/libevmcore/Exceptions.h +++ b/libevmcore/Exceptions.h @@ -28,8 +28,8 @@ namespace dev namespace eth { -struct InvalidDeposit: virtual Exception {}; -struct InvalidOpcode: virtual Exception {}; +DEV_SIMPLE_EXCEPTION(InvalidDeposit); +DEV_SIMPLE_EXCEPTION(InvalidOpcode); } } diff --git a/libp2p/Capability.cpp b/libp2p/Capability.cpp index ecc458730..bc4aa0b04 100644 --- a/libp2p/Capability.cpp +++ b/libp2p/Capability.cpp @@ -23,18 +23,19 @@ #include #include "Session.h" +#include "Host.h" using namespace std; using namespace dev; using namespace dev::p2p; -Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_host(_h), m_idOffset(_idOffset) +Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_hostCap(_h), m_idOffset(_idOffset) { - clog(NetConnect) << "New session for capability" << m_host->name() << "; idOffset:" << m_idOffset; + clog(NetConnect) << "New session for capability" << m_hostCap->name() << "; idOffset:" << m_idOffset; } void Capability::disable(std::string const& _problem) { - clog(NetWarn) << "DISABLE: Disabling capability '" << m_host->name() << "'. Reason:" << _problem; + clog(NetWarn) << "DISABLE: Disabling capability '" << m_hostCap->name() << "'. Reason:" << _problem; m_enabled = false; } @@ -52,3 +53,8 @@ void Capability::addRating(int _r) { m_session->addRating(_r); } + +ReputationManager& Capability::repMan() const +{ + return host()->repMan(); +} diff --git a/libp2p/Capability.h b/libp2p/Capability.h index d09391655..b4f59b243 100644 --- a/libp2p/Capability.h +++ b/libp2p/Capability.h @@ -29,6 +29,8 @@ namespace dev namespace p2p { +class ReputationManager; + class Capability { friend class Session; @@ -43,7 +45,9 @@ public: static unsigned messageCount() { return 0; } */ Session* session() const { return m_session; } - HostCapabilityFace* hostCapability() const { return m_host; } + HostCapabilityFace* hostCapability() const { return m_hostCap; } + Host* host() const { return m_hostCap->host(); } + ReputationManager& repMan() const; protected: virtual bool interpret(unsigned _id, RLP const&) = 0; @@ -56,7 +60,7 @@ protected: private: Session* m_session; - HostCapabilityFace* m_host; + HostCapabilityFace* m_hostCap; bool m_enabled = true; unsigned m_idOffset; }; diff --git a/libp2p/Common.h b/libp2p/Common.h index 8fd330580..4a1b64b70 100644 --- a/libp2p/Common.h +++ b/libp2p/Common.h @@ -183,8 +183,8 @@ struct NodeIPEndpoint uint16_t udpPort = 0; uint16_t tcpPort = 0; - operator bi::udp::endpoint() const { return std::move(bi::udp::endpoint(address, udpPort)); } - operator bi::tcp::endpoint() const { return std::move(bi::tcp::endpoint(address, tcpPort)); } + operator bi::udp::endpoint() const { return bi::udp::endpoint(address, udpPort); } + operator bi::tcp::endpoint() const { return bi::tcp::endpoint(address, tcpPort); } operator bool() const { return !address.is_unspecified() && udpPort > 0 && tcpPort > 0; } diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b6c9efec9..f4cceebf2 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -55,6 +55,25 @@ void HostNodeTableHandler::processEvent(NodeId const& _n, NodeTableEventType con m_host.onNodeTableEvent(_n, _e); } +ReputationManager::ReputationManager() +{ +} + +void ReputationManager::noteRude(Session const& _s, std::string const& _sub) +{ + m_nodes[make_pair(_s.id(), _s.info().clientVersion)].subs[_sub].isRude = true; +} + +bool ReputationManager::isRude(Session const& _s, std::string const& _sub) const +{ + auto nit = m_nodes.find(make_pair(_s.id(), _s.info().clientVersion)); + if (nit == m_nodes.end()) + return false; + auto sit = nit->second.subs.find(_sub); + bool ret = sit == nit->second.subs.end() ? false : sit->second.isRude; + return _sub.empty() ? ret : (ret || isRude(_s)); +} + Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bytesConstRef _restoreNetwork): Worker("p2p", 0), m_restoreNetwork(_restoreNetwork.toBytes()), @@ -834,7 +853,7 @@ KeyPair Host::networkAlias(bytesConstRef _b) { RLP r(_b); if (r.itemCount() == 3 && r[0].isInt() && r[0].toInt() >= 3) - return move(KeyPair(move(Secret(r[1].toBytes())))); + return KeyPair(Secret(r[1].toBytes())); else - return move(KeyPair::create()); + return KeyPair::create(); } diff --git a/libp2p/Host.h b/libp2p/Host.h index 3c7ce257a..132dd379a 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -45,6 +45,18 @@ namespace ba = boost::asio; namespace bi = ba::ip; +namespace std +{ +template<> struct hash> +{ + size_t operator()(pair const& _value) const + { + size_t ret = hash()(_value.first); + return ret ^ (hash()(_value.second) + 0x9e3779b9 + (ret << 6) + (ret >> 2)); + } +}; +} + namespace dev { @@ -66,6 +78,29 @@ private: Host& m_host; }; +struct SubReputation +{ + bool isRude = false; + int utility = 0; +}; + +struct Reputation +{ + std::unordered_map subs; +}; + +class ReputationManager +{ +public: + ReputationManager(); + + void noteRude(Session const& _s, std::string const& _sub = std::string()); + bool isRude(Session const& _s, std::string const& _sub = std::string()) const; + +private: + std::unordered_map, Reputation> m_nodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. +}; + /** * @brief The Host class * Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe. @@ -152,6 +187,9 @@ public: /// @returns if network has been started. bool isStarted() const { return isWorking(); } + /// @returns our reputation manager. + ReputationManager& repMan() { return m_repMan; } + /// @returns if network is started and interactive. bool haveNetwork() const { return m_run && !!m_nodeTable; } @@ -255,6 +293,8 @@ private: std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers. bool m_accepting = false; bool m_dropPeers = false; + + ReputationManager m_repMan; }; } diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp index d8ab90a20..2f2f247b6 100644 --- a/libp2p/Network.cpp +++ b/libp2p/Network.cpp @@ -111,7 +111,7 @@ std::set Network::getInterfaceAddresses() #endif - return std::move(addresses); + return addresses; } int Network::tcp4Listen(bi::tcp::acceptor& _acceptor, NetworkPreferences const& _netPrefs) diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index bf056c52f..6344dc263 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -88,7 +88,7 @@ shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relati } if (!_node.endpoint) - return move(shared_ptr()); + return shared_ptr(); // ping address to recover nodeid if nodeid is empty if (!_node.id) @@ -98,7 +98,7 @@ shared_ptr NodeTable::addNode(Node const& _node, NodeRelation _relati DEV_GUARDED(x_pubkDiscoverPings) m_pubkDiscoverPings[_node.endpoint.address] = std::chrono::steady_clock::now(); ping(_node.endpoint); - return move(shared_ptr()); + return shared_ptr(); } DEV_GUARDED(x_nodes) @@ -129,7 +129,7 @@ list NodeTable::nodes() const DEV_GUARDED(x_nodes) for (auto& i: m_nodes) nodes.push_back(i.second->id); - return move(nodes); + return nodes; } list NodeTable::snapshot() const @@ -140,7 +140,7 @@ list NodeTable::snapshot() const for (auto const& np: s.nodes) if (auto n = np.lock()) ret.push_back(*n); - return move(ret); + return ret; } Node NodeTable::node(NodeId const& _id) @@ -282,7 +282,7 @@ vector> NodeTable::nearestNodeEntries(NodeId _target) for (auto const& n: nodes.second) if (ret.size() < s_bucketSize && !!n->endpoint && n->endpoint.isAllowed()) ret.push_back(n); - return move(ret); + return ret; } void NodeTable::ping(NodeIPEndpoint _to) const @@ -422,8 +422,8 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes unsigned packetType = signedBytes[0]; bytesConstRef rlpBytes(_packet.cropped(h256::size + Signature::size + 1)); - RLP rlp(rlpBytes); try { + RLP rlp(rlpBytes); switch (packetType) { case Pong::type: diff --git a/libp2p/RLPxFrameIO.cpp b/libp2p/RLPxFrameIO.cpp index ac1a27bed..4fa8557ba 100644 --- a/libp2p/RLPxFrameIO.cpp +++ b/libp2p/RLPxFrameIO.cpp @@ -154,7 +154,7 @@ h128 RLPXFrameIO::egressDigest() SHA3_256 h(m_egressMac); h128 digest; h.TruncatedFinal(digest.data(), h128::size); - return move(digest); + return digest; } h128 RLPXFrameIO::ingressDigest() @@ -162,7 +162,7 @@ h128 RLPXFrameIO::ingressDigest() SHA3_256 h(m_ingressMac); h128 digest; h.TruncatedFinal(digest.data(), h128::size); - return move(digest); + return digest; } void RLPXFrameIO::updateEgressMACWithHeader(bytesConstRef _headerCipher) diff --git a/libp2p/RLPxFrameIO.h b/libp2p/RLPxFrameIO.h index 0f0504e48..9d4c274be 100644 --- a/libp2p/RLPxFrameIO.h +++ b/libp2p/RLPxFrameIO.h @@ -56,7 +56,7 @@ public: bool isConnected() const { return m_socket.is_open(); } void close() { try { boost::system::error_code ec; m_socket.shutdown(bi::tcp::socket::shutdown_both, ec); if (m_socket.is_open()) m_socket.close(); } catch (...){} } - bi::tcp::endpoint remoteEndpoint() { try { return m_socket.remote_endpoint(); } catch (...){ return bi::tcp::endpoint(); } } + bi::tcp::endpoint remoteEndpoint() { boost::system::error_code ec; return m_socket.remote_endpoint(ec); } bi::tcp::socket& ref() { return m_socket; } protected: @@ -130,4 +130,4 @@ private: }; } -} \ No newline at end of file +} diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 462fea7b1..6400a5849 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -70,6 +70,11 @@ Session::~Session() delete m_io; } +ReputationManager& Session::repMan() const +{ + return m_server->repMan(); +} + NodeId Session::id() const { return m_peer ? m_peer->id : NodeId(); @@ -450,6 +455,7 @@ void Session::doRead() else if (ec && length < tlen) { clog(NetWarn) << "Error reading - Abrupt peer disconnect: " << ec.message(); + repMan().noteRude(*this); drop(TCPError); return; } diff --git a/libp2p/Session.h b/libp2p/Session.h index bcbf8022b..1e5d69ee0 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -43,6 +43,7 @@ namespace p2p { class Peer; +class ReputationManager; /** * @brief The Session class @@ -75,6 +76,7 @@ public: static RLPStream& prep(RLPStream& _s, PacketType _t, unsigned _args = 0); void sealAndSend(RLPStream& _s); + ReputationManager& repMan() const; int rating() const; void addRating(int _r); diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index 9f89d9ad0..0b85bae4b 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -52,12 +52,12 @@ h256 RLPXDatagramFace::sign(Secret const& _k) bytesConstRef signedRLPx(&data[h256::size], data.size() - h256::size); dev::sha3(signedRLPx).ref().copyTo(rlpxHash); - return std::move(sighash); + return sighash; } Public RLPXDatagramFace::authenticate(bytesConstRef _sig, bytesConstRef _rlp) { Signature const& sig = *(Signature const*)_sig.data(); - return std::move(dev::recover(sig, sha3(_rlp))); + return dev::recover(sig, sha3(_rlp)); } diff --git a/libp2p/UDP.h b/libp2p/UDP.h index 474cb5442..e345ce07f 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -81,7 +81,7 @@ template struct RLPXDatagram: public RLPXDatagramFace { 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; } }; diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 4c7168afa..acb7b50c5 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -410,7 +410,14 @@ void InheritanceSpecifier::checkTypeRequirements() BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call.")); for (size_t i = 0; i < m_arguments.size(); ++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 @@ -592,7 +599,14 @@ void ModifierInvocation::checkTypeRequirements(vector BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for modifier invocation.")); for (size_t i = 0; i < m_arguments.size(); ++i) 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() @@ -782,9 +796,18 @@ void FunctionCall::checkTypeRequirements(TypePointers const*) { // call by positional arguments for (size_t i = 0; i < m_arguments.size(); ++i) - if (!functionType->takesArbitraryParameters() && - !m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) - BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("Invalid type for argument in function call.")); + if ( + !functionType->takesArbitraryParameters() && + !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 { @@ -808,7 +831,14 @@ void FunctionCall::checkTypeRequirements(TypePointers const*) if (parameterNames[j] == *m_names[i]) { // check type convertible 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; break; diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 578709c1e..b3984840f 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -503,7 +503,7 @@ public: /// 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. - TypePointer getType(ContractDefinition const* = nullptr) const { return m_type; } + TypePointer getType(ContractDefinition const* = nullptr) const override { return m_type; } void setType(std::shared_ptr const& _type) { m_type = _type; } virtual bool isLValue() const override; diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index 2edff82e1..fde6adacc 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -133,7 +133,7 @@ set CompilerContext::getFunctionsWithoutCode() for (auto const& it: m_functionEntryLabels) if (m_functionsWithCode.count(it.first) == 0) functions.insert(it.first); - return move(functions); + return functions; } ModifierDefinition const& CompilerContext::getFunctionModifier(string const& _name) const diff --git a/libsolidity/LValue.h b/libsolidity/LValue.h index 1617e8167..726d63328 100644 --- a/libsolidity/LValue.h +++ b/libsolidity/LValue.h @@ -109,7 +109,7 @@ public: StorageItem(CompilerContext& _compilerContext, Declaration const& _declaration); /// Constructs the LValue and assumes that the storage reference is already on the stack. 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 storeValue( Type const& _sourceType, diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 1316bbc37..e1161c3fb 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -1459,29 +1459,29 @@ MagicType::MagicType(MagicType::Kind _kind): switch (m_kind) { case Kind::Block: - m_members = move(MemberList({ + m_members = MemberList({ {"coinbase", make_shared(0, IntegerType::Modifier::Address)}, {"timestamp", make_shared(256)}, {"blockhash", make_shared(strings{"uint"}, strings{"bytes32"}, FunctionType::Location::BlockHash)}, {"difficulty", make_shared(256)}, {"number", make_shared(256)}, {"gaslimit", make_shared(256)} - })); + }); break; case Kind::Message: - m_members = move(MemberList({ + m_members = MemberList({ {"sender", make_shared(0, IntegerType::Modifier::Address)}, {"gas", make_shared(256)}, {"value", make_shared(256)}, {"data", make_shared(ReferenceType::Location::CallData)}, {"sig", make_shared(4)} - })); + }); break; case Kind::Transaction: - m_members = move(MemberList({ + m_members = MemberList({ {"origin", make_shared(0, IntegerType::Modifier::Address)}, {"gasprice", make_shared(256)} - })); + }); break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic.")); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 3ec925395..17d30ea6c 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -407,7 +407,7 @@ public: virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(const Type& _other) 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 unsigned getSizeOnStack() const override; virtual std::string toString() const override; @@ -820,7 +820,7 @@ public: 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 canLiveOutsideStorage() const override { return true; } virtual unsigned getSizeOnStack() const override { return 0; } diff --git a/libtestutils/FixedClient.h b/libtestutils/FixedClient.h index 59da9075f..bdec08849 100644 --- a/libtestutils/FixedClient.h +++ b/libtestutils/FixedClient.h @@ -48,7 +48,7 @@ public: 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 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 {} private: diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 35c35c3f0..1eddc22d4 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -43,7 +43,7 @@ class WebThreeStubServer: public dev::WebThreeStubServerBase, public dev::WebThr public: WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::shared_ptr const& _ethAccounts, std::vector const& _shhAccounts); - virtual std::string web3_clientVersion(); + virtual std::string web3_clientVersion() override; private: virtual dev::eth::Interface* client() override; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index ff7b84dc4..fa07e7dd3 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -781,17 +781,15 @@ string WebThreeStubServerBase::eth_newFilter(Json::Value const& _json) } } -string WebThreeStubServerBase::eth_newBlockFilter(string const& _filter) +string WebThreeStubServerBase::eth_newBlockFilter() { - h256 filter; - - if (_filter.compare("chain") == 0 || _filter.compare("latest") == 0) - filter = dev::eth::ChainChangedFilter; - else if (_filter.compare("pending") == 0) - filter = dev::eth::PendingChangedFilter; - else - BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); - + h256 filter = dev::eth::ChainChangedFilter; + return toJS(client()->installWatch(filter)); +} + +string WebThreeStubServerBase::eth_newPendingTransactionFilter() +{ + h256 filter = dev::eth::PendingChangedFilter; return toJS(client()->installWatch(filter)); } diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index f3f7edfe7..d90df1445 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -107,7 +107,8 @@ public: virtual std::string eth_compileSerpent(std::string const& _s); virtual std::string eth_compileSolidity(std::string const& _code); virtual std::string eth_newFilter(Json::Value const& _json); - virtual std::string eth_newBlockFilter(std::string const& _filter); + virtual std::string eth_newBlockFilter(); + virtual std::string eth_newPendingTransactionFilter(); virtual bool eth_uninstallFilter(std::string const& _filterId); virtual Json::Value eth_getFilterChanges(std::string const& _filterId); virtual Json::Value eth_getFilterLogs(std::string const& _filterId); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 89313df89..6a1a3df10 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -47,7 +47,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_compileSerpent", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileSerpentI); this->bindAndAddMethod(jsonrpc::Procedure("eth_compileSolidity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileSolidityI); this->bindAndAddMethod(jsonrpc::Procedure("eth_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterI); - this->bindAndAddMethod(jsonrpc::Procedure("eth_newBlockFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newBlockFilterI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_newBlockFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newBlockFilterI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_newPendingTransactionFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newPendingTransactionFilterI); this->bindAndAddMethod(jsonrpc::Procedure("eth_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_uninstallFilterI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterChanges", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterChangesI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsI); @@ -228,7 +229,13 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_newBlockFilter(request[0u].asString()); + (void)request; + response = this->eth_newBlockFilter(); + } + inline virtual void eth_newPendingTransactionFilterI(const Json::Value &request, Json::Value &response) + { + (void)request; + response = this->eth_newPendingTransactionFilter(); } inline virtual void eth_uninstallFilterI(const Json::Value &request, Json::Value &response) { @@ -359,7 +366,8 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer #include #include +#include #include "DebuggingStateWrapper.h" #include "Exceptions.h" #include "QContractDefinition.h" @@ -82,7 +83,6 @@ ClientModel::ClientModel(): qRegisterMetaType("QCallData"); qRegisterMetaType("RecordLogEntry*"); - connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); m_ethAccounts = make_shared([=](){return m_client.get();}, std::vector()); @@ -111,7 +111,7 @@ QString ClientModel::apiCall(QString const& _message) void ClientModel::mine() { - if (m_running || m_mining) + if (m_mining) BOOST_THROW_EXCEPTION(ExecutionStateException()); m_mining = true; emit miningStarted(); @@ -206,15 +206,18 @@ QVariantList ClientModel::gasCosts() const return res; } -void ClientModel::setupState(QVariantMap _state) +void ClientModel::setupScenario(QVariantMap _scenario) { - QVariantList stateAccounts = _state.value("accounts").toList(); - QVariantList stateContracts = _state.value("contracts").toList(); - QVariantList transactions = _state.value("transactions").toList(); + onStateReset(); + WriteGuard(x_queueTransactions); + m_running = true; - unordered_map accounts; - std::vector userAccounts; + m_currentScenario = _scenario; + QVariantList blocks = _scenario.value("blocks").toList(); + QVariantList stateAccounts = _scenario.value("accounts").toList(); + m_accounts.clear(); + m_accountsSecret.clear(); for (auto const& b: stateAccounts) { QVariantMap account = b.toMap(); @@ -222,7 +225,7 @@ void ClientModel::setupState(QVariantMap _state) if (account.contains("secret")) { KeyPair key(Secret(account.value("secret").toString().toStdString())); - userAccounts.push_back(key); + m_accountsSecret.push_back(key); address = key.address(); } else if (account.contains("address")) @@ -230,29 +233,70 @@ void ClientModel::setupState(QVariantMap _state) if (!address) continue; - accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); + m_accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); } - for (auto const& c: stateContracts) + m_ethAccounts->setAccounts(m_accountsSecret); + + bool trToExecute = false; + for (auto const& b: blocks) { - QVariantMap contract = c.toMap(); - Address address = Address(fromHex(contract.value("address").toString().toStdString())); - Account account(qvariant_cast(contract.value("balance"))->toU256Wei(), Account::ContractConception); - bytes code = fromHex(contract.value("code").toString().toStdString()); - account.setCode(code); - QVariantMap storageMap = contract.value("storage").toMap(); - for(auto s = storageMap.cbegin(); s != storageMap.cend(); ++s) - account.setStorage(fromBigEndian(fromHex(s.key().toStdString())), fromBigEndian(fromHex(s.value().toString().toStdString()))); - accounts[address] = account; + QVariantList transactions = b.toMap().value("transactions").toList(); + m_queueTransactions.push_back(transactions); + trToExecute = transactions.size() > 0; } + m_client->resetState(m_accounts, Secret(m_currentScenario.value("miner").toMap().value("secret").toString().toStdString())); + if (m_queueTransactions.count() > 0 && trToExecute) + { + setupExecutionChain(); + processNextTransactions(); + } + else + m_running = false; +} +void ClientModel::setupExecutionChain() +{ + connect(this, &ClientModel::newBlock, this, &ClientModel::processNextTransactions, Qt::QueuedConnection); + connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); + connect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock, Qt::QueuedConnection); +} + +void ClientModel::stopExecution() +{ + disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextTransactions); + disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); + disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); + m_running = false; +} + +void ClientModel::finalizeBlock() +{ + m_queueTransactions.pop_front();// pop last execution group. The last block is never mined (pending block) + if (m_queueTransactions.size() > 0) + mine(); + else + { + stopExecution(); + emit runComplete(); + } +} + +void ClientModel::processNextTransactions() +{ + WriteGuard(x_queueTransactions); vector transactionSequence; - for (auto const& t: transactions) + for (auto const& t: m_queueTransactions.front()) { QVariantMap transaction = t.toMap(); QString contractId = transaction.value("contractId").toString(); QString functionId = transaction.value("functionId").toString(); - u256 gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); bool gasAuto = transaction.value("gasAuto").toBool(); + u256 gas = 0; + if (transaction.value("gas").data()) + gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); + else + gasAuto = true; + u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); QString sender = transaction.value("sender").toString(); @@ -260,7 +304,8 @@ void ClientModel::setupState(QVariantMap _state) bool isFunctionCall = transaction.value("isFunctionCall").toBool(); if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later contractId = m_codeModel->contracts().keys()[0]; - TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCreation, isFunctionCall); + Secret f = Secret(sender.toStdString()); + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, f, isContractCreation, isFunctionCall); transactionSettings.parameterValues = transaction.value("parameters").toMap(); if (contractId == functionId || functionId == "Constructor") @@ -268,35 +313,27 @@ void ClientModel::setupState(QVariantMap _state) transactionSequence.push_back(transactionSettings); } - m_ethAccounts->setAccounts(userAccounts); - executeSequence(transactionSequence, accounts, Secret(_state.value("miner").toMap().value("secret").toString().toStdString())); + executeSequence(transactionSequence); } -void ClientModel::executeSequence(vector const& _sequence, std::unordered_map const& _accounts, Secret const& _miner) +void ClientModel::executeSequence(vector const& _sequence) { if (m_running) { qWarning() << "Waiting for current execution to complete"; m_runFuture.waitForFinished(); } - m_running = true; - emit runStarted(); - emit runStateChanged(); - - m_client->resetState(_accounts, _miner); //run sequence m_runFuture = QtConcurrent::run([=]() { try { - vector
deployedContracts; - onStateReset(); m_gasCosts.clear(); for (TransactionSettings const& transaction: _sequence) { std::pair ctrInstance = resolvePair(transaction.contractId); - QString address = resolveToken(ctrInstance, deployedContracts); + QString address = resolveToken(ctrInstance); if (!transaction.isFunctionCall) { callAddress(Address(address.toStdString()), bytes(), transaction); @@ -319,12 +356,7 @@ void ClientModel::executeSequence(vector const& _sequence, break; } if (!f) - { emit runFailed("Function '" + transaction.functionId + tr("' not found. Please check transactions or the contract code.")); - m_running = false; - emit runStateChanged(); - return; - } if (!transaction.functionId.isEmpty()) encoder.encode(f); for (QVariableDeclaration const* p: f->parametersList()) @@ -334,7 +366,7 @@ void ClientModel::executeSequence(vector const& _sequence, if (type->type().type == SolidityType::Type::Address && value.toString().startsWith("<")) { std::pair ctrParamInstance = resolvePair(value.toString()); - value = QVariant(resolveToken(ctrParamInstance, deployedContracts)); + value = QVariant(resolveToken(ctrParamInstance)); } encoder.encode(value, type->type()); } @@ -344,8 +376,7 @@ void ClientModel::executeSequence(vector const& _sequence, bytes param = encoder.encodedData(); contractCode.insert(contractCode.end(), param.begin(), param.end()); Address newAddress = deployContract(contractCode, transaction); - deployedContracts.push_back(newAddress); - std::pair contractToken = retrieveToken(transaction.contractId, deployedContracts); + std::pair contractToken = retrieveToken(transaction.contractId); m_contractAddresses[contractToken] = newAddress; m_contractNames[newAddress] = contractToken.first; contractAddressesChanged(); @@ -355,18 +386,12 @@ void ClientModel::executeSequence(vector const& _sequence, { auto contractAddressIter = m_contractAddresses.find(ctrInstance); if (contractAddressIter == m_contractAddresses.end()) - { emit runFailed("Contract '" + transaction.contractId + tr(" not deployed.") + "' " + tr(" Cannot call ") + transaction.functionId); - m_running = false; - emit runStateChanged(); - return; - } callAddress(contractAddressIter->second, encoder.encodedData(), transaction); } m_gasCosts.append(m_client->lastExecution().gasUsed); onNewTransaction(); } - m_running = false; emit runComplete(); } catch(boost::exception const&) @@ -379,37 +404,54 @@ void ClientModel::executeSequence(vector const& _sequence, cerr << boost::current_exception_diagnostic_information(); emit runFailed(e.what()); } - m_running = false; emit runStateChanged(); }); } +void ClientModel::executeTr(QVariantMap _tr) +{ + WriteGuard(x_queueTransactions); + QVariantList trs; + trs.push_back(_tr); + m_queueTransactions.push_back(trs); + if (!m_running) + { + m_running = true; + setupExecutionChain(); + processNextTransactions(); + } +} + std::pair ClientModel::resolvePair(QString const& _contractId) { - std::pair ret = std::make_pair(_contractId, 0); - if (_contractId.startsWith("<") && _contractId.endsWith(">")) - { - QStringList values = ret.first.remove("<").remove(">").split(" - "); - ret = std::make_pair(values[0], values[1].toUInt()); - } - return ret; + std::pair ret = std::make_pair(_contractId, 0); + if (_contractId.startsWith("<") && _contractId.endsWith(">")) + { + QStringList values = ret.first.remove("<").remove(">").split(" - "); + ret = std::make_pair(values[0], values[1].toUInt()); + } + if (_contractId.startsWith("0x")) + ret = std::make_pair(_contractId, -2); + return ret; } -QString ClientModel::resolveToken(std::pair const& _value, vector
const& _contracts) +QString ClientModel::resolveToken(std::pair const& _value) { - if (_contracts.size() > 0) - return QString::fromStdString("0x" + dev::toHex(_contracts.at(_value.second).ref())); + if (_value.second == -2) //-2: first contains a real address + return _value.first; + else if (m_contractAddresses.size() > 0) + return QString::fromStdString("0x" + dev::toHex(m_contractAddresses[_value].ref())); else return _value.first; } -std::pair ClientModel::retrieveToken(QString const& _value, vector
const& _contracts) +std::pair ClientModel::retrieveToken(QString const& _value) { - std::pair ret; - ret.first = _value; - ret.second = _contracts.size() - 1; - return ret; + std::pair ret; + ret.first = _value; + ret.second = m_contractAddresses.size(); + return ret; } void ClientModel::showDebugger() @@ -539,7 +581,9 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t) // filter out locations that match whole function or contract 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)) location = dev::SourceLocation(-1, -1, location.sourceName); @@ -631,7 +675,7 @@ RecordLogEntry* ClientModel::lastBlock() const strGas << blockInfo.gasUsed; stringstream strNumber; strNumber << blockInfo.number; - RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str())); + RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; } @@ -642,6 +686,7 @@ void ClientModel::onStateReset() m_contractNames.clear(); m_stdContractAddresses.clear(); m_stdContractNames.clear(); + m_queueTransactions.clear(); emit stateCleared(); } @@ -690,27 +735,110 @@ void ClientModel::onNewTransaction() Address contractAddress = (bool)tr.address ? tr.address : tr.contractAddress; auto contractAddressIter = m_contractNames.find(contractAddress); + QVariantMap inputParameters; + QVariantList logs; if (contractAddressIter != m_contractNames.end()) { + ContractCallDataEncoder encoder; CompiledContract const& compilerRes = m_codeModel->contract(contractAddressIter->second); const QContractDefinition* def = compilerRes.contract(); contract = def->name(); + if (creation) + function = contract; if (abi) { QFunctionDefinition const* funcDef = def->getFunction(functionHash); if (funcDef) { function = funcDef->name(); - ContractCallDataEncoder encoder; QStringList returnValues = encoder.decode(funcDef->returnParameters(), tr.result.output); returned += "("; returned += returnValues.join(", "); returned += ")"; + bytes data = tr.inputParameters; + data.erase(data.begin(), data.begin() + 4); + QStringList parameters = encoder.decode(funcDef->parametersList(), data); + for (int k = 0; k < parameters.length(); ++k) + inputParameters.insert(funcDef->parametersList().at(k)->name(), parameters.at(k)); } } + + // Fill generated logs and decode parameters + for (auto const& log: tr.logs) + { + QVariantMap l; + l.insert("address", QString::fromStdString(log.address.hex())); + std::ostringstream s; + s << log.data; + l.insert("data", QString::fromStdString(s.str())); + std::ostringstream streamTopic; + streamTopic << log.topics; + l.insert("topic", QString::fromStdString(streamTopic.str())); + auto const& sign = log.topics.front(); // first hash supposed to be the event signature. To check + auto dataIterator = log.data.begin(); + int topicDataIndex = 1; + for (auto const& event: def->eventsList()) + { + if (sign == event->fullHash()) + { + QVariantList paramsList; + l.insert("name", event->name()); + for (auto const& e: event->parametersList()) + { + bytes data; + QString param; + if (!e->isIndexed()) + { + data = bytes(dataIterator, dataIterator + 32); + dataIterator = dataIterator + 32; + } + else + { + data = log.topics.at(topicDataIndex).asBytes(); + topicDataIndex++; + } + param = encoder.decode(e, data); + QVariantMap p; + p.insert("indexed", e->isIndexed()); + p.insert("value", param); + p.insert("name", e->name()); + paramsList.push_back(p); + } + l.insert("param", paramsList); + break; + } + } + logs.push_back(l); + } + } + + QString sender; + for (auto const& secret: m_accountsSecret) + { + if (secret.address() == tr.sender) + { + sender = QString::fromStdString(dev::toHex(secret.secret().ref())); + break; + } } + QString label; + if (function != QObject::tr("")) + label = contract + "." + function + "()"; + else + label = contract; + + if (!creation) + for (auto const& ctr: m_contractAddresses) + { + if (ctr.second == tr.address) + { + contract = "<" + ctr.first.first + " - " + QString::number(ctr.first.second) + ">"; + break; + } + } - RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, gasUsed); + RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, + gasUsed, sender, label, inputParameters, logs); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); emit newRecord(log); } diff --git a/mix/ClientModel.h b/mix/ClientModel.h index e1648b78d..32348b603 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -30,12 +30,13 @@ #include #include #include +#include #include "MachineStates.h" namespace dev { -namespace eth { class Account; class FixedAccountHolder; } +namespace eth { class FixedAccountHolder; } namespace mix { @@ -108,6 +109,14 @@ class RecordLogEntry: public QObject Q_PROPERTY(RecordType type MEMBER m_type CONSTANT) /// Gas used Q_PROPERTY(QString gasUsed MEMBER m_gasUsed CONSTANT) + /// Sender + Q_PROPERTY(QString sender MEMBER m_sender CONSTANT) + /// label + Q_PROPERTY(QString label MEMBER m_label CONSTANT) + /// input parameters + Q_PROPERTY(QVariantMap parameters MEMBER m_inputParameters CONSTANT) + /// logs + Q_PROPERTY(QVariantList logs MEMBER m_logs CONSTANT) public: enum RecordType @@ -118,8 +127,10 @@ public: RecordLogEntry(): m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {} - RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed): - m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed) {} + RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed, + QString _sender, QString _label, QVariantMap _inputParameters, QVariantList _logs): + m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed), + m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters), m_logs(_logs) {} private: unsigned m_recordIndex; @@ -132,6 +143,10 @@ private: bool m_call; RecordType m_type; QString m_gasUsed; + QString m_sender; + QString m_label; + QVariantMap m_inputParameters; + QVariantList m_logs; }; /** @@ -170,9 +185,11 @@ public: Q_INVOKABLE QString toHex(QString const& _int); public slots: - /// Setup state, run transaction sequence, show debugger for the last transaction + /// Setup scenario, run transaction sequence, show debugger for the last transaction /// @param _state JS object with state configuration - void setupState(QVariantMap _state); + void setupScenario(QVariantMap _scenario); + /// Execute the given @param _tr on the current state + void executeTr(QVariantMap _tr); /// Show the debugger for a specified record Q_INVOKABLE void debugRecord(unsigned _index); /// Show the debugger for an empty record @@ -224,17 +241,21 @@ private: RecordLogEntry* lastBlock() const; QVariantMap contractAddresses() const; QVariantList gasCosts() const; - void executeSequence(std::vector const& _sequence, std::unordered_map const& _accounts, Secret const& _miner); + void executeSequence(std::vector const& _sequence); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); void callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void onNewTransaction(); void onStateReset(); void showDebuggerForTransaction(ExecutionResult const& _t); QVariant formatValue(SolidityType const& _type, dev::u256 const& _value); - QString resolveToken(std::pair const& _value, std::vector
const& _contracts); - std::pair retrieveToken(QString const& _value, std::vector
const& _contracts); + QString resolveToken(std::pair const& _value); + std::pair retrieveToken(QString const& _value); std::pair resolvePair(QString const& _contractId); QVariant formatStorageValue(SolidityType const& _type, std::unordered_map const& _storage, unsigned _offset, dev::u256 const& _slot); + void processNextTransactions(); + void finalizeBlock(); + void stopExecution(); + void setupExecutionChain(); std::atomic m_running; std::atomic m_mining; @@ -243,12 +264,17 @@ private: std::unique_ptr m_rpcConnector; std::unique_ptr m_web3Server; std::shared_ptr m_ethAccounts; + std::unordered_map m_accounts; + std::vector m_accountsSecret; QList m_gasCosts; std::map, Address> m_contractAddresses; std::map m_contractNames; std::map m_stdContractAddresses; std::map m_stdContractNames; CodeModel* m_codeModel = nullptr; + QList m_queueTransactions; + QVariantMap m_currentScenario; + mutable boost::shared_mutex x_queueTransactions; }; } diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 434cf1e7d..1ca5d9160 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -67,7 +67,7 @@ private: return LocationPair(_node.getLocation().start, _node.getLocation().end); } - virtual bool visit(FunctionDefinition const&) + virtual bool visit(FunctionDefinition const&) override { m_functionScope = true; return true; diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 07ab8dd73..d805822aa 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -29,6 +29,7 @@ #include "QVariableDefinition.h" #include "QFunctionDefinition.h" #include "ContractCallDataEncoder.h" +using namespace std; using namespace dev; using namespace dev::solidity; using namespace dev::mix; @@ -227,6 +228,12 @@ QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found")); } +QString ContractCallDataEncoder::decode(QVariableDeclaration* const& _param, bytes _value) +{ + SolidityType const& type = _param->type()->type(); + return decode(type, _value).toString(); +} + QStringList ContractCallDataEncoder::decode(QList const& _returnParameters, bytes _value) { bytesConstRef value(&_value); diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 2707845ae..8fcc65c0a 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -48,6 +48,8 @@ public: void encode(QVariant const& _data, SolidityType const& _type); /// Decode variable in order to be sent to QML view. QStringList decode(QList const& _dec, bytes _value); + /// Decode @param _parameter + QString decode(QVariableDeclaration* const& _param, bytes _value); /// Decode single variable QVariant decode(SolidityType const& _type, bytes const& _value); /// Get all encoded data encoded by encode function. diff --git a/mix/MachineStates.h b/mix/MachineStates.h index 2a88d83bf..9a9acecf4 100644 --- a/mix/MachineStates.h +++ b/mix/MachineStates.h @@ -37,57 +37,59 @@ namespace dev namespace mix { - /** +/** * @brief Store information about a machine state. */ - struct MachineState - { - uint64_t steps; - dev::u256 curPC; - dev::eth::Instruction inst; - dev::bigint newMemSize; - dev::u256 gas; - dev::u256s stack; - dev::bytes memory; - dev::bigint gasCost; - std::unordered_map storage; - std::vector levels; - unsigned codeIndex; - unsigned dataIndex; - }; +struct MachineState +{ + uint64_t steps; + dev::u256 curPC; + dev::eth::Instruction inst; + dev::bigint newMemSize; + dev::u256 gas; + dev::u256s stack; + dev::bytes memory; + dev::bigint gasCost; + std::unordered_map storage; + std::vector levels; + unsigned codeIndex; + unsigned dataIndex; +}; - /** +/** * @brief Executed conract code info */ - struct MachineCode - { - dev::Address address; - bytes code; - }; +struct MachineCode +{ + dev::Address address; + bytes code; +}; - /** +/** * @brief Store information about a machine states. */ - struct ExecutionResult - { - ExecutionResult(): transactionIndex(std::numeric_limits::max()) {} +struct ExecutionResult +{ + ExecutionResult(): transactionIndex(std::numeric_limits::max()) {} - std::vector machineStates; - std::vector transactionData; - std::vector executionCode; - dev::eth::ExecutionResult result; - dev::Address address; - dev::Address sender; - dev::Address contractAddress; - dev::u256 value; - dev::u256 gasUsed; - unsigned transactionIndex; - unsigned executonIndex = 0; + std::vector machineStates; + std::vector transactionData; + std::vector executionCode; + dev::eth::ExecutionResult result; + dev::Address address; + dev::Address sender; + dev::Address contractAddress; + dev::u256 value; + dev::u256 gasUsed; + unsigned transactionIndex; + unsigned executonIndex = 0; + bytes inputParameters; + eth::LocalisedLogEntries logs; - bool isCall() const { return transactionIndex == std::numeric_limits::max(); } - bool isConstructor() const { return !isCall() && !address; } - }; + bool isCall() const { return transactionIndex == std::numeric_limits::max(); } + bool isConstructor() const { return !isCall() && !address; } +}; - using ExecutionResults = std::vector; +using ExecutionResults = std::vector; } } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index aa469d8a0..df3795c7e 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -22,6 +22,7 @@ #include "MixClient.h" #include +#include #include #include #include @@ -58,9 +59,9 @@ bytes MixBlockChain::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)); + << 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(); @@ -78,10 +79,9 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { + WriteGuard l(x_state); Guard fl(x_filtersWatches); - m_filters.clear(); - m_watches.clear(); m_stateDB = OverlayDB(); SecureTrieDB accountState(&m_stateDB); @@ -130,7 +130,9 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c State execState = _state; execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation + eth::ExecutionResult er; Executive execution(execState, lastHashes, 0); + execution.setResultRecipient(er); execution.initialize(t); execution.execute(); std::vector machineStates; @@ -181,51 +183,53 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c levels.resize(ext.depth); machineStates.push_back(MachineState{ - steps, - vm.curPC(), - inst, - newMemSize, - static_cast(gas), - vm.stack(), - vm.memory(), - gasCost, - ext.state().storage(ext.myAddress), - std::move(levels), - codeIndex, - dataIndex - }); + steps, + vm.curPC(), + inst, + newMemSize, + static_cast(gas), + vm.stack(), + vm.memory(), + gasCost, + ext.state().storage(ext.myAddress), + std::move(levels), + codeIndex, + dataIndex + }); }; execution.go(onOp); execution.finalize(); - dev::eth::ExecutionResult er = execution.executionResult(); switch (er.excepted) { - case TransactionException::None: - break; - case TransactionException::NotEnoughCash: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment")); - case TransactionException::OutOfGasBase: - case TransactionException::OutOfGas: - BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); - case TransactionException::BlockGasLimitReached: - BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached")); - case TransactionException::OutOfStack: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack")); - case TransactionException::StackUnderflow: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow")); + case TransactionException::None: + break; + case TransactionException::NotEnoughCash: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment")); + case TransactionException::OutOfGasIntrinsic: + case TransactionException::OutOfGasBase: + case TransactionException::OutOfGas: + BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); + case TransactionException::BlockGasLimitReached: + BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached")); + case TransactionException::OutOfStack: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack")); + case TransactionException::StackUnderflow: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow")); //these should not happen in mix - case TransactionException::Unknown: - case TransactionException::BadInstruction: - case TransactionException::BadJumpDestination: - case TransactionException::InvalidSignature: - case TransactionException::InvalidNonce: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); - }; + case TransactionException::Unknown: + case TransactionException::BadInstruction: + case TransactionException::BadJumpDestination: + case TransactionException::InvalidSignature: + case TransactionException::InvalidNonce: + case TransactionException::BadRLP: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); + } ExecutionResult d; - d.result = execution.executionResult(); + d.inputParameters = t.data(); + d.result = er; d.machineStates = machineStates; d.executionCode = std::move(codes); d.transactionData = std::move(data); @@ -243,28 +247,19 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c if (!_call) { t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; - er =_state.execute(lastHashes, t); + er = _state.execute(lastHashes, t); if (t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; - // collect watches - h256Set changed; - Guard l(x_filtersWatches); - for (std::pair& i: m_filters) - if ((unsigned)i.second.filter.latest() > bc().number()) - { - // acceptable number. - auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); - if (m.size()) - { - // filter catches them - for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1)); - changed.insert(i.first); - } - } - changed.insert(dev::eth::PendingChangedFilter); - noteChanged(changed); + LocalisedLogEntries logs; + TransactionReceipt const& tr = _state.receipt(_state.pending().size() - 1); + + auto trHash = _state.pending().at(_state.pending().size() - 1).sha3(); + LogEntries le = tr.log(); + if (le.size()) + for (unsigned j = 0; j < le.size(); ++j) + logs.insert(logs.begin(), LocalisedLogEntry(le[j], bc().number() + 1, trHash)); + d.logs = logs; } WriteGuard l(x_executions); m_executions.emplace_back(std::move(d)); @@ -279,7 +274,6 @@ void MixClient::mine() m_state.sync(bc()); m_startState = m_state; h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; - noteChanged(changed); } ExecutionResult MixClient::lastExecution() const @@ -366,20 +360,6 @@ dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, b return lastExecution().result; } -void MixClient::noteChanged(h256Set const& _filters) -{ - for (auto& i: m_watches) - if (_filters.count(i.second.id)) - { - if (m_filters.count(i.second.id)) - i.second.changes += m_filters.at(i.second.id).changes; - else - i.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); - } - for (auto& i: m_filters) - i.second.changes.clear(); -} - eth::BlockInfo MixClient::blockInfo() const { ReadGuard l(x_state); diff --git a/mix/MixClient.h b/mix/MixClient.h index 4c5b51a09..afb9f5430 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include "MachineStates.h" @@ -80,7 +81,7 @@ protected: /// ClientBase methods using ClientBase::asOf; 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::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; } @@ -88,7 +89,6 @@ protected: private: void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto, dev::Secret const& _secret = dev::Secret()); - void noteChanged(h256Set const& _filters); dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas, dev::Secret const& _secret = dev::Secret()); eth::State m_state; diff --git a/mix/QContractDefinition.cpp b/mix/QContractDefinition.cpp index 51b37e399..f4022d1ff 100644 --- a/mix/QContractDefinition.cpp +++ b/mix/QContractDefinition.cpp @@ -39,8 +39,23 @@ QContractDefinition::QContractDefinition(QObject* _parent, dev::solidity::Contra else m_constructor = new QFunctionDefinition(parent); + std::vector found; + for (auto const& f: _contract->getDefinedFunctions()) + { + m_functions.append(new QFunctionDefinition(parent, f)); + found.push_back(f->getName()); + } + for (auto const& it: _contract->getInterfaceFunctions()) - m_functions.append(new QFunctionDefinition(parent, it.second)); + { + if (std::find(found.begin(), found.end(), it.second->getDeclaration().getName()) == found.end()) + m_functions.append(new QFunctionDefinition(parent, it.second)); + } + + + for (auto const& it: _contract->getEvents()) + m_events.append(new QFunctionDefinition(parent, it)); + } QFunctionDefinition const* QContractDefinition::getFunction(dev::FixedHash<4> _hash) const diff --git a/mix/QContractDefinition.h b/mix/QContractDefinition.h index ff0df1f15..f68133ab7 100644 --- a/mix/QContractDefinition.h +++ b/mix/QContractDefinition.h @@ -37,6 +37,7 @@ class QContractDefinition: public QBasicNodeDefinition Q_OBJECT Q_PROPERTY(QQmlListProperty functions READ functions CONSTANT) Q_PROPERTY(dev::mix::QFunctionDefinition* constructor READ constructor CONSTANT) + Q_PROPERTY(QQmlListProperty events READ events CONSTANT) public: QContractDefinition(QObject* _parent, solidity::ContractDefinition const* _contract); @@ -44,12 +45,19 @@ public: QQmlListProperty functions() const { return QQmlListProperty(const_cast(this), const_cast(this)->m_functions); } /// Get the constructor of the contract. QFunctionDefinition* constructor() const { return m_constructor; } + /// Get all the functions of the contract. QList const& functionsList() const { return m_functions; } /// Find function by hash, returns nullptr if not found QFunctionDefinition const* getFunction(dev::FixedHash<4> _hash) const; + /// Get events + QQmlListProperty events() const { return QQmlListProperty(const_cast(this), const_cast(this)->m_events); } + /// Get events + QList const& eventsList() const { return m_events; } + private: QList m_functions; QFunctionDefinition* m_constructor; + QList m_events; }; } diff --git a/mix/QFunctionDefinition.cpp b/mix/QFunctionDefinition.cpp index e6764d712..52d8ad30c 100644 --- a/mix/QFunctionDefinition.cpp +++ b/mix/QFunctionDefinition.cpp @@ -28,15 +28,41 @@ using namespace dev::solidity; using namespace dev::mix; -QFunctionDefinition::QFunctionDefinition(QObject* _parent, dev::solidity::FunctionTypePointer const& _f): QBasicNodeDefinition(_parent, &_f->getDeclaration()), m_hash(dev::sha3(_f->externalSignature())) +QFunctionDefinition::QFunctionDefinition(QObject* _parent, dev::solidity::FunctionTypePointer const& _f): QBasicNodeDefinition(_parent, &_f->getDeclaration()), m_hash(dev::sha3(_f->externalSignature())), + m_fullHash(dev::sha3(_f->externalSignature())) +{ + init(_f); +} + +QFunctionDefinition::QFunctionDefinition(QObject* _parent, ASTPointer const& _f): QBasicNodeDefinition(_parent, _f.get()), m_hash(dev::sha3(_f->externalSignature())), + m_fullHash(dev::sha3(_f->externalSignature())) +{ + + for (unsigned i = 0; i < _f->getParameters().size(); ++i) + m_parameters.append(new QVariableDeclaration(parent(), _f->getParameters().at(i))); + + for (unsigned i = 0; i < _f->getReturnParameters().size(); ++i) + m_returnParameters.append(new QVariableDeclaration(parent(), _f->getReturnParameters().at(i))); +} + +QFunctionDefinition::QFunctionDefinition(QObject* _parent, ASTPointer const& _e): QBasicNodeDefinition(_parent, _e.get()) +{ + for (unsigned i = 0; i < _e->getParameters().size(); ++i) + m_parameters.append(new QVariableDeclaration(parent(), _e->getParameters().at(i))); + FunctionTypePointer _f = std::make_shared(*_e); + m_hash = (FixedHash<4>)dev::sha3(_f->externalSignature(_e->getName())); + m_fullHash = dev::sha3(_f->externalSignature(_e->getName())); +} + +void QFunctionDefinition::init(dev::solidity::FunctionTypePointer _f) { auto paramNames = _f->getParameterNames(); auto paramTypes = _f->getParameterTypes(); auto returnNames = _f->getReturnParameterNames(); auto returnTypes = _f->getReturnParameterTypes(); for (unsigned i = 0; i < paramNames.size(); ++i) - m_parameters.append(new QVariableDeclaration(_parent, paramNames[i], paramTypes[i].get())); + m_parameters.append(new QVariableDeclaration(parent(), paramNames[i], paramTypes[i].get())); for (unsigned i = 0; i < returnNames.size(); ++i) - m_returnParameters.append(new QVariableDeclaration(_parent, returnNames[i], returnTypes[i].get())); + m_returnParameters.append(new QVariableDeclaration(parent(), returnNames[i], returnTypes[i].get())); } diff --git a/mix/QFunctionDefinition.h b/mix/QFunctionDefinition.h index 18f2d911b..a9c45ffcd 100644 --- a/mix/QFunctionDefinition.h +++ b/mix/QFunctionDefinition.h @@ -41,6 +41,10 @@ public: QFunctionDefinition(){} QFunctionDefinition(QObject* _parent): QBasicNodeDefinition(_parent) {} QFunctionDefinition(QObject* _parent, solidity::FunctionTypePointer const& _f); + QFunctionDefinition(QObject* _parent, solidity::ASTPointer const& _f); + QFunctionDefinition(QObject* _parent, solidity::ASTPointer const& _f); + /// Init members + void init(dev::solidity::FunctionTypePointer _f); /// Get all input parameters of this function. QList const& parametersList() const { return m_parameters; } /// Get all input parameters of this function as QML property. @@ -49,10 +53,13 @@ public: QList returnParameters() const { return m_returnParameters; } /// Get the hash of this function declaration on the contract ABI. FixedHash<4> hash() const { return m_hash; } + /// Get the full hash of this function declaration on the contract ABI. + FixedHash<32> fullHash() const { return m_fullHash; } private: int m_index; FixedHash<4> m_hash; + FixedHash<32> m_fullHash; QList m_parameters; QList m_returnParameters; void initQParameters(); diff --git a/mix/QVariableDeclaration.cpp b/mix/QVariableDeclaration.cpp index 3bbb0d523..4299e34ee 100644 --- a/mix/QVariableDeclaration.cpp +++ b/mix/QVariableDeclaration.cpp @@ -24,27 +24,32 @@ #include #include "CodeModel.h" +using namespace solidity; + namespace dev { namespace mix { -QVariableDeclaration::QVariableDeclaration(QObject* _parent, solidity::VariableDeclaration const* _v): - QBasicNodeDefinition(_parent, _v), +QVariableDeclaration::QVariableDeclaration(QObject* _parent, ASTPointer const _v): + QBasicNodeDefinition(_parent, _v.get()), m_type(new QSolidityType(this, CodeModel::nodeType(_v->getType().get()))) { + m_isIndexed = _v->isIndexed(); } -QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type): +QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type, bool _isIndexed): QBasicNodeDefinition(_parent, _name), m_type(new QSolidityType(_parent, _type)) { + m_isIndexed = _isIndexed; } -QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type): +QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type, bool _isIndexed): QBasicNodeDefinition(_parent, _name), m_type(new QSolidityType(this, CodeModel::nodeType(_type))) { + m_isIndexed = _isIndexed; } QSolidityType::QSolidityType(QObject* _parent, SolidityType const& _type): diff --git a/mix/QVariableDeclaration.h b/mix/QVariableDeclaration.h index 4309550b2..85c719987 100644 --- a/mix/QVariableDeclaration.h +++ b/mix/QVariableDeclaration.h @@ -21,6 +21,7 @@ #include #include +#include #include "QBasicNodeDefinition.h" #include "SolidityType.h" @@ -82,14 +83,16 @@ class QVariableDeclaration: public QBasicNodeDefinition public: QVariableDeclaration() {} - QVariableDeclaration(QObject* _parent, solidity::VariableDeclaration const* _v); - QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type); - QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type); + QVariableDeclaration(QObject* _parent, solidity::ASTPointer const _v); + QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type, bool _isIndexed = false); + QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type, bool _isIndexed = false); QSolidityType* type() const { return m_type; } void setType(QSolidityType* _type) { m_type = _type; } + bool isIndexed() { return m_isIndexed; } private: QSolidityType* m_type; + bool m_isIndexed; }; diff --git a/mix/qml.qrc b/mix/qml.qrc index 784404270..16bb01b83 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -64,5 +64,10 @@ qml/js/ansi2html.js qml/js/NetworkDeployment.js qml/js/InputValidator.js + qml/Block.qml + qml/BlockChain.qml + qml/ScenarioExecution.qml + qml/ScenarioLoader.qml + qml/ScenarioButton.qml diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index d041f421e..61a2e09b1 100644 --- a/mix/qml/Application.qml +++ b/mix/qml/Application.qml @@ -128,10 +128,8 @@ ApplicationWindow { MenuSeparator {} MenuItem { action: toggleProjectNavigatorAction } MenuItem { action: showHideRightPanelAction } - MenuItem { action: toggleTransactionLogAction } MenuItem { action: toggleWebPreviewAction } MenuItem { action: toggleWebPreviewOrientationAction } - //MenuItem { action: toggleCallsInLog } } } @@ -211,8 +209,8 @@ ApplicationWindow { id: toggleAssemblyDebuggingAction text: qsTr("Show VM Code") shortcut: "Ctrl+Alt+V" - onTriggered: mainContent.rightPane.assemblyMode = !mainContent.rightPane.assemblyMode; - checked: mainContent.rightPane.assemblyMode; + onTriggered: mainContent.debuggerPanel.assemblyMode = !mainContent.debuggerPanel.assemblyMode; + checked: mainContent.debuggerPanel.assemblyMode; enabled: true } @@ -225,15 +223,6 @@ ApplicationWindow { onTriggered: mainContent.toggleWebPreview(); } - Action { - id: toggleTransactionLogAction - text: qsTr("Show States and Transactions") - shortcut: "Alt+1" - checkable: true - checked: mainContent.rightPane.transactionLog.visible - onTriggered: mainContent.rightPane.transactionLog.visible = !mainContent.rightPane.transactionLog.visible - } - Action { id: toggleProjectNavigatorAction text: qsTr("Show Project Navigator") diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml new file mode 100644 index 000000000..6fb274ccd --- /dev/null +++ b/mix/qml/Block.qml @@ -0,0 +1,346 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.1 +import Qt.labs.settings 1.0 +import "js/Debugger.js" as Debugger +import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "." + +ColumnLayout +{ + id: root + property variant transactions + property string status + property int number + property int blockWidth: Layout.preferredWidth - statusWidth - horizontalMargin + property int horizontalMargin: 10 + property int trHeight: 30 + spacing: 0 + property int openedTr: 0 + property int blockIndex + property variant scenario + + function calculateHeight() + { + if (transactions) + { + if (index >= 0) + return 30 + 30 * transactions.count + openedTr + else + return 30 + } + else + return 30 + } + + onOpenedTrChanged: + { + Layout.preferredHeight = calculateHeight() + height = calculateHeight() + } + + + + RowLayout + { + Layout.preferredHeight: trHeight + Layout.preferredWidth: blockWidth + id: rowHeader + Rectangle + { + color: "#DEDCDC" + Layout.preferredWidth: blockWidth + Layout.preferredHeight: trHeight + radius: 4 + anchors.left: parent.left + anchors.leftMargin: statusWidth + 5 + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + text: + { + if (status === "mined") + return qsTr("BLOCK") + " " + number + else + return qsTr("BLOCK") + " pending" + } + } + } + } + + Repeater // List of transactions + { + id: transactionRepeater + model: transactions + + RowLayout + { + id: rowTransaction + Layout.preferredHeight: trHeight + function displayContent() + { + logsText.text = "" + if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) + { + for (var k = 0; k < transactions.get(index).logs.count; k++) + { + var log = transactions.get(index).logs.get(k) + if (log.name) + logsText.text += log.name + ":\n" + else + logsText.text += "log:\n" + + if (log.param) + for (var i = 0; i < log.param.count; i++) + { + var p = log.param.get(i) + logsText.text += p.name + " = " + p.value + " - indexed:" + p.indexed + "\n" + } + else{ + logsText.text += "From : " + log.address + "\n" + } + } + logsText.text += "\n\n" + } + rowDetailedContent.visible = !rowDetailedContent.visible + } + + Rectangle + { + id: trSaveStatus + Layout.preferredWidth: statusWidth + Layout.preferredHeight: trHeight + color: "transparent" + anchors.top: parent.top + property bool saveStatus + + Image { + id: saveStatusImage + source: "qrc:/qml/img/recyclediscard@2x.png" + width: statusWidth + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + + Component.onCompleted: + { + if (index >= 0) + saveStatus = transactions.get(index).saveStatus + } + + onSaveStatusChanged: + { + if (saveStatus) + saveStatusImage.source = "qrc:/qml/img/recyclekeep@2x.png" + else + saveStatusImage.source = "qrc:/qml/img/recyclediscard@2x.png" + + if (index >= 0) + transactions.get(index).saveStatus = saveStatus + } + + MouseArea { + id: statusMouseArea + anchors.fill: parent + onClicked: + { + parent.saveStatus = !parent.saveStatus + } + } + } + + Rectangle + { + Layout.preferredWidth: blockWidth + Layout.preferredHeight: parent.height + color: "#DEDCDC" + id: rowContentTr + anchors.top: parent.top + ColumnLayout + { + anchors.top: parent.top + spacing: 10 + RowLayout + { + anchors.top: parent.top + anchors.verticalCenter: parent.verticalCenter + spacing: cellSpacing + Text + { + id: hash + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + Layout.preferredWidth: fromWidth + elide: Text.ElideRight + maximumLineCount: 1 + text: { + if (index >= 0) + return transactions.get(index).sender + else + return "" + } + } + + Text + { + id: func + text: { + if (index >= 0) + parent.userFrienldyToken(transactions.get(index).label) + else + return "" + } + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: toWidth + } + + function userFrienldyToken(value) + { + if (value && value.indexOf("<") === 0) + { + if (value.split("> ")[1] === " - ") + return value.split(" - ")[0].replace("<", "") + else + return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()"; + } + else + return value + } + + Text + { + id: returnValue + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: valueWidth + text: { + if (index >= 0 && transactions.get(index).returned) + return transactions.get(index).returned + else + return "" + } + } + + Rectangle + { + Layout.preferredWidth: logsWidth + Layout.preferredHeight: trHeight - 10 + width: logsWidth + color: "transparent" + Text + { + id: logs + anchors.left: parent.left + anchors.leftMargin: 10 + text: { + if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) + return transactions.get(index).logs.count + else + return "" + } + } + MouseArea { + anchors.fill: parent + onClicked: { + rowTransaction.displayContent(); + } + } + } + + Rectangle + { + Layout.preferredWidth: debugActionWidth + Layout.preferredHeight: trHeight - 10 + color: "transparent" + + Image { + source: "qrc:/qml/img/edit.png" + width: 18 + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + MouseArea + { + anchors.fill: parent + onClicked: + { + transactionDialog.stateAccounts = scenario.accounts + transactionDialog.execute = false + transactionDialog.open(index, blockIndex, transactions.get(index)) + } + } + } + + Rectangle + { + Layout.preferredWidth: debugActionWidth + Layout.preferredHeight: trHeight - 10 + color: "transparent" + + Image { + id: debugImg + source: "qrc:/qml/img/rightarrow@2x.png" + width: statusWidth + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + visible: transactions.get(index).recordIndex !== undefined + } + MouseArea + { + anchors.fill: parent + onClicked: + { + if (transactions.get(index).recordIndex !== undefined) + { + debugTrRequested = [ blockIndex, index ] + clientModel.debugRecord(transactions.get(index).recordIndex); + } + } + } + } + } + + RowLayout + { + id: rowDetailedContent + visible: false + Layout.preferredHeight:{ + if (index >= 0 && transactions.get(index).logs) + return 100 * transactions.get(index).logs.count + else + return 100 + } + onVisibleChanged: + { + var lognb = transactions.get(index).logs.count + if (visible) + { + rowContentTr.Layout.preferredHeight = trHeight + 100 * lognb + openedTr += 100 * lognb + } + else + { + rowContentTr.Layout.preferredHeight = trHeight + openedTr -= 100 * lognb + } + } + + Text { + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + id: logsText + } + } + } + } + } + } +} + diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml new file mode 100644 index 000000000..d3fad6fda --- /dev/null +++ b/mix/qml/BlockChain.qml @@ -0,0 +1,480 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.1 +import Qt.labs.settings 1.0 +import org.ethereum.qml.QEther 1.0 +import "js/Debugger.js" as Debugger +import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "js/TransactionHelper.js" as TransactionHelper +import "js/QEtherHelper.js" as QEtherHelper +import "." + +ColumnLayout { + id: blockChainPanel + property variant model + spacing: 0 + property int previousWidth + property variant debugTrRequested: [] + signal chainChanged + + onChainChanged: { + reBuildNeeded.start() + } + + onWidthChanged: + { + + if (width <= 630 || previousWidth <= 630) + { + fromWidth = 100 + toWidth = 100 + valueWidth = 200 + } + else + { + var diff = (width - previousWidth) / 3; + fromWidth = fromWidth + diff < 100 ? 100 : fromWidth + diff + toWidth = toWidth + diff < 100 ? 100 : toWidth + diff + valueWidth = valueWidth + diff < 200 ? 200 : valueWidth + diff + } + previousWidth = width + } + + function load(scenario) + { + if (!scenario) + return; + if (model) + chainChanged() + model = scenario + blockModel.clear() + for (var b in model.blocks) + blockModel.append(model.blocks[b]) + previousWidth = width + } + + property int statusWidth: 30 + property int fromWidth: 100 + property int toWidth: 100 + property int valueWidth: 200 + property int logsWidth: 50 + property int debugActionWidth: 50 + property int horizontalMargin: 10 + property int cellSpacing: 10 + + RowLayout + { + id: header + spacing: 0 + Layout.preferredHeight: 25 + Image { + id: debugImage + source: "qrc:/qml/img/recycleicon@2x.png" + Layout.preferredWidth: statusWidth + Layout.preferredHeight: 25 + fillMode: Image.PreserveAspectFit + } + Rectangle + { + Layout.preferredWidth: fromWidth + cellSpacing + Label + { + anchors.verticalCenter: parent.verticalCenter + text: "From" + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + 5 + } + } + Label + { + text: "To" + Layout.preferredWidth: toWidth + cellSpacing + } + Label + { + text: "Value" + Layout.preferredWidth: valueWidth + cellSpacing + } + Label + { + text: "Logs" + Layout.preferredWidth: logsWidth + cellSpacing + } + Label + { + text: "" + Layout.preferredWidth: debugActionWidth + } + } + + Rectangle + { + Layout.preferredHeight: 500 + Layout.preferredWidth: parent.width + border.color: "#cccccc" + border.width: 2 + color: "white" + ScrollView + { + id: blockChainScrollView + anchors.fill: parent + anchors.topMargin: 10 + ColumnLayout + { + id: blockChainLayout + width: parent.width + spacing: 10 + Repeater // List of blocks + { + id: blockChainRepeater + model: blockModel + Block + { + scenario: blockChainPanel.model + Layout.preferredWidth: blockChainScrollView.width + Layout.preferredHeight: + { + return calculateHeight() + } + blockIndex: index + transactions: + { + if (index >= 0) + return blockModel.get(index).transactions + else + return [] + } + + status: + { + if (index >= 0) + return blockModel.get(index).status + else + return "" + } + + number: + { + if (index >= 0) + return blockModel.get(index).number + else + return 0 + } + } + } + } + } + } + + ListModel + { + id: blockModel + + function appendBlock(block) + { + blockModel.append(block); + } + + function appendTransaction(tr) + { + blockModel.get(blockModel.count - 1).transactions.append(tr) + } + + function removeTransaction(blockIndex, trIndex) + { + blockModel.get(blockIndex).transactions.remove(trIndex) + } + + function removeLastBlock() + { + blockModel.remove(blockModel.count - 1) + } + + function removeBlock(index) + { + blockModel.remove(index) + } + + function getTransaction(block, tr) + { + return blockModel.get(block).transactions.get(tr) + } + + function setTransaction(blockIndex, trIndex, tr) + { + blockModel.get(blockIndex).transactions.set(trIndex, tr) + } + + function setTransactionProperty(blockIndex, trIndex, propertyName, value) + { + blockModel.get(blockIndex).transactions.set(trIndex, { propertyName: value }) + } + } + + Rectangle + { + Layout.preferredWidth: parent.width + RowLayout + { + width: 4 * 100 + anchors.top: parent.top + anchors.topMargin: 10 + spacing: 0 + ScenarioButton { + id: rebuild + text: qsTr("Rebuild") + onClicked: + { + if (ensureNotFuturetime.running) + return; + reBuildNeeded.stop() + var retBlocks = []; + var bAdded = 0; + for (var j = 0; j < model.blocks.length; j++) + { + var b = model.blocks[j]; + var block = { + hash: b.hash, + number: b.number, + transactions: [], + status: b.status + } + for (var k = 0; k < model.blocks[j].transactions.length; k++) + { + if (blockModel.get(j).transactions.get(k).saveStatus) + { + var tr = model.blocks[j].transactions[k] + tr.saveStatus = true + block.transactions.push(tr); + } + + } + if (block.transactions.length > 0) + { + bAdded++ + block.number = bAdded + block.status = "mined" + retBlocks.push(block) + } + + } + if (retBlocks.length === 0) + retBlocks.push(projectModel.stateListModel.createEmptyBlock()) + else + { + var last = retBlocks[retBlocks.length - 1] + last.number = -1 + last.status = "pending" + } + + model.blocks = retBlocks + blockModel.clear() + for (var j = 0; j < model.blocks.length; j++) + blockModel.append(model.blocks[j]) + + ensureNotFuturetime.start() + clientModel.setupScenario(model); + } + + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycleicon@2x.png" + Timer + { + id: reBuildNeeded + repeat: true + interval: 1000 + running: false + onTriggered: { + if (!parent.fillColor || parent.fillColor === "white") + parent.fillColor = "orange" + else + parent.fillColor = "white" + } + onRunningChanged: { + if (!running) + parent.fillColor = "white" + } + } + } + + ScenarioButton { + id: addTransaction + text: qsTr("Add Transaction") + onClicked: + { + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + { + var newblock = projectModel.stateListModel.createEmptyBlock() + blockModel.appendBlock(newblock) + model.blocks.push(newblock); + } + + var item = TransactionHelper.defaultTransaction() + transactionDialog.stateAccounts = model.accounts + transactionDialog.execute = true + transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/sendtransactionicon@2x.png" + } + + Timer + { + id: ensureNotFuturetime + interval: 1000 + repeat: false + running: false + } + + ScenarioButton { + id: addBlockBtn + text: qsTr("Add Block") + onClicked: + { + if (ensureNotFuturetime.running) + return + if (clientModel.mining || clientModel.running) + return + if (model.blocks.length > 0) + { + var lastBlock = model.blocks[model.blocks.length - 1] + if (lastBlock.status === "pending") + { + ensureNotFuturetime.start() + clientModel.mine() + } + else + addNewBlock() + } + else + addNewBlock() + + } + + function addNewBlock() + { + var block = projectModel.stateListModel.createEmptyBlock() + model.blocks.push(block) + blockModel.appendBlock(block) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/addblock@2x.png" + } + + Connections + { + target: clientModel + onNewBlock: + { + if (!clientModel.running) + { + var lastBlock = model.blocks[model.blocks.length - 1] + lastBlock.status = "mined" + lastBlock.number = model.blocks.length + var lastB = blockModel.get(model.blocks.length - 1) + lastB.status = "mined" + lastB.number = model.blocks.length + addBlockBtn.addNewBlock() + } + } + onStateCleared: + { + } + onNewRecord: + { + var blockIndex = parseInt(_r.transactionIndex.split(":")[0]) - 1 + var trIndex = parseInt(_r.transactionIndex.split(":")[1]) + if (blockIndex <= model.blocks.length - 1) + { + var item = model.blocks[blockIndex] + if (trIndex <= item.transactions.length - 1) + { + var tr = item.transactions[trIndex] + tr.returned = _r.returned + tr.recordIndex = _r.recordIndex + tr.logs = _r.logs + tr.sender = _r.sender + var trModel = blockModel.getTransaction(blockIndex, trIndex) + trModel.returned = _r.returned + trModel.recordIndex = _r.recordIndex + trModel.logs = _r.logs + trModel.sender = _r.sender + blockModel.setTransaction(blockIndex, trIndex, trModel) + return; + } + } + + // tr is not in the list. + var itemTr = TransactionHelper.defaultTransaction() + itemTr.saveStatus = false + itemTr.functionId = _r.function + itemTr.contractId = _r.contract + itemTr.gasAuto = true + itemTr.parameters = _r.parameters + itemTr.isContractCreation = itemTr.functionId === itemTr.contractId + itemTr.label = _r.label + itemTr.isFunctionCall = itemTr.functionId !== "" + itemTr.returned = _r.returned + itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) + itemTr.sender = _r.sender + itemTr.recordIndex = _r.recordIndex + itemTr.logs = _r.logs + model.blocks[model.blocks.length - 1].transactions.push(itemTr) + blockModel.appendTransaction(itemTr) + } + onMiningComplete: + { + } + } + + ScenarioButton { + id: newAccount + text: qsTr("New Account") + onClicked: { + model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/newaccounticon@2x.png" + } + } + } + + TransactionDialog { + id: transactionDialog + property bool execute + onAccepted: { + var item = transactionDialog.getItem() + if (execute) + { + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + { + var newBlock = projectModel.stateListModel.createEmptyBlock(); + model.blocks.push(newBlock); + blockModel.appendBlock(newBlock) + } + if (!clientModel.running) + clientModel.executeTr(item) + } + else { + model.blocks[blockIndex].transactions[transactionIndex] = item + blockModel.setTransaction(blockIndex, transactionIndex, item) + chainChanged() + } + + } + } +} + + diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 9decc91ae..0129f864d 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -11,7 +11,6 @@ import "." Rectangle { id: debugPanel - property alias transactionLog: transactionLog property alias debugSlider: statesSlider property alias solLocals: solLocals property alias solStorage: solStorage @@ -23,7 +22,7 @@ Rectangle { signal debugExecuteLocation(string documentId, var location) property string compilationErrorMessage property bool assemblyMode: false - + signal panelClosed objectName: "debugPanel" color: "#ededed" clip: true @@ -40,6 +39,11 @@ Rectangle { machineStates.updateHeight(); } + function setTr(tr) + { + trName.text = tr.label + } + function displayCompilationErrorIfAny() { debugScrollArea.visible = false; @@ -61,7 +65,6 @@ Rectangle { { Debugger.init(data); debugScrollArea.visible = true; - compilationErrorArea.visible = false; machineStates.visible = true; } if (giveFocus) @@ -97,96 +100,77 @@ Rectangle { Settings { id: splitSettings - property alias transactionLogHeight: transactionLog.height property alias callStackHeight: callStackRect.height property alias storageHeightSettings: storageRect.height property alias memoryDumpHeightSettings: memoryRect.height property alias callDataHeightSettings: callDataRect.height - property alias transactionLogVisible: transactionLog.visible property alias solCallStackHeightSettings: solStackRect.height property alias solStorageHeightSettings: solStorageRect.height property alias solLocalsHeightSettings: solLocalsRect.height } - Rectangle - { - visible: false; - id: compilationErrorArea - width: parent.width - 20 - height: 600 - color: "#ededed" - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: 10 - ColumnLayout + ColumnLayout { + id: debugScrollArea + anchors.fill: parent + //orientation: Qt.Vertical + spacing: 0 + RowLayout { - width: parent.width - anchors.top: parent.top - spacing: 15 + Layout.preferredWidth: parent.width + Layout.preferredHeight: 30 Rectangle { - height: 15 - Button { - text: qsTr("Back to Debugger") - onClicked: { - debugScrollArea.visible = true; - compilationErrorArea.visible = false; - machineStates.visible = true; - } + Layout.preferredWidth: parent.width + Layout.preferredHeight: parent.height + color: "transparent" + Text { + anchors.centerIn: parent + text: qsTr("Current Transaction") } - } - RowLayout - { - height: 100 - ColumnLayout + Rectangle { - Text { - color: "red" - id: errorLocation + anchors.left: parent.left + anchors.leftMargin: 10 + width: 30 + height: parent.height + color: "transparent" + anchors.verticalCenter: parent.verticalCenter + Image { + source: "qrc:/qml/img/leftarrow@2x.png" + width: parent.width + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent } - Text { - color: "#4a4a4a" - id: errorDetail + MouseArea + { + anchors.fill: parent + onClicked: + { + Debugger.init(null); + panelClosed() + } } } } + } + RowLayout + { + Layout.preferredWidth: parent.width + Layout.preferredHeight: 30 Rectangle { - width: parent.width - 6 - height: 2 - color: "#d0d0d0" - } - - RowLayout - { - Text - { - color: "#4a4a4a" - id: errorLine + Layout.preferredWidth: parent.width + Layout.preferredHeight: parent.height + color: "#2C79D3" + Text { + id: trName + color: "white" + anchors.centerIn: parent } } } - } - - Splitter { - id: debugScrollArea - anchors.fill: parent - orientation: Qt.Vertical - - TransactionLog { - id: transactionLog - Layout.fillWidth: true - Layout.minimumHeight: 130 - height: 250 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: machineStates.sideMargin - anchors.rightMargin: machineStates.sideMargin - anchors.topMargin: machineStates.sideMargin - } ScrollView { @@ -230,32 +214,6 @@ Rectangle { spacing: 3 layoutDirection: Qt.LeftToRight - StepActionImage - { - id: playAction - enabledStateImg: "qrc:/qml/img/play_button.png" - disableStateImg: "qrc:/qml/img/play_button.png" - buttonLeft: true - onClicked: projectModel.stateListModel.runState(transactionLog.selectedStateIndex) - width: 23 - buttonShortcut: "Ctrl+Shift+F8" - buttonTooltip: qsTr("Start Debugging") - visible: true - Layout.alignment: Qt.AlignLeft - } - - StepActionImage - { - id: pauseAction - enabledStateImg: "qrc:/qml/img/stop_button2x.png" - disableStateImg: "qrc:/qml/img/stop_button2x.png" - onClicked: Debugger.init(null); - width: 23 - buttonShortcut: "Ctrl+Shift+F9" - buttonTooltip: qsTr("Stop Debugging") - visible: true - } - StepActionImage { id: runBackAction; @@ -562,12 +520,12 @@ Rectangle { } Rectangle { - id: separator - width: parent.width; - height: 1; - color: "#cccccc" - anchors.bottom: parent.bottom - } + id: separator + width: parent.width; + height: 1; + color: "#cccccc" + anchors.bottom: parent.bottom + } } } } diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 67f45f973..de19baf35 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -20,13 +20,14 @@ Rectangle { anchors.fill: parent id: root - property alias rightViewVisible: rightView.visible + property alias rightViewVisible: scenarioExe.visible property alias webViewVisible: webPreview.visible property alias webView: webPreview property alias projectViewVisible: projectList.visible property alias projectNavigator: projectList property alias runOnProjectLoad: mainSettings.runOnProjectLoad - property alias rightPane: rightView + property alias rightPane: scenarioExe + property alias debuggerPanel: debugPanel property alias codeEditor: codeEditor property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally property bool firstCompile: true @@ -43,7 +44,7 @@ Rectangle { } Connections { - target: rightView + target: debugPanel onDebugExecuteLocation: { codeEditor.highlightExecution(documentId, location); } @@ -52,7 +53,7 @@ Rectangle { Connections { target: codeEditor onBreakpointsChanged: { - rightPane.setBreakpoints(codeEditor.getBreakpoints()); + debugPanel.setBreakpoints(codeEditor.getBreakpoints()); } } @@ -63,20 +64,20 @@ Rectangle { } function toggleRightView() { - rightView.visible = !rightView.visible; + scenarioExe.visible = !scenarioExe.visible; } function ensureRightView() { - rightView.visible = true; + scenarioExe.visible = true; } function rightViewIsVisible() { - return rightView.visible; + return scenarioExe.visible; } function hideRightView() { - rightView.visible = false; + scenarioExe.visible = lfalse; } function toggleWebPreview() { @@ -98,8 +99,8 @@ Rectangle { function displayCompilationErrorIfAny() { - rightView.visible = true; - rightView.displayCompilationErrorIfAny(); + scenarioExe.visible = true; + scenarioExe.displayCompilationErrorIfAny(); } Settings { @@ -153,7 +154,7 @@ Rectangle { id: splitSettings property alias projectWidth: projectList.width property alias contentViewWidth: contentView.width - property alias rightViewWidth: rightView.width + property alias rightViewWidth: scenarioExe.width } Splitter @@ -198,14 +199,45 @@ Rectangle { } } - Debugger { + ScenarioExecution + { + id: scenarioExe; visible: false; - id: rightView; Layout.fillHeight: true Keys.onEscapePressed: visible = false - Layout.minimumWidth: 515 + Layout.minimumWidth: 650 + anchors.right: parent.right + } + + Debugger + { + id: debugPanel + visible: false + Layout.fillHeight: true + Keys.onEscapePressed: visible = false + Layout.minimumWidth: 650 anchors.right: parent.right } + + Connections { + target: clientModel + onDebugDataReady: { + scenarioExe.visible = false + debugPanel.visible = true + if (scenarioExe.bc.debugTrRequested) + { + debugPanel.setTr(scenarioExe.bc.model.blocks[scenarioExe.bc.debugTrRequested[0]].transactions[scenarioExe.bc.debugTrRequested[1]]) + } + } + } + + Connections { + target: debugPanel + onPanelClosed: { + debugPanel.visible = false + scenarioExe.visible = true + } + } } } } diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index c880f0904..4781d092b 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -39,21 +39,26 @@ Item { accountRef.clear(); accountRef.append({"itemid": " - "}); - - if (subType === "contract" || subType === "address") + if (subType === "contract" || subType === "address") { var trCr = 0; - for (var k = 0; k < transactionsModel.count; k++) - { - if (k >= transactionIndex) - break; - var tr = transactionsModel.get(k); - if (tr.functionId === tr.contractId /*&& (dec[1] === tr.contractId || item.subType === "address")*/) - { - accountRef.append({ "itemid": tr.contractId + " - " + trCr, "value": "<" + tr.contractId + " - " + trCr + ">", "type": "contract" }); - trCr++; - } - } + if (blockChainPanel) + for (var k = 0; k < blockChainPanel.model.blocks.length; k++) + { + if (k > blockIndex) + break; + for (var i = 0; i < blockChainPanel.model.blocks[k].transactions.length; i++) + { + if (i > transactionIndex) + break; + var tr = blockChainPanel.model.blocks[k].transactions[i] + if (tr.functionId === tr.contractId /*&& (dec[1] === tr.contractId || item.subType === "address")*/) + { + accountRef.append({ "itemid": tr.contractId + " - " + trCr, "value": "<" + tr.contractId + " - " + trCr + ">", "type": "contract" }); + trCr++; + } + } + } } if (subType === "address") { diff --git a/mix/qml/ScenarioButton.qml b/mix/qml/ScenarioButton.qml new file mode 100644 index 000000000..4dd7bc53f --- /dev/null +++ b/mix/qml/ScenarioButton.qml @@ -0,0 +1,67 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls.Styles 1.1 + +Rectangle { + id: buttonActionContainer + property string text + property string buttonShortcut + property string sourceImg + property string fillColor + signal clicked + + Rectangle { + id: contentRectangle + anchors.fill: parent + border.color: "#cccccc" + border.width: 1 + radius: 4 + color: parent.fillColor ? parent.fillColor : "white" + Image { + id: debugImage + anchors { + left: parent.left + right: parent.right + top: parent.top + bottom: parent.bottom + bottomMargin: debugImg.pressed ? 0 : 2; + topMargin: debugImg.pressed ? 2 : 0; + } + source: sourceImg + fillMode: Image.PreserveAspectFit + height: 30 + } + + Button { + anchors.fill: parent + id: debugImg + action: buttonAction + style: ButtonStyle { + background: Rectangle { + color: "transparent" + } + } + } + + Action { + id: buttonAction + shortcut: buttonShortcut + onTriggered: { + buttonActionContainer.clicked(); + } + } + } + + Rectangle + { + anchors.top: contentRectangle.bottom + anchors.topMargin: 15 + width: parent.width + Text + { + text: buttonActionContainer.text + anchors.centerIn: parent + } + } +} diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml new file mode 100644 index 000000000..bc872bff7 --- /dev/null +++ b/mix/qml/ScenarioExecution.qml @@ -0,0 +1,57 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.1 +import Qt.labs.settings 1.0 +import "js/Debugger.js" as Debugger +import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "." + +Rectangle { + color: "#ededed" + property alias bc: blockChain + + Connections + { + target: projectModel + onProjectLoaded: { + loader.init() + } + + } + + Column + { + anchors.margins: 10 + anchors.fill: parent + spacing: 10 + ScenarioLoader + { + height: 70 + width: parent.width + id: loader + } + + Rectangle + { + width: parent.width + height: 1 + color: "#cccccc" + } + + Connections + { + target: loader + onLoaded: { + blockChain.load(scenario) + } + } + + BlockChain + { + id: blockChain + width: parent.width + } + } +} diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml new file mode 100644 index 000000000..93f4f059b --- /dev/null +++ b/mix/qml/ScenarioLoader.qml @@ -0,0 +1,175 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.2 +import QtQuick.Window 2.0 +import QtQuick.Dialogs 1.1 +import Qt.labs.settings 1.0 +import "js/Debugger.js" as Debugger +import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "." + +RowLayout +{ + signal restored(variant scenario) + signal saved(variant scenario) + signal duplicated(variant scenario) + signal loaded(variant scenario) + spacing: 0 + function init() + { + scenarioList.load() + } + + id: blockChainSelector + + Dialog { + id: newStateWin + modality: Qt.ApplicationModal + title: qsTr("New Project"); + + width: 320 + height: 120 + + visible: false + + contentItem: Rectangle { + anchors.fill: parent + anchors.margins: 10 + RowLayout { + anchors.verticalCenter: parent.verticalCenter + Text { + text: qsTr("Name:") + } + + Rectangle + { + Layout.preferredWidth: 250 + Layout.preferredHeight: parent.height + border.width: 1 + border.color: "#cccccc" + TextInput + { + anchors.fill: parent + id: stateName + } + } + } + RowLayout + { + anchors.bottom: parent.bottom + anchors.right: parent.right; + function acceptAndClose() + { + var item = projectModel.stateListModel.createDefaultState(); + item.title = stateName.text + projectModel.stateListModel.appendState(item) + projectModel.stateListModel.save() + close() + scenarioList.currentIndex = projectModel.stateListModel.count - 1 + } + + function close() + { + newStateWin.close() + stateName.text = "" + } + + Button { + id: okButton; + enabled: stateName.text !== "" + text: qsTr("OK"); + onClicked: { + parent.acceptAndClose(); + } + } + Button { + text: qsTr("Cancel"); + onClicked: parent.close(); + } + } + } + } + + ComboBox + { + id: scenarioList + model: projectModel.stateListModel + textRole: "title" + onCurrentIndexChanged: + { + restoreScenario.restore() + } + + function load() + { + var state = projectModel.stateListModel.getState(currentIndex) + loaded(state) + } + } + + Row + { + Layout.preferredWidth: 100 * 4 + Layout.preferredHeight: 30 + spacing: 0 + ScenarioButton { + id: restoreScenario + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/restoreicon@2x.png" + onClicked: { + restore() + } + text: qsTr("Restore") + function restore() + { + var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) + restored(state) + loaded(state) + } + } + + ScenarioButton { + id: saveScenario + text: qsTr("Save") + onClicked: { + projectModel.saveProjectFile() + saved(state) + } + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/saveicon@2x.png" + } + + ScenarioButton + { + id: duplicateScenario + text: qsTr("Duplicate") + onClicked: { + projectModel.stateListModel.duplicateState(scenarioList.currentIndex) + duplicated(state) + } + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/duplicateicon@2x.png" + } + + ScenarioButton { + id: addScenario + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/plus.png" + onClicked: { + newStateWin.open() + } + text: qsTr("New") + } + } + +} diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index d3062af9e..992113cc6 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -20,13 +20,29 @@ Item { s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project if (!s.contracts) s.contracts = []; - return { - title: s.title, - transactions: s.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem), //support old projects by filtering std contracts - accounts: s.accounts.map(fromPlainAccountItem), - contracts: s.contracts.map(fromPlainAccountItem), - miner: s.miner - }; + + var ret = {}; + ret.title = s.title; + ret.transactions = s.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem); //support old projects by filtering std contracts + if (s.blocks) + ret.blocks = s.blocks.map(fromPlainBlockItem); + ret.accounts = s.accounts.map(fromPlainAccountItem); + ret.contracts = s.contracts.map(fromPlainAccountItem); + ret.miner = s.miner; + + // support old projects + if (!ret.blocks) + { + ret.blocks = [{ + hash: "", + number: -1, + transactions: [], + status: "pending" + }] + for (var j in ret.transactions) + ret.blocks[0].transactions.push(fromPlainTransactionItem(toPlainTransactionItem(ret.transactions[j]))) + } + return ret; } function fromPlainAccountItem(t) @@ -58,9 +74,13 @@ Item { sender: t.sender, isContractCreation: t.isContractCreation, label: t.label, - isFunctionCall: t.isFunctionCall + isFunctionCall: t.isFunctionCall, + saveStatus: t.saveStatus }; + if (r.saveStatus === undefined) + r.saveStatus = true + if (r.isFunctionCall === undefined) r.isFunctionCall = true; @@ -76,9 +96,21 @@ Item { return r; } + function fromPlainBlockItem(b) + { + var r = { + hash: b.hash, + number: b.number, + transactions: b.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem), //support old projects by filtering std contracts + status: b.status + } + return r; + } + function toPlainStateItem(s) { return { title: s.title, + blocks: s.blocks.map(toPlainBlockItem), transactions: s.transactions.map(toPlainTransactionItem), accounts: s.accounts.map(toPlainAccountItem), contracts: s.contracts.map(toPlainAccountItem), @@ -96,6 +128,17 @@ Item { return ''; } + function toPlainBlockItem(b) + { + var r = { + hash: b.hash, + number: b.number, + transactions: b.transactions.map(toPlainTransactionItem), + status: b.status + } + return r; + } + function toPlainAccountItem(t) { return { @@ -125,7 +168,8 @@ Item { parameters: {}, isContractCreation: t.isContractCreation, label: t.label, - isFunctionCall: t.isFunctionCall + isFunctionCall: t.isFunctionCall, + saveStatus: t.saveStatus }; for (var key in t.parameters) r.parameters[key] = t.parameters[key]; @@ -146,6 +190,8 @@ Item { projectData.states.push(toPlainStateItem(stateList[i])); } projectData.defaultStateIndex = stateListModel.defaultStateIndex; + stateListModel.data = projectData + } onNewProject: { var state = toPlainStateItem(stateListModel.createDefaultState()); @@ -170,6 +216,11 @@ Item { id: stateDialog onAccepted: { var item = stateDialog.getItem(); + saveState(item); + } + + function saveState(item) + { if (stateDialog.stateIndex < stateListModel.count) { if (stateDialog.isDefault) stateListModel.defaultStateIndex = stateIndex; @@ -190,6 +241,7 @@ Item { ListModel { id: stateListModel property int defaultStateIndex: 0 + property variant data signal defaultStateChanged; signal stateListModelReady; signal stateRun(int index) @@ -208,12 +260,32 @@ Item { return { name: name, secret: _secret, balance: QEtherHelper.createEther(_balance, _unit), address: address }; } + function duplicateState(index) + { + var state = stateList[index] + var item = fromPlainStateItem(toPlainStateItem(state)) + item.title = qsTr("Copy of") + " " + state.title + appendState(item) + save() + } + + function createEmptyBlock() + { + return { + hash: "", + number: -1, + transactions: [], + status: "pending" + } + } + function createDefaultState() { var item = { title: "", transactions: [], accounts: [], - contracts: [] + contracts: [], + blocks: [{ status: "pending", number: -1, hash: "", transactions: []}] }; var account = newAccount("1000000", QEther.Ether, defaultAccount) @@ -228,6 +300,7 @@ Item { ctorTr.label = qsTr("Deploy") + " " + ctorTr.contractId; ctorTr.sender = item.accounts[0].secret; item.transactions.push(ctorTr); + item.blocks[0].transactions.push(ctorTr) } return item; } @@ -284,10 +357,20 @@ Item { stateDialog.open(stateListModel.count, item, false); } + function appendState(item) + { + stateListModel.append(item); + stateList.push(item); + } + function editState(index) { stateDialog.open(index, stateList[index], defaultStateIndex === index); } + function getState(index) { + return stateList[index]; + } + function debugDefaultState() { if (defaultStateIndex >= 0 && defaultStateIndex < stateList.length) runState(defaultStateIndex); @@ -295,7 +378,7 @@ Item { function runState(index) { var item = stateList[index]; - clientModel.setupState(item); + clientModel.setupScenario(item); stateRun(index); } @@ -322,8 +405,20 @@ Item { return stateList[defaultStateIndex].title; } + function reloadStateFromFromProject(index) + { + if (data) + { + var item = fromPlainStateItem(data.states[index]) + stateListModel.set(index, item) + stateList[index] = item + return item + } + } + function loadStatesFromProject(projectData) { + data = projectData if (!projectData.states) projectData.states = []; if (projectData.defaultStateIndex !== undefined) diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 029fd162d..880f22057 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -9,6 +9,7 @@ Column property alias members: repeater.model //js array property variant accounts property var value: ({}) + property int blockIndex property int transactionIndex property string context Layout.fillWidth: true diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index df5ad781b..287ba08c2 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -17,6 +17,7 @@ Dialog { visible: false title: qsTr("Edit Transaction") property int transactionIndex + property int blockIndex property alias gas: gasValueEdit.gasValue; property alias gasAuto: gasAutoCheck.checked; property alias gasPrice: gasPriceField.value; @@ -27,21 +28,24 @@ Dialog { property var paramsModel: []; property bool useTransactionDefaultValue: false property alias stateAccounts: senderComboBox.model + property bool saveStatus signal accepted; StateDialogStyle { id: transactionDialogStyle } - function open(index, item) { + function open(index, blockIdx, item) { rowFunction.visible = !useTransactionDefaultValue; rowValue.visible = !useTransactionDefaultValue; rowGas.visible = !useTransactionDefaultValue; rowGasPrice.visible = !useTransactionDefaultValue; - transactionIndex = index; - typeLoader.transactionIndex = index; - + transactionIndex = index + blockIndex = blockIdx + typeLoader.transactionIndex = index + typeLoader.blockIndex = blockIdx + saveStatus = item.saveStatus gasValueEdit.gasValue = item.gas; gasAutoCheck.checked = item.gasAuto ? true : false; gasPriceField.value = item.gasPrice; @@ -229,7 +233,7 @@ Dialog { item.functionId = item.contractId; item.label = qsTr("Deploy") + " " + item.contractId; } - + item.saveStatus = saveStatus item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; item.parameters = paramValues; return item; diff --git a/mix/qml/img/newIcon.png b/mix/qml/img/newIcon.png new file mode 100644 index 000000000..016d0ddbb Binary files /dev/null and b/mix/qml/img/newIcon.png differ diff --git a/mix/qml/img/newIcon@2x.png b/mix/qml/img/newIcon@2x.png new file mode 100644 index 000000000..085fcb686 Binary files /dev/null and b/mix/qml/img/newIcon@2x.png differ diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 6fce7686d..31f30e2da 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -82,9 +82,9 @@ function saveProjectFile() }; for (var i = 0; i < projectListModel.count; i++) projectData.files.push({ - title: projectListModel.get(i).name, - fileName: projectListModel.get(i).fileName, - }); + title: projectListModel.get(i).name, + fileName: projectListModel.get(i).fileName, + }); projectFileSaving(projectData); var json = JSON.stringify(projectData, null, "\t"); @@ -98,50 +98,52 @@ function saveProjectFile() function loadProject(path) { closeProject(function() { - console.log("Loading project at " + path); - var projectFile = path + projectFileName; - var json = fileIo.readFile(projectFile); - var projectData = JSON.parse(json); - if (projectData.deploymentDir) - projectModel.deploymentDir = projectData.deploymentDir - if (projectData.packageHash) - deploymentDialog.packageHash = projectData.packageHash - if (projectData.packageBase64) - deploymentDialog.packageBase64 = projectData.packageBase64 - if (projectData.applicationUrlEth) - deploymentDialog.applicationUrlEth = projectData.applicationUrlEth - if (projectData.applicationUrlHttp) - deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp - if (!projectData.title) { - var parts = path.split("/"); - projectData.title = parts[parts.length - 2]; - } - deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : []; - projectTitle = projectData.title; - projectPath = path; - if (!projectData.files) - projectData.files = []; - - for(var i = 0; i < projectData.files.length; i++) { - var entry = projectData.files[i]; - if (typeof(entry) === "string") - addFile(entry); //TODO: remove old project file support - else - addFile(entry.fileName, entry.title); - } - if (mainApplication.trackLastProject) - projectSettings.lastProjectPath = path; - projectLoading(projectData); - projectLoaded() - - //TODO: move this to codemodel - var contractSources = {}; - for (var d = 0; d < listModel.count; d++) { - var doc = listModel.get(d); - if (doc.isContract) - contractSources[doc.documentId] = fileIo.readFile(doc.path); - } - codeModel.reset(contractSources); + console.log("Loading project at " + path); + var projectFile = path + projectFileName; + var json = fileIo.readFile(projectFile); + if (!json) + return; + var projectData = JSON.parse(json); + if (projectData.deploymentDir) + projectModel.deploymentDir = projectData.deploymentDir + if (projectData.packageHash) + deploymentDialog.packageHash = projectData.packageHash + if (projectData.packageBase64) + deploymentDialog.packageBase64 = projectData.packageBase64 + if (projectData.applicationUrlEth) + deploymentDialog.applicationUrlEth = projectData.applicationUrlEth + if (projectData.applicationUrlHttp) + deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp + if (!projectData.title) { + var parts = path.split("/"); + projectData.title = parts[parts.length - 2]; + } + deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : []; + projectTitle = projectData.title; + projectPath = path; + if (!projectData.files) + projectData.files = []; + + for(var i = 0; i < projectData.files.length; i++) { + var entry = projectData.files[i]; + if (typeof(entry) === "string") + addFile(entry); //TODO: remove old project file support + else + addFile(entry.fileName, entry.title); + } + if (mainApplication.trackLastProject) + projectSettings.lastProjectPath = path; + projectLoading(projectData); + projectLoaded() + + //TODO: move this to codemodel + var contractSources = {}; + for (var d = 0; d < listModel.count; d++) { + var doc = listModel.get(d); + if (doc.isContract) + contractSources[doc.documentId] = fileIo.readFile(doc.path); + } + codeModel.reset(contractSources); }); } @@ -160,12 +162,12 @@ function addFile(fileName, title) { path: p, fileName: fileName, name: title !== undefined ? title : fileName, - documentId: fileName, - syntaxMode: syntaxMode, - isText: isContract || isHtml || isCss || isJs, - isContract: isContract, - isHtml: isHtml, - groupName: groupName + documentId: fileName, + syntaxMode: syntaxMode, + isText: isContract || isHtml || isCss || isJs, + isContract: isContract, + isHtml: isHtml, + groupName: groupName }; projectListModel.append(docData); diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index b9a011b66..f8bad03ed 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -12,7 +12,8 @@ function defaultTransaction() stdContract: false, isContractCreation: true, label: "", - isFunctionCall: true + isFunctionCall: true, + saveStatus: true }; } diff --git a/mix/res.qrc b/mix/res.qrc index ac0af57ac..b50aa3d9f 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -68,5 +68,27 @@ qml/img/warningicon.png qml/img/warningicon@2x.png qml/QAddressView.qml + qml/img/addblock.png + qml/img/addblock@2x.png + qml/img/duplicateicon.png + qml/img/duplicateicon@2x.png + qml/img/leftarrow.png + qml/img/leftarrow@2x.png + qml/img/newaccounticon.png + qml/img/newaccounticon@2x.png + qml/img/recyclediscard.png + qml/img/recyclediscard@2x.png + qml/img/recycleicon.png + qml/img/recycleicon@2x.png + qml/img/recyclekeep.png + qml/img/recyclekeep@2x.png + qml/img/restoreicon.png + qml/img/restoreicon@2x.png + qml/img/rightarrow.png + qml/img/rightarrow@2x.png + qml/img/saveicon.png + qml/img/saveicon@2x.png + qml/img/sendtransactionicon.png + qml/img/sendtransactionicon@2x.png diff --git a/test/fuzzTesting/checkRandomVMTest.cpp b/test/fuzzTesting/checkRandomVMTest.cpp index 13d677e17..a6ade07f1 100644 --- a/test/fuzzTesting/checkRandomVMTest.cpp +++ b/test/fuzzTesting/checkRandomVMTest.cpp @@ -98,9 +98,9 @@ bool doVMTest(mValue& _v) try { auto vm = eth::VMFactory::create(); - output = vm->go(fev.gas, fev, fev.simpleTrace()).toBytes(); + output = vm->exec(fev.gas, fev, fev.simpleTrace()); } - catch (eth::VMException) + catch (eth::VMException const&) { cnote << "Safe VM Exception"; vmExceptionOccured = true; diff --git a/test/fuzzTesting/createRandomVMTest.cpp b/test/fuzzTesting/createRandomVMTest.cpp index 3196590d4..93040d6de 100644 --- a/test/fuzzTesting/createRandomVMTest.cpp +++ b/test/fuzzTesting/createRandomVMTest.cpp @@ -160,7 +160,7 @@ void doMyTests(json_spirit::mValue& _v) bool vmExceptionOccured = false; try { - output = vm->go(fev.gas, fev, fev.simpleTrace()).toBytes(); + output = vm->exec(fev.gas, fev, fev.simpleTrace()); } catch (eth::VMException const& _e) { diff --git a/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json b/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json index 1b2d59385..1c870c543 100644 --- a/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json +++ b/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json @@ -42,7 +42,2072 @@ } }, + "CallEcrecoverH_prefixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa0b29af6a56d6cfef6415cb195ccbe540e006d0a", + "0x01" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecoverV_prefixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x01" : "0x01", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 0x001c) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecoverR_prefixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x3f17f1962b36e491b30a40b2405849e597ba5fb5", + "0x01" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x00b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecoverS_prefixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xb4950a7fad428434b11c357fa6d4b4bcd3096a5d", + "0x01" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0x00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "CallEcrecover80": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x3f17f1962b36e491b30a40b2405849e597ba5fb5", + "0x01" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x00b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0x00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover0_overlappingInputOutput": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x01" : "0x01", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 300000 1 0 0 128 64 32) [[ 0 ]] (MOD (MLOAD 64) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + + "CallEcrecover0_completeReturnValue": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 3000 1 0 0 128 128 32) [[ 0 ]] (MLOAD 128) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover0_gas3000": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x01" : "0x01", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 3000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover0_NoGas": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { + "balance" : "0x011248" + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 0 1 1 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover0_Gas2999": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x02" : "0x00" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 2999 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover0_0input": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ [[ 2 ]] (CALL 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 1) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 100000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 33 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 65 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 100000 1 0 0 97 97 32) [[ 0 ]] (MOD (MLOAD 97) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xe4319f4b631c6d0fcfc84045dbcb676865fe5e13", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9) (MSTORE 32 27) (MSTORE 64 0x6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a) (MSTORE 96 0x37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4) [[ 2 ]] (CALL 100000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "0x600160005260206000602060006000600260fff1600051600055", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ [[ 2 ]] (CALL 500 2 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_1_nonzeroValue": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "100000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "0000000000000000000000000000000000000002" : { + "balance" : "19" + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "200000000", + "nonce" : "0", + "code" : "{ [[ 2 ]] (CALL 200000 2 0x13 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xcb39b3bde22925b2f931111130c774761d8895e0e08437c9b396c1e97d10f34d", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x7392925565d67be8e9620aacbcfaecd8cb6ec58d709d25da9eccf1d08a41ce35", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_3_prefix0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x7392925565d67be8e9620aacbcfaecd8cb6ec58d709d25da9eccf1d08a41ce35", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0x00f34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_3_postfix0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x3b745a1c00d035c334f358d007a430e4cf0ae63aa0556fb05529706de546464d", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xf34578907f00) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xaf9613760f72635fbdb44a5a0a63c39f12af30f950a6ee5c971be188e89c4051", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_4_gas99": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xaf9613760f72635fbdb44a5a0a63c39f12af30f950a6ee5c971be188e89c4051", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 99 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 600 2 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "0x600160005260206000602060006000600360fff1600051600055", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x9c1185a5c5e9fc54612808977ee8f548b2258d31", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ [[ 2 ]] (CALL 600 3 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x00" : "0xdbc100f916bfbc53535573d98cf0cbb3a5b36124", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 6000 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x00" : "0x316750573f9be26bc17727b47cacedbd0ab3e6ca", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 6000 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_3_prefixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x00" : "0x316750573f9be26bc17727b47cacedbd0ab3e6ca", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0x00f34578907f) [[ 2 ]] (CALL 6000 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_3_postfixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x00" : "0x7730b4642169b0f16752696da8da830a4b429c9d", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xf34578907f00) [[ 2 ]] (CALL 6000 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x00" : "0x1cf4e77f5966e13e109703cd8a0df7ceda7f3dc3", + "0x02" : "0x01" } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 720 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_4_gas719": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 719 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 6000 3 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentitiy_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0000000000000000000000000000000000000000000000000000000000000001" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "0x600160005260206000602060006000600460fff1600051600055", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentitiy_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ [[ 2 ]] (CALL 500 4 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentity_1_nonzeroValue": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "100000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "0000000000000000000000000000000000000004" : { + "balance" : "19" + }, + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "200000000", + "nonce" : "0", + "code" : "{ [[ 2 ]] (CALL 200000 4 0x13 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentity_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x000000000000000000000000000000000000000000000000000000f34578907f", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 4 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentity_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x000000000000000000000000000000000000000000000000000000f34578907f", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 4 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentity_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 4 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentity_4_gas18": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 18 4 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentity_4_gas17": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "0x02" : "0x00" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 17 4 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentity_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 600 4 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CALLCODEEcrecover0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x01" : "0x01", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CALLCODEEcrecoverH_prefixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa0b29af6a56d6cfef6415cb195ccbe540e006d0a", + "0x01" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CALLCODEEcrecoverV_prefixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x01" : "0x01", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 0x001c) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CALLCODEEcrecoverR_prefixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x3f17f1962b36e491b30a40b2405849e597ba5fb5", + "0x01" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x00b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CALLCODEEcrecoverS_prefixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xb4950a7fad428434b11c357fa6d4b4bcd3096a5d", + "0x01" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0x00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CALLCODEEcrecover80": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0x3f17f1962b36e491b30a40b2405849e597ba5fb5", + "0x01" : "0x00", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x00b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0x00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3652240", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CALLCODEEcrecover0_overlappingInputOutput": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0x01" : "0x01", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 300000 1 0 0 128 64 32) [[ 0 ]] (MOD (MLOAD 64) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + + "CALLCODEEcrecover0_completeReturnValue": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -55,7 +2120,6 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "0x01" : "0x01", "0x02" : "0x01" } } @@ -64,7 +2128,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ (MSTORE 0 0x00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x00b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0x00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 3000 1 0 0 128 128 32) [[ 0 ]] (MLOAD 128) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -77,7 +2141,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "3652240", + "gasLimit" : "365224", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -85,7 +2149,7 @@ } }, - "CallEcrecover0_overlappingInputOutput": { + "CALLCODEEcrecover0_gas3000": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -107,7 +2171,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 300000 1 0 0 128 64 32) [[ 0 ]] (MOD (MLOAD 64) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 3000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -128,8 +2192,7 @@ } }, - - "CallEcrecover0_completeReturnValue": { + "CALLCODEEcrecover0_NoGas": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -139,18 +2202,15 @@ "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "expect" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "storage" : { - "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "0x02" : "0x01" - } + "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : { + "balance" : "0xb0a0" } }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 3000 1 0 0 128 128 32) [[ 0 ]] (MLOAD 128) }", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 0 1 1 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -171,7 +2231,7 @@ } }, - "CallEcrecover0_gas3000": { + "CALLCODEEcrecover0_Gas2999": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -183,9 +2243,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", - "0x01" : "0x01", - "0x02" : "0x01" + "0x02" : "0x00" } } }, @@ -193,7 +2251,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 3000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 2999 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -214,7 +2272,7 @@ } }, - "CallEcrecover0_BonusGas": { + "CALLCODEEcrecover0_0input": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -226,6 +2284,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { + "0x02" : "0x01" } } }, @@ -233,7 +2292,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 0 1 1 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "code": "{ [[ 2 ]] (CALLCODE 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -246,7 +2305,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "365224", + "gasLimit" : "3652240", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -254,7 +2313,7 @@ } }, - "CallEcrecover0_Gas2999": { + "CALLCODEEcrecover1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -266,6 +2325,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { + "0x02" : "0x01" } } }, @@ -273,7 +2333,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 2999 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 1) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 100000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -294,7 +2354,7 @@ } }, - "CallEcrecover0_0input": { + "CALLCODEEcrecover2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -314,7 +2374,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ [[ 2 ]] (CALL 300000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) }", + "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 33 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 65 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALLCODE 100000 1 0 0 97 97 32) [[ 0 ]] (MOD (MLOAD 97) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -327,7 +2387,7 @@ "transaction" : { "nonce" : "0", "gasPrice" : "1", - "gasLimit" : "3652240", + "gasLimit" : "365224", "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", "value" : "100000", "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", @@ -335,7 +2395,7 @@ } }, - "CallEcrecover1": { + "CALLCODEEcrecover3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -347,6 +2407,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { + "0x" : "0xe4319f4b631c6d0fcfc84045dbcb676865fe5e13", "0x02" : "0x01" } } @@ -355,7 +2416,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 1) (MSTORE 64 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 96 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 100000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "code": "{ (MSTORE 0 0x2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9) (MSTORE 32 27) (MSTORE 64 0x6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a) (MSTORE 96 0x37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4) [[ 2 ]] (CALLCODE 100000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -376,7 +2437,7 @@ } }, - "CallEcrecover2": { + "CALLCODESha256_0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -388,7 +2449,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x02" : "0x01" + "0x" : "0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5" } } }, @@ -396,7 +2457,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ (MSTORE 0 0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c) (MSTORE 32 28) (MSTORE 33 0x73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f) (MSTORE 65 0xeeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549) [[ 2 ]] (CALL 100000 1 0 0 97 97 32) [[ 0 ]] (MOD (MLOAD 97) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "code" : "0x600160005260206000602060006000600260fff2600051600055", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -417,7 +2478,7 @@ } }, - "CallEcrecover3": { + "CALLCODESha256_1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -429,7 +2490,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0xe4319f4b631c6d0fcfc84045dbcb676865fe5e13", + "0x" : "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "0x02" : "0x01" } } @@ -438,7 +2499,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code": "{ (MSTORE 0 0x2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9) (MSTORE 32 27) (MSTORE 64 0x6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a) (MSTORE 96 0x37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4) [[ 2 ]] (CALL 100000 1 0 0 128 128 32) [[ 0 ]] (MOD (MLOAD 128) (EXP 2 160)) [[ 1 ]] (EQ (ORIGIN) (SLOAD 0)) }", + "code" : "{ [[ 2 ]] (CALLCODE 500 2 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -459,11 +2520,11 @@ } }, - "CallSha256_0": { + "CALLCODESha256_1_nonzeroValue": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "10000000", + "currentGasLimit" : "100000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" @@ -471,15 +2532,16 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5" + "0x" : "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "0x02" : "0x01" } } }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "20000000", + "balance" : "200000000", "nonce" : "0", - "code" : "0x600160005260206000602060006000600260fff1600051600055", + "code" : "{ [[ 2 ]] (CALLCODE 200000 2 0x13 0 0 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -500,7 +2562,7 @@ } }, - "CallSha256_1": { + "CALLCODESha256_2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -512,7 +2574,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "0x" : "0xcb39b3bde22925b2f931111130c774761d8895e0e08437c9b396c1e97d10f34d", "0x02" : "0x01" } } @@ -521,7 +2583,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ [[ 2 ]] (CALL 500 2 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALLCODE 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -542,31 +2604,28 @@ } }, - "CallSha256_1_nonzeroValue": { + "CALLCODESha256_3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", - "currentGasLimit" : "100000000", + "currentGasLimit" : "10000000", "currentDifficulty" : "256", "currentTimestamp" : 1, "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "expect" : { - "0000000000000000000000000000000000000002" : { - "balance" : "19" - }, "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "0x" : "0x7392925565d67be8e9620aacbcfaecd8cb6ec58d709d25da9eccf1d08a41ce35", "0x02" : "0x01" } } }, "pre" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "200000000", + "balance" : "20000000", "nonce" : "0", - "code" : "{ [[ 2 ]] (CALL 200000 2 0x13 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALLCODE 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -587,7 +2646,7 @@ } }, - "CallSha256_2": { + "CALLCODESha256_3_prefix0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -599,7 +2658,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0xcb39b3bde22925b2f931111130c774761d8895e0e08437c9b396c1e97d10f34d", + "0x" : "0x7392925565d67be8e9620aacbcfaecd8cb6ec58d709d25da9eccf1d08a41ce35", "0x02" : "0x01" } } @@ -608,7 +2667,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0x00f34578907f) [[ 2 ]] (CALLCODE 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -629,7 +2688,7 @@ } }, - "CallSha256_3": { + "CALLCODESha256_3_postfix0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -641,7 +2700,7 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0x7392925565d67be8e9620aacbcfaecd8cb6ec58d709d25da9eccf1d08a41ce35", + "0x" : "0x3b745a1c00d035c334f358d007a430e4cf0ae63aa0556fb05529706de546464d", "0x02" : "0x01" } } @@ -650,7 +2709,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xf34578907f00) [[ 2 ]] (CALLCODE 500 2 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -671,7 +2730,7 @@ } }, - "CallSha256_4": { + "CALLCODESha256_4": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -692,7 +2751,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 100 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -713,7 +2772,7 @@ } }, - "CallSha256_4_gas99": { + "CALLCODESha256_4_gas99": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -734,7 +2793,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 99 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 99 2 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -755,7 +2814,7 @@ } }, - "CallSha256_5": { + "CALLCODESha256_5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -775,7 +2834,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 600 2 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 600 2 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -796,7 +2855,7 @@ } }, - "CallRipemd160_0": { + "CALLCODERipemd160_0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -816,7 +2875,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "0x600160005260206000602060006000600360fff1600051600055", + "code" : "0x600160005260206000602060006000600360fff2600051600055", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -837,7 +2896,7 @@ } }, - "CallRipemd160_1": { + "CALLCODERipemd160_1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -858,7 +2917,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ [[ 2 ]] (CALL 600 3 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ [[ 2 ]] (CALLCODE 600 3 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -879,7 +2938,7 @@ } }, - "CallRipemd160_2": { + "CALLCODERipemd160_2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -891,6 +2950,8 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { + "0x00" : "0xdbc100f916bfbc53535573d98cf0cbb3a5b36124", + "0x02" : "0x01" } } }, @@ -898,7 +2959,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALL 600 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 5 0xf34578907f) [[ 2 ]] (CALLCODE 6000 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -919,7 +2980,7 @@ } }, - "CallRipemd160_3": { + "CALLCODERipemd160_3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -931,7 +2992,8 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0xf34578907f" + "0x00" : "0x316750573f9be26bc17727b47cacedbd0ab3e6ca", + "0x02" : "0x01" } } }, @@ -939,7 +3001,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 600 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALLCODE 6000 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -960,7 +3022,7 @@ } }, - "CallRipemd160_4": { + "CALLCODERipemd160_3_prefixed0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -972,7 +3034,50 @@ "expect" : { "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { - "0x" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "0x00" : "0x316750573f9be26bc17727b47cacedbd0ab3e6ca", + "0x02" : "0x01" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0x00f34578907f) [[ 2 ]] (CALLCODE 6000 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CALLCODERipemd160_3_postfixed0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x00" : "0x7730b4642169b0f16752696da8da830a4b429c9d", + "0x02" : "0x01" } } }, @@ -980,7 +3085,48 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 120 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xf34578907f00) [[ 2 ]] (CALLCODE 6000 3 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "365224", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CALLCODERipemd160_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x00" : "0x1cf4e77f5966e13e109703cd8a0df7ceda7f3dc3", + "0x02" : "0x01" } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 720 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1001,7 +3147,7 @@ } }, - "CallRipemd160_4_gas99": { + "CALLCODERipemd160_4_gas719": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1021,7 +3167,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 119 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 719 3 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1042,7 +3188,7 @@ } }, - "CallRipemd160_5": { + "CALLCODERipemd160_5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1062,7 +3208,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 600 3 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 6000 3 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1083,7 +3229,7 @@ } }, - "CallIdentitiy_0": { + "CALLCODEIdentitiy_0": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1103,7 +3249,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "0x600160005260206000602060006000600460fff1600051600055", + "code" : "0x600160005260206000602060006000600460fff2600051600055", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1124,7 +3270,7 @@ } }, - "CallIdentitiy_1": { + "CALLCODEIdentitiy_1": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1145,7 +3291,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ [[ 2 ]] (CALL 500 4 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ [[ 2 ]] (CALLCODE 500 4 0 0 0 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1166,7 +3312,7 @@ } }, - "CallIdentity_1_nonzeroValue": { + "CALLCODEIdentity_1_nonzeroValue": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1176,9 +3322,6 @@ "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" }, "expect" : { - "0000000000000000000000000000000000000004" : { - "balance" : "19" - }, "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "storage" : { "0x" : "0x00", @@ -1190,7 +3333,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "200000000", "nonce" : "0", - "code" : "{ [[ 2 ]] (CALL 200000 4 0x13 0 0 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ [[ 2 ]] (CALLCODE 200000 4 0x13 0 0 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1211,7 +3354,7 @@ } }, - "CallIdentity_2": { + "CALLCODEIdentity_2": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1232,7 +3375,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 4 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALLCODE 500 4 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1253,7 +3396,7 @@ } }, - "CallIdentity_3": { + "CALLCODEIdentity_3": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1274,7 +3417,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALL 500 4 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xf34578907f) [[ 2 ]] (CALLCODE 500 4 0 0 37 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1295,7 +3438,7 @@ } }, - "CallIdentity_4": { + "CALLCODEIdentity_4": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1316,7 +3459,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 100 4 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 100 4 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1337,7 +3480,7 @@ } }, - "CallIdentity_4_gas18": { + "CALLCODEIdentity_4_gas18": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1358,7 +3501,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 18 4 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 18 4 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1379,7 +3522,7 @@ } }, - "CallIdentity_4_gas17": { + "CALLCODEIdentity_4_gas17": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1400,7 +3543,7 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 17 4 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 17 4 0 0 32 0 32) [[ 0 ]] (MLOAD 0)}", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1421,7 +3564,7 @@ } }, - "CallIdentity_5": { + "CALLCODEIdentity_5": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", "currentNumber" : "0", @@ -1441,7 +3584,48 @@ "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { "balance" : "20000000", "nonce" : "0", - "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALL 600 4 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", + "code" : "{ (MSTORE 0 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) [[ 2 ]] (CALLCODE 600 4 0 0 1000000 0 32) [[ 0 ]] (MLOAD 0)}", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "10000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "sec80": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "storage" : { + "0x00" : "0xc001f00d" + } + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20000000", + "nonce" : "0", + "code" : "0x601b565b6000555b005b630badf00d6003565b63c001f00d6003565b7319e7e376e7c213b7e7e7e46cc70a5dd086daff2a7f22ae6da6b482f9b1b19b0b897c3fd43884180a1c5ee361e1107a1bc635649dda600052601b603f537f16433dce375ce6dc8151d3f0a22728bc4a1d9fd6ed39dfd18b4609331937367f6040527f306964c0cf5d74f04129fdc60b54d35b596dde1bf89ad92cb4123318f4c0e40060605260206080607f60006000600161fffff21560075760805114601257600956", "storage": {} }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { @@ -1460,6 +3644,6 @@ "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "data" : "" } - } + }, } diff --git a/test/libethereum/StateTestsFiller/stSpecialTestFiller.json b/test/libethereum/StateTestsFiller/stSpecialTestFiller.json index aeaebefd8..8dee4af11 100644 --- a/test/libethereum/StateTestsFiller/stSpecialTestFiller.json +++ b/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" : { "env" : { "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", diff --git a/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json b/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json index 410434d1d..c5789f859 100644 --- a/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json +++ b/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" : { "expect" : "invalid", "transaction" : diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 2c56b7ada..ec66837e1 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -330,12 +330,10 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) { auto vm = eth::VMFactory::create(); auto vmtrace = Options::get().vmtrace ? fev.simpleTrace() : OnOpFunc{}; - auto outputRef = bytesConstRef{}; { Listener::ExecTimeGuard guard{i.first}; - outputRef = vm->go(fev.gas, fev, vmtrace); + output = vm->exec(fev.gas, fev, vmtrace); } - output = outputRef.toBytes(); } catch (VMException const&) { diff --git a/test/libp2p/net.cpp b/test/libp2p/net.cpp index 1cd43b13f..a31537b98 100644 --- a/test/libp2p/net.cpp +++ b/test/libp2p/net.cpp @@ -74,7 +74,7 @@ struct TestNodeTable: public NodeTable ret.push_back(make_pair(k,s_basePort+i)); } - return std::move(ret); + return ret; } void pingTestNodes(std::vector> const& _testNodes) diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index e81b4d7b5..44590b1c8 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -148,6 +148,8 @@ protected: { m_state.addBalance(m_sender, _value); // just in case eth::Executive executive(m_state, eth::LastHashes(), 0); + eth::ExecutionResult res; + executive.setResultRecipient(res); eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : @@ -176,7 +178,7 @@ protected: m_state.noteSending(m_sender); executive.finalize(); m_gasUsed = executive.gasUsed(); - m_output = executive.out().toVector(); + m_output = std::move(res.output); // FIXME: Looks like Framework needs ExecutiveResult embedded m_logs = executive.logs(); } diff --git a/test/libweb3jsonrpc/webthreestubclient.h b/test/libweb3jsonrpc/webthreestubclient.h index 51d556eec..99fe48034 100644 --- a/test/libweb3jsonrpc/webthreestubclient.h +++ b/test/libweb3jsonrpc/webthreestubclient.h @@ -374,16 +374,26 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - std::string eth_newBlockFilter(const std::string& param1) throw (jsonrpc::JsonRpcException) + std::string eth_newBlockFilter() throw (jsonrpc::JsonRpcException) { Json::Value p; - p.append(param1); + p = Json::nullValue; Json::Value result = this->CallMethod("eth_newBlockFilter",p); if (result.isString()) return result.asString(); else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + std::string eth_newPendingTransactionFilter() throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p = Json::nullValue; + Json::Value result = this->CallMethod("eth_newPendingTransactionFilter",p); + if (result.isString()) + return result.asString(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } bool eth_uninstallFilter(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; diff --git a/test/libwhisper/whisperMessage.cpp b/test/libwhisper/whisperMessage.cpp index 56a763622..343573713 100644 --- a/test/libwhisper/whisperMessage.cpp +++ b/test/libwhisper/whisperMessage.cpp @@ -37,7 +37,7 @@ Topics createRandomTopics(unsigned int i) ret.push_back(t); } - return move(ret); + return ret; } bytes createRandomPayload(unsigned int i) @@ -48,7 +48,7 @@ bytes createRandomPayload(unsigned int i) for (int j = 0; j < sz; ++j) ret.push_back(rand() % 256); - return move(ret); + return ret; } void comparePayloads(Message const& m1, Message const& m2) diff --git a/third/MainWin.cpp b/third/MainWin.cpp index 3cfc016e3..f2a90cc0b 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl;