From 6cf597651533d66759e00f69f8a3abe3d0d75d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 11 May 2015 14:07:27 +0200 Subject: [PATCH 01/90] Remove gas counter from VM interface (VMFace) --- evmjit/libevmjit-cpp/JitVM.cpp | 16 +++++----- evmjit/libevmjit-cpp/JitVM.h | 3 +- libethereum/Executive.cpp | 42 ++++++++++++------------- libethereum/Executive.h | 8 ++--- libethereum/ExtVM.cpp | 4 +-- libevm/VM.cpp | 23 +++++++------- libevm/VM.h | 9 ++---- libevm/VMFace.h | 10 ++---- libevm/VMFactory.cpp | 6 ++-- libevm/VMFactory.h | 2 +- test/fuzzTesting/checkRandomVMTest.cpp | 8 ++--- test/fuzzTesting/createRandomVMTest.cpp | 8 ++--- test/libevm/vm.cpp | 10 +++--- 13 files changed, 64 insertions(+), 85 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 84cc41dd1..717d70958 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -18,29 +18,27 @@ namespace eth extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below -bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) +bytesConstRef JitVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) { using namespace jit; auto rejected = false; // TODO: Rejecting transactions with gas limit > 2^63 can be used by attacker to take JIT out of scope - rejected |= m_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) + rejected |= io_gas > std::numeric_limits::max(); // Do not accept requests with gas > 2^63 (int64 max) rejected |= _ext.gasPrice > std::numeric_limits::max(); rejected |= _ext.currentBlock.number > std::numeric_limits::max(); rejected |= _ext.currentBlock.timestamp > std::numeric_limits::max(); if (rejected) { - cwarn << "Execution rejected by EVM JIT (gas limit: " << m_gas << "), executing with interpreter"; + cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter"; VMFactory::setKind(VMKind::Interpreter); - m_fallbackVM = VMFactory::create(m_gas); + m_fallbackVM = VMFactory::create(); VMFactory::setKind(VMKind::JIT); - auto&& output = m_fallbackVM->go(_ext, _onOp, _step); - m_gas = m_fallbackVM->gas(); // copy remaining gas, Executive expects it - return output; + return m_fallbackVM->go(io_gas, _ext, _onOp, _step); } - m_data.gas = static_cast(m_gas); + m_data.gas = static_cast(io_gas); m_data.gasPrice = static_cast(_ext.gasPrice); m_data.callData = _ext.data.data(); m_data.callDataSize = _ext.data.size(); @@ -80,7 +78,7 @@ bytesConstRef JitVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) break; } - m_gas = m_data.gas; // TODO: Remove m_gas field + io_gas = m_data.gas; return {std::get<0>(m_engine.returnData), std::get<1>(m_engine.returnData)}; } diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h index 58caa3648..797fe7e1c 100644 --- a/evmjit/libevmjit-cpp/JitVM.h +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -10,11 +10,10 @@ namespace eth class JitVM: public VMFace { - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; private: friend class VMFactory; - explicit JitVM(u256 _gas = 0) : VMFace(_gas) {} jit::RuntimeData m_data; jit::ExecutionEngine m_engine; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 2d8dbdc16..a856b9ef4 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -41,7 +41,7 @@ Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): u256 Executive::gasUsed() const { - return m_t.gas() - m_endGas; + return m_t.gas() - m_gas; } ExecutionResult Executive::executionResult() const @@ -133,26 +133,27 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen bigint g = it->second.gas(_data); if (_gas < g) { - m_endGas = 0; m_excepted = TransactionException::OutOfGasBase; // Bail from exception. return true; // true actually means "all finished - nothing more to be done regarding go(). } else { - m_endGas = (u256)(_gas - g); + m_gas = (u256)(_gas - g); m_precompiledOut = it->second.exec(_data); m_out = &m_precompiledOut; } } - else if (m_s.addressHasCode(_codeAddress)) + else { - m_vm = VMFactory::create(_gas); - bytes const& c = m_s.code(_codeAddress); - m_ext = make_shared(m_s, m_lastHashes, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth); + m_gas = _gas; + if (m_s.addressHasCode(_codeAddress)) + { + m_vm = VMFactory::create(); + bytes const& c = m_s.code(_codeAddress); + m_ext = make_shared(m_s, m_lastHashes, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth); + } } - else - m_endGas = _gas; m_s.transferBalance(_senderAddress, _receiveAddress, _value); @@ -166,11 +167,12 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g // We can allow for the reverted state (i.e. that with which m_ext is constructed) to contain the m_newAddress, since // we delete it explicitly if we decide we need to revert. m_newAddress = right160(sha3(rlpList(_sender, m_s.transactionsFrom(_sender) - 1))); + m_gas = _gas; // Execute _init. if (!_init.empty()) { - m_vm = VMFactory::create(_gas); + m_vm = VMFactory::create(); m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth); } @@ -178,10 +180,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g m_s.transferBalance(_sender, m_newAddress, _endowment); if (_init.empty()) - { m_s.m_cache[m_newAddress].setCode({}); - m_endGas = _gas; - } return !m_ext; } @@ -215,17 +214,16 @@ bool Executive::go(OnOpFunc const& _onOp) #endif try { - m_out = m_vm->go(*m_ext, _onOp); - m_endGas = m_vm->gas(); + m_out = m_vm->go(m_gas, *m_ext, _onOp); if (m_isCreation) { - m_gasForDeposit = m_endGas; + m_gasForDeposit = m_gas; m_depositSize = m_out.size(); - if (m_out.size() * c_createDataGas <= m_endGas) + if (m_out.size() * c_createDataGas <= m_gas) { m_codeDeposit = CodeDeposit::Success; - m_endGas -= m_out.size() * c_createDataGas; + m_gas -= m_out.size() * c_createDataGas; } else { @@ -243,7 +241,7 @@ bool Executive::go(OnOpFunc const& _onOp) catch (VMException const& _e) { clog(StateSafeExceptions) << "Safe VM Exception. " << diagnostic_information(_e); - m_endGas = 0; + m_gas = 0; m_excepted = toTransactionException(_e); m_ext->revert(); } @@ -273,12 +271,12 @@ void Executive::finalize() // SSTORE refunds... // must be done before the miner gets the fees. if (m_ext) - m_endGas += min((m_t.gas() - m_endGas) / 2, m_ext->sub.refunds); + m_gas += min((m_t.gas() - m_gas) / 2, m_ext->sub.refunds); // cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")"; - m_s.addBalance(m_t.sender(), m_endGas * m_t.gasPrice()); + m_s.addBalance(m_t.sender(), m_gas * m_t.gasPrice()); - u256 feesEarned = (m_t.gas() - m_endGas) * m_t.gasPrice(); + u256 feesEarned = (m_t.gas() - m_gas) * m_t.gasPrice(); m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); // Suicides... diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 8903fd464..6057659fa 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -99,14 +99,14 @@ public: void accrueSubState(SubState& _parentContext); /// Executes (or continues execution of) the VM. - /// @returns false iff go() must be called again to finish the transction. + /// @returns false iff go() must be called again to finish the transaction. bool go(OnOpFunc const& _onOp = OnOpFunc()); /// Operation function for providing a simple trace of the VM execution. static OnOpFunc simpleTrace(); - /// @returns gas remaining after the transaction/operation. - u256 endGas() const { return m_endGas; } + /// @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. @@ -132,7 +132,7 @@ private: 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_endGas; ///< The final amount of gas for the transaction. + u256 m_gas = 0; ///< The gas for EVM code execution. Initial amount before go() execution, final amount after go() execution. Transaction m_t; ///< The original transaction. Set by setup(). LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize(). diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index 68d146ce1..650200059 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -34,7 +34,7 @@ bool ExtVM::call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, e.go(_onOp); e.accrueSubState(sub); } - io_gas = e.endGas(); + io_gas = e.gas(); e.out().copyTo(_out); return !e.excepted(); @@ -51,7 +51,7 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc e.go(_onOp); e.accrueSubState(sub); } - io_gas = e.endGas(); + io_gas = e.gas(); return e.newAddress(); } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 853ac25f6..8f1b47c05 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -25,13 +25,6 @@ using namespace std; using namespace dev; using namespace dev::eth; -void VM::reset(u256 _gas) noexcept -{ - VMFace::reset(_gas); - m_curPC = 0; - m_jumpDests.clear(); -} - struct InstructionMetric { int gasPriceTier; @@ -52,8 +45,14 @@ static array metrics() return s_ret; } -bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { + // Reset leftovers from possible previous run + m_curPC = 0; + m_jumpDests.clear(); + + m_gas = io_gas; + m_stack.reserve((unsigned)c_stackLimit); static const array c_metrics = metrics(); @@ -200,11 +199,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) // _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); if (m_gas < runGas) - { - // Out of gas! - m_gas = 0; BOOST_THROW_EXCEPTION(OutOfGas()); - } m_gas = (u256)((bigint)m_gas - runGas); @@ -655,6 +650,7 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) unsigned s = (unsigned)m_stack.back(); m_stack.pop_back(); + io_gas = m_gas; return bytesConstRef(m_temp.data() + b, s); } case Instruction::SUICIDE: @@ -664,9 +660,12 @@ bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) // ...follow through to... } case Instruction::STOP: + io_gas = m_gas; return bytesConstRef(); } } + + io_gas = m_gas; if (_steps == (uint64_t)-1) BOOST_THROW_EXCEPTION(StepsDone()); return bytesConstRef(); diff --git a/libevm/VM.h b/libevm/VM.h index 30007e0b3..a73142dad 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -52,14 +52,13 @@ inline u256 fromAddress(Address _a) class VM: public VMFace { public: - virtual void reset(u256 _gas = 0) noexcept override final; - - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; 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 curPC() const { return m_curPC; } + u256 gas() const { return m_gas; } bytes const& memory() const { return m_temp; } u256s const& stack() const { return m_stack; } @@ -67,10 +66,8 @@ public: private: friend class VMFactory; - /// Construct VM object. - explicit VM(u256 _gas): VMFace(_gas) {} - u256 m_curPC = 0; + u256 m_gas = 0; bytes m_temp; u256s m_stack; std::set m_jumpDests; diff --git a/libevm/VMFace.h b/libevm/VMFace.h index d2689d13e..d2a12e0ca 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -38,18 +38,12 @@ struct StackUnderflow: virtual VMException {}; class VMFace { public: - explicit VMFace(u256 _gas): m_gas(_gas) {} + VMFace() = default; virtual ~VMFace() = default; VMFace(VMFace const&) = delete; VMFace& operator=(VMFace const&) = delete; - virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; } - u256 gas() const noexcept { return m_gas; } - - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; - -protected: - u256 m_gas = 0; + virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; }; } diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp index 1092906e4..4b9df6a73 100644 --- a/libevm/VMFactory.cpp +++ b/libevm/VMFactory.cpp @@ -37,13 +37,13 @@ void VMFactory::setKind(VMKind _kind) g_kind = _kind; } -std::unique_ptr VMFactory::create(u256 _gas) +std::unique_ptr VMFactory::create() { #if ETH_EVMJIT - return std::unique_ptr(g_kind == VMKind::JIT ? static_cast(new JitVM(_gas)) : static_cast(new VM(_gas))); + return std::unique_ptr(g_kind == VMKind::JIT ? static_cast(new JitVM) : static_cast(new VM)); #else asserts(g_kind == VMKind::Interpreter && "JIT disabled in build configuration"); - return std::unique_ptr(new VM(_gas)); + return std::unique_ptr(new VM); #endif } diff --git a/libevm/VMFactory.h b/libevm/VMFactory.h index d0d02e0c4..6d2762dfc 100644 --- a/libevm/VMFactory.h +++ b/libevm/VMFactory.h @@ -34,7 +34,7 @@ class VMFactory public: VMFactory() = delete; - static std::unique_ptr create(u256 _gas); + static std::unique_ptr create(); static void setKind(VMKind _kind); }; diff --git a/test/fuzzTesting/checkRandomVMTest.cpp b/test/fuzzTesting/checkRandomVMTest.cpp index e22cb9361..13d677e17 100644 --- a/test/fuzzTesting/checkRandomVMTest.cpp +++ b/test/fuzzTesting/checkRandomVMTest.cpp @@ -94,13 +94,11 @@ bool doVMTest(mValue& _v) } bytes output; - u256 gas; bool vmExceptionOccured = false; try { - auto vm = eth::VMFactory::create(fev.gas); - output = vm->go(fev, fev.simpleTrace()).toBytes(); - gas = vm->gas(); + auto vm = eth::VMFactory::create(); + output = vm->go(fev.gas, fev, fev.simpleTrace()).toBytes(); } catch (eth::VMException) { @@ -168,7 +166,7 @@ bool doVMTest(mValue& _v) return 1; } - if (asserts(toInt(o["gas"]) == gas)) + if (asserts(toInt(o["gas"]) == fev.gas)) return 1; auto& expectedAddrs = test.addresses; diff --git a/test/fuzzTesting/createRandomVMTest.cpp b/test/fuzzTesting/createRandomVMTest.cpp index bad854718..3196590d4 100644 --- a/test/fuzzTesting/createRandomVMTest.cpp +++ b/test/fuzzTesting/createRandomVMTest.cpp @@ -155,14 +155,12 @@ void doMyTests(json_spirit::mValue& _v) } bytes output; - auto vm = eth::VMFactory::create(fev.gas); + auto vm = eth::VMFactory::create(); - u256 gas; bool vmExceptionOccured = false; try { - output = vm->go(fev, fev.simpleTrace()).toBytes(); - gas = vm->gas(); + output = vm->go(fev.gas, fev, fev.simpleTrace()).toBytes(); } catch (eth::VMException const& _e) { @@ -201,7 +199,7 @@ void doMyTests(json_spirit::mValue& _v) o["post"] = mValue(fev.exportState()); o["callcreates"] = fev.exportCallCreates(); o["out"] = toHex(output, 2, HexPrefix::Add); - o["gas"] = toCompactHex(gas, HexPrefix::Add, 1); + o["gas"] = toCompactHex(fev.gas, HexPrefix::Add, 1); o["logs"] = test::exportLog(fev.sub.logs); } } diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 8b5a7c5d3..53a49f5c4 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -322,19 +322,17 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) } bytes output; - u256 gas; bool vmExceptionOccured = false; try { - auto vm = eth::VMFactory::create(fev.gas); + 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, vmtrace); + outputRef = vm->go(fev.gas, fev, vmtrace); } output = outputRef.toBytes(); - gas = vm->gas(); } catch (VMException const&) { @@ -389,7 +387,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) o["callcreates"] = fev.exportCallCreates(); o["out"] = toHex(output, 2, HexPrefix::Add); - o["gas"] = toCompactHex(gas, HexPrefix::Add, 1); + o["gas"] = toCompactHex(fev.gas, HexPrefix::Add, 1); o["logs"] = exportLog(fev.sub.logs); } } @@ -412,7 +410,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) checkOutput(output, o); - BOOST_CHECK_EQUAL(toInt(o["gas"]), gas); + BOOST_CHECK_EQUAL(toInt(o["gas"]), fev.gas); State postState, expectState; mObject mPostState = fev.exportState(); From 5b4a3e1f60af0447ef0bd89b6898d7d6977c1f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 11 May 2015 15:47:34 +0200 Subject: [PATCH 02/90] Remove gas counter from interpreter VM. OnOp callback signature changed. --- alethzero/Debugger.cpp | 4 ++-- eth/main.cpp | 12 ++++++------ libethereum/Executive.cpp | 4 ++-- libevm/ExtVMFace.h | 2 +- libevm/VM.cpp | 20 ++++++-------------- libevm/VM.h | 2 -- mix/MixClient.cpp | 4 ++-- test/libevm/vm.cpp | 6 +++--- 8 files changed, 22 insertions(+), 32 deletions(-) diff --git a/alethzero/Debugger.cpp b/alethzero/Debugger.cpp index a1d246a21..21ef3b711 100644 --- a/alethzero/Debugger.cpp +++ b/alethzero/Debugger.cpp @@ -82,7 +82,7 @@ bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transacti bytesConstRef lastData; h256 lastHash; h256 lastDataHash; - auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, VM* voidVM, ExtVMFace const* voidExt) + auto onOp = [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, VM* voidVM, ExtVMFace const* voidExt) { VM& vm = *voidVM; ExtVM const& ext = *static_cast(voidExt); @@ -104,7 +104,7 @@ bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transacti levels.push_back(&history.back()); else levels.resize(ext.depth); - history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); + history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, (u256)gas, lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); }; _executive.go(onOp); _executive.finalize(); diff --git a/eth/main.cpp b/eth/main.cpp index cb051aad1..807fd4c50 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -1462,7 +1462,7 @@ int main(int argc, char** argv) { OnOpFunc oof; if (format == "pretty") - oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) + oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) { dev::eth::VM* vm = vvm; dev::eth::ExtVM const* ext = static_cast(vextVM); @@ -1473,24 +1473,24 @@ int main(int argc, char** argv) f << " STORAGE" << endl; for (auto const& i: ext->state().storage(ext->myAddress)) f << showbase << hex << i.first << ": " << i.second << endl; - f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32"; + f << dec << ext->depth << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << dev::eth::instructionInfo(instr).name << " | " << dec << gas << " | -" << dec << gasCost << " | " << newMemSize << "x32"; }; else if (format == "standard") - oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) + oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) { dev::eth::VM* vm = vvm; dev::eth::ExtVM const* ext = static_cast(vextVM); - f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; + f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl; }; else if (format == "standard+") - oof = [&](uint64_t, Instruction instr, bigint, bigint, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) + oof = [&](uint64_t, Instruction instr, bigint, bigint, bigint gas, dev::eth::VM* vvm, dev::eth::ExtVMFace const* vextVM) { dev::eth::VM* vm = vvm; dev::eth::ExtVM const* ext = static_cast(vextVM); if (instr == Instruction::STOP || instr == Instruction::RETURN || instr == Instruction::SUICIDE) for (auto const& i: ext->state().storage(ext->myAddress)) f << toHex(dev::toCompactBigEndian(i.first, 1)) << " " << toHex(dev::toCompactBigEndian(i.second, 1)) << endl; - f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; + f << ext->myAddress << " " << hex << toHex(dev::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(dev::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(dev::toCompactBigEndian((uint64_t)gas, 1)) << endl; }; e.initialize(t); if (!e.execute()) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index a856b9ef4..ecfdd7721 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -187,7 +187,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g OnOpFunc Executive::simpleTrace() { - return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, VM* voidVM, ExtVMFace const* voidExt) + 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; @@ -201,7 +201,7 @@ OnOpFunc Executive::simpleTrace() for (auto const& i: ext.state().storage(ext.myAddress)) o << showbase << hex << i.first << ": " << i.second << endl; dev::LogOutputStream() << o.str(); - dev::LogOutputStream() << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps << " : " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " : " << dec << vm.gas() << " : -" << dec << gasCost << " : " << newMemSize << "x32" << " >"; + dev::LogOutputStream() << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps << " : " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " : " << dec << gas << " : -" << dec << gasCost << " : " << newMemSize << "x32" << " >"; }; } diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 48fbd0b01..4bbdb36ac 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -106,7 +106,7 @@ class VM; using LastHashes = std::vector; -using OnOpFunc = std::function; +using OnOpFunc = std::function; /** * @brief Interface and null implementation of the class for specifying VM externalities. diff --git a/libevm/VM.cpp b/libevm/VM.cpp index 8f1b47c05..695b556dd 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -51,8 +51,6 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 m_curPC = 0; m_jumpDests.clear(); - m_gas = io_gas; - m_stack.reserve((unsigned)c_stackLimit); static const array c_metrics = metrics(); @@ -97,7 +95,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 auto onOperation = [&]() { if (_onOp) - _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); + _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, io_gas, this, &_ext); }; switch (inst) @@ -195,13 +193,11 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 runGas += c_copyGas * ((copySize + 31) / 32); onOperation(); -// if (_onOp) -// _onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, this, &_ext); - if (m_gas < runGas) + if (io_gas < runGas) BOOST_THROW_EXCEPTION(OutOfGas()); - m_gas = (u256)((bigint)m_gas - runGas); + io_gas = (u256)((bigint)io_gas - runGas); if (newTempSize > m_temp.size()) m_temp.resize((size_t)newTempSize); @@ -560,7 +556,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 m_stack.push_back(m_temp.size()); break; case Instruction::GAS: - m_stack.push_back(m_gas); + m_stack.push_back(io_gas); break; case Instruction::JUMPDEST: break; @@ -609,7 +605,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 m_stack.pop_back(); if (_ext.balance(_ext.myAddress) >= endowment && _ext.depth < 1024) - m_stack.push_back((u160)_ext.create(endowment, m_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); + m_stack.push_back((u160)_ext.create(endowment, io_gas, bytesConstRef(m_temp.data() + initOff, initSize), _onOp)); else m_stack.push_back(0); break; @@ -640,7 +636,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 else m_stack.push_back(0); - m_gas += gas; + io_gas += gas; break; } case Instruction::RETURN: @@ -649,8 +645,6 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 m_stack.pop_back(); unsigned s = (unsigned)m_stack.back(); m_stack.pop_back(); - - io_gas = m_gas; return bytesConstRef(m_temp.data() + b, s); } case Instruction::SUICIDE: @@ -660,12 +654,10 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 // ...follow through to... } case Instruction::STOP: - io_gas = m_gas; return bytesConstRef(); } } - io_gas = m_gas; if (_steps == (uint64_t)-1) BOOST_THROW_EXCEPTION(StepsDone()); return bytesConstRef(); diff --git a/libevm/VM.h b/libevm/VM.h index a73142dad..755d820fa 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -58,7 +58,6 @@ public: void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } u256 curPC() const { return m_curPC; } - u256 gas() const { return m_gas; } bytes const& memory() const { return m_temp; } u256s const& stack() const { return m_stack; } @@ -67,7 +66,6 @@ private: friend class VMFactory; u256 m_curPC = 0; - u256 m_gas = 0; bytes m_temp; u256s m_stack; std::set m_jumpDests; diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index b1d8f889e..853441490 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -132,7 +132,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c bytesConstRef const* lastData = nullptr; unsigned codeIndex = 0; unsigned dataIndex = 0; - auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) + auto onOp = [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, void* voidVM, void const* voidExt) { VM& vm = *static_cast(voidVM); ExtVM const& ext = *static_cast(voidExt); @@ -169,7 +169,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c else levels.resize(ext.depth); - machineStates.emplace_back(MachineState({steps, vm.curPC(), inst, newMemSize, vm.gas(), + machineStates.emplace_back(MachineState({steps, vm.curPC(), inst, newMemSize, (u256)gas, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels, codeIndex, dataIndex})); }; diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 53a49f5c4..222a012f4 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -234,7 +234,7 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) eth::OnOpFunc FakeExtVM::simpleTrace() { - return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, dev::eth::VM* voidVM, dev::eth::ExtVMFace const* voidExt) + return [](uint64_t steps, eth::Instruction inst, bigint newMemSize, bigint gasCost, bigint gas, dev::eth::VM* voidVM, dev::eth::ExtVMFace const* voidExt) { FakeExtVM const& ext = *static_cast(voidExt); eth::VM& vm = *voidVM; @@ -250,7 +250,7 @@ eth::OnOpFunc FakeExtVM::simpleTrace() o << std::showbase << std::hex << i.first << ": " << i.second << std::endl; dev::LogOutputStream() << o.str(); - dev::LogOutputStream() << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << vm.gas() << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]"; + dev::LogOutputStream() << " | " << std::dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << std::hex << std::setw(4) << std::setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << std::dec << gas << " | -" << std::dec << gasCost << " | " << newMemSize << "x32" << " ]"; /*creates json stack trace*/ if (eth::VMTraceChannel::verbosity <= g_logVerbosity) @@ -279,7 +279,7 @@ eth::OnOpFunc FakeExtVM::simpleTrace() /*add all the other details*/ o_step.push_back(Pair("storage", storage)); o_step.push_back(Pair("depth", to_string(ext.depth))); - o_step.push_back(Pair("gas", (string)vm.gas())); + o_step.push_back(Pair("gas", (string)gas)); o_step.push_back(Pair("address", toString(ext.myAddress ))); o_step.push_back(Pair("step", steps )); o_step.push_back(Pair("pc", (int)vm.curPC())); From a202d2a633cf70d0dd8c5f9ae0ea0fed62893cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 12 May 2015 12:13:42 +0200 Subject: [PATCH 03/90] Update SmartVM to new VM interface (without gas counter) --- libevm/SmartVM.cpp | 10 ++++------ libevm/SmartVM.h | 4 +--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/libevm/SmartVM.cpp b/libevm/SmartVM.cpp index 4f759a745..7343bd7a2 100644 --- a/libevm/SmartVM.cpp +++ b/libevm/SmartVM.cpp @@ -41,7 +41,7 @@ namespace } } -bytesConstRef SmartVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) +bytesConstRef SmartVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { auto codeHash = sha3(_ext.code); auto vmKind = VMKind::Interpreter; // default VM @@ -66,11 +66,9 @@ bytesConstRef SmartVM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step } // TODO: Selected VM must be kept only because it returns reference to its internal memory. - // VM implementations should be stateless, without gas counter and escaping memory reference. - m_selectedVM = VMFactory::create(vmKind, gas()); - auto out = m_selectedVM->go(_ext, _onOp, _steps); - m_gas = m_selectedVM->gas(); - return out; + // VM implementations should be stateless, without escaping memory reference. + m_selectedVM = VMFactory::create(vmKind); + return m_selectedVM->go(io_gas, _ext, _onOp, _steps); } } diff --git a/libevm/SmartVM.h b/libevm/SmartVM.h index 29f464ecd..cc198c0c2 100644 --- a/libevm/SmartVM.h +++ b/libevm/SmartVM.h @@ -31,9 +31,7 @@ namespace eth class SmartVM: public VMFace { public: - SmartVM(u256 _gas): VMFace(_gas) {} - - virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; + virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; private: std::unique_ptr m_selectedVM; From 855d2f677c568b42aa38c0f230b57417b0d97885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 12 May 2015 14:29:06 +0200 Subject: [PATCH 04/90] VM cleanups --- evmjit/libevmjit-cpp/JitVM.h | 3 +-- libevm/VM.h | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/evmjit/libevmjit-cpp/JitVM.h b/evmjit/libevmjit-cpp/JitVM.h index 797fe7e1c..e6864f885 100644 --- a/evmjit/libevmjit-cpp/JitVM.h +++ b/evmjit/libevmjit-cpp/JitVM.h @@ -10,11 +10,10 @@ 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; private: - friend class VMFactory; - jit::RuntimeData m_data; jit::ExecutionEngine m_engine; std::unique_ptr m_fallbackVM; ///< VM used in case of input data rejected by JIT diff --git a/libevm/VM.h b/libevm/VM.h index 755d820fa..8a641b1b8 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -54,16 +54,14 @@ class VM: public VMFace public: virtual bytesConstRef go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; - 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 curPC() const { return m_curPC; } bytes const& memory() const { return m_temp; } u256s const& stack() const { return m_stack; } private: - friend class VMFactory; + 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; bytes m_temp; From b9133db9fb84a4c4f0c6d066cbefcefd5e369814 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 15 May 2015 16:46:02 +0200 Subject: [PATCH 05/90] printf logging for ethash_full_new() errors --- internal.c | 12 +++++++++++- io.c | 18 ++++++++++++++++-- io.h | 13 +++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/internal.c b/internal.c index e881e0c7b..ec2275f32 100644 --- a/internal.c +++ b/internal.c @@ -400,38 +400,48 @@ ethash_full_t ethash_full_new_internal( ret->file_size = (size_t)full_size; switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) { case ETHASH_IO_FAIL: + // ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case goto fail_free_full; case ETHASH_IO_MEMO_MATCH: if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); goto fail_close_file; } return ret; case ETHASH_IO_MEMO_SIZE_MISMATCH: // if a DAG of same filename but unexpected size is found, silently force new file creation if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) { + ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size."); goto fail_free_full; } // fallthrough to the mismatch case here, DO NOT go through match case ETHASH_IO_MEMO_MISMATCH: if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); goto fail_close_file; } break; } if (!ethash_compute_full_data(ret->data, full_size, light, callback)) { + ETHASH_CRITICAL("Failure at computing DAG data."); goto fail_free_full_data; } // after the DAG has been filled then we finalize it by writting the magic number at the beginning if (fseek(f, 0, SEEK_SET) != 0) { + ETHASH_CRITICAL("Could not seek to DAG file start to write magic number."); goto fail_free_full_data; } uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM; if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + ETHASH_CRITICAL("Could not write magic number to DAG's beginning."); + goto fail_free_full_data; + } + if (fflush(f) != 0) {// make sure the magic number IS there + ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?"); goto fail_free_full_data; } - fflush(f); // make sure the magic number IS there return ret; fail_free_full_data: diff --git a/io.c b/io.c index 5b4e7da2b..f53827ee0 100644 --- a/io.c +++ b/io.c @@ -35,12 +35,14 @@ enum ethash_io_rc ethash_io_prepare( // assert directory exists if (!ethash_mkdir(dirname)) { + ETHASH_CRITICAL("Could not create the ethash directory"); goto end; } ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name); char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name)); if (!tmpfile) { + ETHASH_CRITICAL("Could not create the full DAG pathname"); goto end; } @@ -52,6 +54,7 @@ enum ethash_io_rc ethash_io_prepare( size_t found_size; if (!ethash_file_size(f, &found_size)) { fclose(f); + ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile); goto free_memo; } if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) { @@ -64,6 +67,7 @@ enum ethash_io_rc ethash_io_prepare( if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { // I/O error fclose(f); + ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile); ret = ETHASH_IO_MEMO_SIZE_MISMATCH; goto free_memo; } @@ -80,15 +84,25 @@ enum ethash_io_rc ethash_io_prepare( // file does not exist, will need to be created f = ethash_fopen(tmpfile, "wb+"); if (!f) { + ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile); goto free_memo; } // make sure it's of the proper size if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) { fclose(f); + ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fputc('\n', f) == EOF) { + fclose(f); + ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fflush(f) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile); goto free_memo; } - fputc('\n', f); - fflush(f); ret = ETHASH_IO_MEMO_MISMATCH; goto set_file; diff --git a/io.h b/io.h index 05aa5ed37..58ec90a9e 100644 --- a/io.h +++ b/io.h @@ -54,6 +54,19 @@ enum ethash_io_rc { #define snprintf(...) sprintf_s(__VA_ARGS__) #endif +/** + * Logs a critical error in important parts of ethash. Should mostly help + * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL + * ethash_full_t + */ +#define ETHASH_CRITICAL(...) \ + do \ + { \ + printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) + /** * Prepares io for ethash * From d4a4b6e2850a1df8247939119f3812477e1659b3 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sun, 17 May 2015 17:29:38 +0200 Subject: [PATCH 06/90] Using errno to detect ethash_io failures - Printf debug output is still printed by ethash itself unless one compiles with -DETHASH_NO_CRITICAL_OUTPUT. --- internal.c | 1 + io.c | 3 +++ io.h | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/internal.c b/internal.c index ec2275f32..b28a59e43 100644 --- a/internal.c +++ b/internal.c @@ -364,6 +364,7 @@ static bool ethash_mmap(struct ethash_full* ret, FILE* f) { int fd; char* mmapped_data; + errno = 0; ret->file = f; if ((fd = ethash_fileno(ret->file)) == -1) { return false; diff --git a/io.c b/io.c index f53827ee0..f4db477c2 100644 --- a/io.c +++ b/io.c @@ -21,6 +21,7 @@ #include "io.h" #include #include +#include enum ethash_io_rc ethash_io_prepare( char const* dirname, @@ -32,6 +33,8 @@ enum ethash_io_rc ethash_io_prepare( { char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE]; enum ethash_io_rc ret = ETHASH_IO_FAIL; + // reset errno before io calls + errno = 0; // assert directory exists if (!ethash_mkdir(dirname)) { diff --git a/io.h b/io.h index 58ec90a9e..da35eacba 100644 --- a/io.h +++ b/io.h @@ -59,6 +59,7 @@ enum ethash_io_rc { * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL * ethash_full_t */ +#ifndef ETHASH_NO_CRITICAL_OUTPUT #define ETHASH_CRITICAL(...) \ do \ { \ @@ -66,6 +67,9 @@ enum ethash_io_rc { printf("\n"); \ fflush(stdout); \ } while (0) +#else +#define ETHASH_CRITICAL(...) +#endif /** * Prepares io for ethash From c11326c22189c3a72af90820cf97d58ef2b7780c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 18 May 2015 11:37:31 +0200 Subject: [PATCH 07/90] Ethash critical output should be disabled by default - If the user needs it simply compile with -DETHASH_PRINT_CRITICAL_OUTPUT --- io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io.h b/io.h index da35eacba..7a27089c7 100644 --- a/io.h +++ b/io.h @@ -59,7 +59,7 @@ enum ethash_io_rc { * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL * ethash_full_t */ -#ifndef ETHASH_NO_CRITICAL_OUTPUT +#ifdef ETHASH_PRINT_CRITICAL_OUTPUT #define ETHASH_CRITICAL(...) \ do \ { \ From 259dc9a63bd8aebbea8d8a57116dca93906ab000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 20 May 2015 18:16:18 +0200 Subject: [PATCH 08/90] testeth: let expected be expected. --- test/libevm/vm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index d00396472..f60ca44ce 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -422,7 +422,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) checkAddresses, bytes> > >(test.addresses, fev.addresses); - checkCallCreates(fev.callcreates, test.callcreates); + checkCallCreates(test.callcreates, fev.callcreates); checkLog(fev.sub.logs, test.sub.logs); } From bede7bcf104d753e1ed01bdec0bbf2d31441382c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Wed, 20 May 2015 18:22:54 +0200 Subject: [PATCH 09/90] Simplify gas related expression. NFC. --- libevm/VM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libevm/VM.cpp b/libevm/VM.cpp index f1bfc1f8a..101b210b7 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -199,7 +199,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6 if (io_gas < runGas) BOOST_THROW_EXCEPTION(OutOfGas()); - io_gas = (u256)((bigint)io_gas - runGas); + io_gas -= (u256)runGas; if (newTempSize > m_temp.size()) m_temp.resize((size_t)newTempSize); From 3a3647c9f0f77d04a27c4005bc24f3c74aeaac7f Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 20 May 2015 21:54:35 +0200 Subject: [PATCH 10/90] Guard use of m_writeQueue operator[]. --- libp2p/Session.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 8f395158b..1c037e783 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -319,10 +319,14 @@ void Session::send(bytes&& _msg) void Session::write() { - const bytes& bytes = m_writeQueue[0]; - m_io->writeSingleFramePacket(&bytes, m_writeQueue[0]); + bytes *out; + DEV_GUARDED(x_writeQueue) + { + m_io->writeSingleFramePacket(&m_writeQueue[0], m_writeQueue[0]); + out = &m_writeQueue[0]; + } auto self(shared_from_this()); - ba::async_write(m_socket, ba::buffer(bytes), [this, self](boost::system::error_code ec, std::size_t /*length*/) + ba::async_write(m_socket, ba::buffer(*out), [this, self](boost::system::error_code ec, std::size_t /*length*/) { ThreadContext tc(info().id.abridged()); ThreadContext tc2(info().clientVersion); From 012ffd4adc9cead57b021445cfa3d8267da5b951 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 21 May 2015 02:02:57 +0200 Subject: [PATCH 11/90] retain session when interacting with capability --- libethereum/EthereumHost.cpp | 35 +++++++++++++++++++++-------------- libethereum/EthereumHost.h | 2 +- libp2p/HostCapability.cpp | 4 ++-- libp2p/HostCapability.h | 2 +- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index d62d6716f..43af332c6 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -189,7 +189,7 @@ void EthereumHost::maintainTransactions() for (auto const& i: ts) { bool unsent = !m_transactionsSent.count(i.first); - for (auto const& p: randomSelection(0, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }).second) + for (auto const& p: get<1>(randomSelection(0, [&](EthereumPeer* p) { return p->m_requireTransactions || (unsent && !p->m_knownTransactions.count(i.first)); }))) peerTransactions[p].push_back(i.first); } for (auto const& t: ts) @@ -218,25 +218,32 @@ void EthereumHost::maintainTransactions() } } -pair>, vector>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow) +tuple>, vector>, list>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow) { - pair>, vector>> ret; - ret.second.reserve(peerSessions().size()); - for (auto const& j: peerSessions()) + vector> chosen; + vector> allowed; + list> sessions; + + auto ps = peerSessions(); + allowed.reserve(ps.size()); + for (auto const& j: ps) { auto pp = j.first->cap(); if (_allow(pp.get())) - ret.second.push_back(pp); + { + allowed.push_back(move(pp)); + sessions.push_back(move(j.first)); + } } - ret.second.reserve((peerSessions().size() * _percent + 99) / 100); - for (unsigned i = (peerSessions().size() * _percent + 99) / 100; i-- && ret.second.size();) + chosen.reserve((ps.size() * _percent + 99) / 100); + for (unsigned i = (ps.size() * _percent + 99) / 100; i-- && allowed.size();) { - unsigned n = rand() % ret.second.size(); - ret.first.push_back(std::move(ret.second[n])); - ret.second.erase(ret.second.begin() + n); + unsigned n = rand() % allowed.size(); + chosen.push_back(std::move(allowed[n])); + allowed.erase(allowed.begin() + n); } - return ret; + return make_tuple(chosen, allowed, sessions); } void EthereumHost::maintainBlocks(h256 const& _currentHash) @@ -254,7 +261,7 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash) h256s blocks = get<0>(m_chain.treeRoute(m_latestBlockSent, _currentHash, false, false, true)); auto s = randomSelection(25, [&](EthereumPeer* p){ DEV_GUARDED(p->x_knownBlocks) return !p->m_knownBlocks.count(_currentHash); return false; }); - for (shared_ptr const& p: s.first) + for (shared_ptr const& p: get<0>(s)) for (auto const& b: blocks) { RLPStream ts; @@ -264,7 +271,7 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash) p->sealAndSend(ts); p->m_knownBlocks.clear(); } - for (shared_ptr const& p: s.second) + for (shared_ptr const& p: get<1>(s)) { RLPStream ts; p->prep(ts, NewBlockHashesPacket, blocks.size()); diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 95c7f147a..e8f7a0bad 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -80,7 +80,7 @@ public: void noteNewBlocks() { m_newBlocks = true; } private: - std::pair>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); + std::tuple>, std::vector>, std::list>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); /// Session is tell us that we may need (re-)syncing with the peer. void noteNeedsSyncing(EthereumPeer* _who); diff --git a/libp2p/HostCapability.cpp b/libp2p/HostCapability.cpp index b2acdcd1b..5f097875e 100644 --- a/libp2p/HostCapability.cpp +++ b/libp2p/HostCapability.cpp @@ -27,10 +27,10 @@ using namespace std; using namespace dev; using namespace dev::p2p; -std::vector,std::shared_ptr>> HostCapabilityFace::peerSessions() const +std::vector, std::shared_ptr>> HostCapabilityFace::peerSessions() const { RecursiveGuard l(m_host->x_sessions); - std::vector,std::shared_ptr>> ret; + std::vector, std::shared_ptr>> ret; for (auto const& i: m_host->m_sessions) if (std::shared_ptr s = i.second.lock()) if (s->m_capabilities.count(capDesc())) diff --git a/libp2p/HostCapability.h b/libp2p/HostCapability.h index 93086b1c9..668bcb929 100644 --- a/libp2p/HostCapability.h +++ b/libp2p/HostCapability.h @@ -45,7 +45,7 @@ public: Host* host() const { return m_host; } - std::vector,std::shared_ptr>> peerSessions() const; + std::vector, std::shared_ptr>> peerSessions() const; protected: virtual std::string name() const = 0; From 922c7055b766de9b62a0fb7b17c691bd7c03b48c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 21 May 2015 10:26:12 +0200 Subject: [PATCH 12/90] Fix Executive::call(CallParameters). --- libethereum/Executive.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 0bf8bdbb5..ca7a5a38a 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -163,14 +163,12 @@ bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _sen bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address const& _origin) { m_isCreation = false; -// cnote << "Transferring" << formatBalance(_value) << "to receiver."; auto it = !(_p.codeAddress & ~h160(0xffffffff)) ? precompiled().find((unsigned)(u160)_p.codeAddress) : precompiled().end(); if (it != precompiled().end()) { bigint g = it->second.gas(_p.data); if (_p.gas < g) { - m_gas = 0; m_excepted = TransactionException::OutOfGasBase; // Bail from exception. return true; // true actually means "all finished - nothing more to be done regarding go(). @@ -182,14 +180,16 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co m_out = &m_precompiledOut; } } - else if (m_s.addressHasCode(_p.codeAddress)) - { - m_vm = VMFactory::create(); - 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); - } else + { m_gas = _p.gas; + if (m_s.addressHasCode(_p.codeAddress)) + { + m_vm = VMFactory::create(); + 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); + } + } m_s.transferBalance(_p.senderAddress, _p.receiveAddress, _p.value); From 33dd3f2e2bc6e4631faf088de4cf64df7b7ccca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 21 May 2015 11:01:19 +0200 Subject: [PATCH 13/90] Fix code duplication in Executive::call overloadings. --- libethereum/Client.cpp | 2 +- libethereum/Executive.cpp | 39 ++----------------- libethereum/Executive.h | 2 +- test/libsolidity/solidityExecutionFramework.h | 2 +- 4 files changed, 7 insertions(+), 38 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index e372e611a..6dec81b38 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -440,7 +440,7 @@ 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); - if (!e.call(_dest, _dest, _from, _value, _gasPrice, &_data, _gas, _from)) + if (!e.call(_dest, _from, _value, _gasPrice, &_data, _gas)) e.go(); ret = e.executionResult(); } diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index ca7a5a38a..d7bad0ff9 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -120,44 +120,13 @@ bool Executive::execute() if (m_t.isCreation()) return create(m_t.sender(), m_t.value(), m_t.gasPrice(), m_t.gas() - (u256)m_t.gasRequired(), &m_t.data(), m_t.sender()); else - return call(m_t.receiveAddress(), m_t.receiveAddress(), m_t.sender(), m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)m_t.gasRequired(), m_t.sender()); + return call(m_t.receiveAddress(), m_t.sender(), m_t.value(), m_t.gasPrice(), bytesConstRef(&m_t.data()), m_t.gas() - (u256)m_t.gasRequired()); } -bool Executive::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas, Address _originAddress) +bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256 _gas) { - m_isCreation = false; -// cnote << "Transferring" << formatBalance(_value) << "to receiver."; - auto it = !(_codeAddress & ~h160(0xffffffff)) ? precompiled().find((unsigned)(u160)_codeAddress) : precompiled().end(); - if (it != precompiled().end()) - { - bigint g = it->second.gas(_data); - if (_gas < g) - { - m_excepted = TransactionException::OutOfGasBase; - // Bail from exception. - return true; // true actually means "all finished - nothing more to be done regarding go(). - } - else - { - m_gas = (u256)(_gas - g); - m_precompiledOut = it->second.exec(_data); - m_out = &m_precompiledOut; - } - } - else - { - m_gas = _gas; - if (m_s.addressHasCode(_codeAddress)) - { - m_vm = VMFactory::create(); - bytes const& c = m_s.code(_codeAddress); - m_ext = make_shared(m_s, m_lastHashes, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_depth); - } - } - - m_s.transferBalance(_senderAddress, _receiveAddress, _value); - - return !m_ext; + CallParameters params{_senderAddress, _receiveAddress, _receiveAddress, _gas, _value, _data, {}, {}}; + return call(params, _gasPrice, _senderAddress); } bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address const& _origin) diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 6f72d0966..04d5857b3 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -94,7 +94,7 @@ public: bool create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress); /// Set up the executive for evaluating a bare CALL (message call) operation. /// @returns false iff go() must be called (and thus a VM execution in required). - bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress); + bool call(Address _receiveAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas); bool call(CallParameters const& _cp, u256 const& _gasPrice, Address const& _origin); /// Finalise an operation through accruing the substate into the parent context. void accrueSubState(SubState& _parentContext); diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index fa25fb12c..0f80e9f59 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -155,7 +155,7 @@ protected: else { BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + BOOST_REQUIRE(!executive.call(m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas)); } BOOST_REQUIRE(executive.go()); m_state.noteSending(m_sender); From 39c5cc45d49b9f23116164164109ed4c45329154 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 26 May 2015 14:56:18 +0200 Subject: [PATCH 14/90] fix #2012 --- eth/main.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index a57928e72..4ac462d64 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -628,7 +628,7 @@ int main(int argc, char** argv) nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(), netPrefs, &nodesState); - + auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); @@ -693,15 +693,18 @@ int main(int argc, char** argv) } if (keyManager.exists()) - while (masterPassword.empty()) - { - masterPassword = getPassword("Please enter your MASTER password: "); - if (!keyManager.load(masterPassword)) + if (!masterPassword.empty()) + keyManager.load(masterPassword); + else + while (masterPassword.empty()) { - cout << "Password invalid. Try again." << endl; - masterPassword.clear(); + masterPassword = getPassword("Please enter your MASTER password: "); + if (!keyManager.load(masterPassword)) + { + cout << "Password invalid. Try again." << endl; + masterPassword.clear(); + } } - } else { while (masterPassword.empty()) From ba6efaf40813e8d575adc8624caafdb0488ce63e Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 28 May 2015 14:43:46 +0200 Subject: [PATCH 15/90] Allow duplicate code removal for loops. --- libevmasm/Assembly.cpp | 10 ++-- libevmasm/BlockDeduplicator.cpp | 75 +++++++++++++++++++------- libevmasm/BlockDeduplicator.h | 16 ++++-- libsolidity/ArrayUtils.cpp | 14 ++++- test/libsolidity/SolidityOptimizer.cpp | 32 +++++++++++ 5 files changed, 116 insertions(+), 31 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 5cf3b787a..8c6591885 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -307,6 +307,11 @@ Assembly& Assembly::optimise(bool _enable) count = 0; copt << "Performing optimisation..."; + // This only modifies PushTags, we have to run again to actually remove code. + BlockDeduplicator dedup(m_items); + if (dedup.deduplicate()) + count++; + { ControlFlowGraph cfg(m_items); AssemblyItems optimisedItems; @@ -349,11 +354,6 @@ Assembly& Assembly::optimise(bool _enable) m_items = move(optimisedItems); count++; } - - // This only modifies PushTags, we have to run again to actually remove code. - BlockDeduplicator dedup(m_items); - if (dedup.deduplicate()) - count++; } } diff --git a/libevmasm/BlockDeduplicator.cpp b/libevmasm/BlockDeduplicator.cpp index eadbe1b40..d930ea22b 100644 --- a/libevmasm/BlockDeduplicator.cpp +++ b/libevmasm/BlockDeduplicator.cpp @@ -35,13 +35,33 @@ bool BlockDeduplicator::deduplicate() { // Compares indices based on the suffix that starts there, ignoring tags and stopping at // opcodes that stop the control flow. + + // Virtual tag that signifies "the current block" and which is used to optimise loops. + // We abort if this virtual tag actually exists. + AssemblyItem pushSelf(PushTag, u256(-4)); + if ( + std::count(m_items.cbegin(), m_items.cend(), pushSelf.tag()) || + std::count(m_items.cbegin(), m_items.cend(), pushSelf.pushTag()) + ) + return false; + function comparator = [&](size_t _i, size_t _j) { if (_i == _j) return false; - BlockIterator first(m_items.begin() + _i, m_items.end()); - BlockIterator second(m_items.begin() + _j, m_items.end()); + // To compare recursive loops, we have to already unify PushTag opcodes of the + // block's own tag. + AssemblyItem pushFirstTag(pushSelf); + AssemblyItem pushSecondTag(pushSelf); + + if (_i < m_items.size() && m_items.at(_i).type() == Tag) + pushFirstTag = m_items.at(_i).pushTag(); + if (_j < m_items.size() && m_items.at(_j).type() == Tag) + pushSecondTag = m_items.at(_j).pushTag(); + + BlockIterator first(m_items.begin() + _i, m_items.end(), &pushFirstTag, &pushSelf); + BlockIterator second(m_items.begin() + _j, m_items.end(), &pushSecondTag, &pushSelf); BlockIterator end(m_items.end(), m_items.end()); if (first != end && (*first).type() == Tag) @@ -52,27 +72,34 @@ bool BlockDeduplicator::deduplicate() return std::lexicographical_compare(first, end, second, end); }; - set> blocksSeen(comparator); - map tagReplacement; - for (size_t i = 0; i < m_items.size(); ++i) + size_t iterations = 0; + for (; ; ++iterations) { - if (m_items.at(i).type() != Tag) - continue; - auto it = blocksSeen.find(i); - if (it == blocksSeen.end()) - blocksSeen.insert(i); - else - tagReplacement[m_items.at(i).data()] = m_items.at(*it).data(); - } - - bool ret = false; - for (AssemblyItem& item: m_items) - if (item.type() == PushTag && tagReplacement.count(item.data())) + //@todo this should probably be optimized. + set> blocksSeen(comparator); + map tagReplacement; + for (size_t i = 0; i < m_items.size(); ++i) { - ret = true; - item.setData(tagReplacement.at(item.data())); + if (m_items.at(i).type() != Tag) + continue; + auto it = blocksSeen.find(i); + if (it == blocksSeen.end()) + blocksSeen.insert(i); + else + tagReplacement[m_items.at(i).data()] = m_items.at(*it).data(); } - return ret; + + bool changed = false; + for (AssemblyItem& item: m_items) + if (item.type() == PushTag && tagReplacement.count(item.data())) + { + changed = true; + item.setData(tagReplacement.at(item.data())); + } + if (!changed) + break; + } + return iterations > 0; } BlockDeduplicator::BlockIterator& BlockDeduplicator::BlockIterator::operator++() @@ -89,3 +116,11 @@ BlockDeduplicator::BlockIterator& BlockDeduplicator::BlockIterator::operator++() } return *this; } + +AssemblyItem const& BlockDeduplicator::BlockIterator::operator*() const +{ + if (replaceItem && replaceWith && *it == *replaceItem) + return *replaceWith; + else + return *it; +} diff --git a/libevmasm/BlockDeduplicator.h b/libevmasm/BlockDeduplicator.h index 8a82a1ed7..c48835fd4 100644 --- a/libevmasm/BlockDeduplicator.h +++ b/libevmasm/BlockDeduplicator.h @@ -47,19 +47,27 @@ public: bool deduplicate(); private: - /// Iterator that skips tags skips to the end if (all branches of) the control + /// Iterator that skips tags and skips to the end if (all branches of) the control /// flow does not continue to the next instruction. + /// If the arguments are supplied to the constructor, replaces items on the fly. struct BlockIterator: std::iterator { public: - BlockIterator(AssemblyItems::const_iterator _it, AssemblyItems::const_iterator _end): - it(_it), end(_end) { } + BlockIterator( + AssemblyItems::const_iterator _it, + AssemblyItems::const_iterator _end, + AssemblyItem const* _replaceItem = nullptr, + AssemblyItem const* _replaceWith = nullptr + ): + it(_it), end(_end), replaceItem(_replaceItem), replaceWith(_replaceWith) {} BlockIterator& operator++(); bool operator==(BlockIterator const& _other) const { return it == _other.it; } bool operator!=(BlockIterator const& _other) const { return it != _other.it; } - AssemblyItem const& operator*() const { return *it; } + AssemblyItem const& operator*() const; AssemblyItems::const_iterator it; AssemblyItems::const_iterator end; + AssemblyItem const* replaceItem; + AssemblyItem const* replaceWith; }; AssemblyItems& m_items; diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index 448e4da2a..397b098c4 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -364,7 +364,13 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const return; } // stack: end_pos pos - eth::AssemblyItem loopStart = m_context.newTag(); + + // jump to and return from the loop to allow for duplicate code removal + eth::AssemblyItem returnTag = m_context.pushNewTag(); + m_context << eth::Instruction::SWAP2 << eth::Instruction::SWAP1; + + // stack: end_pos pos + eth::AssemblyItem loopStart = m_context.appendJumpToNew(); m_context << loopStart; // check for loop condition m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 @@ -380,7 +386,11 @@ void ArrayUtils::clearStorageLoop(Type const& _type) const m_context.appendJumpTo(loopStart); // cleanup m_context << zeroLoopEnd; - m_context << eth::Instruction::POP; + m_context << eth::Instruction::POP << eth::Instruction::SWAP1; + // "return" + m_context << eth::Instruction::JUMP; + + m_context << returnTag; solAssert(m_context.getStackHeight() == stackHeightStart - 1, ""); } diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index 744fc48ae..827d8833a 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -1004,6 +1004,38 @@ BOOST_AUTO_TEST_CASE(block_deduplicator) BOOST_CHECK_EQUAL(pushTags.size(), 2); } +BOOST_AUTO_TEST_CASE(block_deduplicator_loops) +{ + AssemblyItems input{ + u256(0), + eth::Instruction::SLOAD, + AssemblyItem(PushTag, 1), + AssemblyItem(PushTag, 2), + eth::Instruction::JUMPI, + eth::Instruction::JUMP, + AssemblyItem(Tag, 1), + u256(5), + u256(6), + eth::Instruction::SSTORE, + AssemblyItem(PushTag, 1), + eth::Instruction::JUMP, + AssemblyItem(Tag, 2), + u256(5), + u256(6), + eth::Instruction::SSTORE, + AssemblyItem(PushTag, 2), + eth::Instruction::JUMP, + }; + BlockDeduplicator dedup(input); + dedup.deduplicate(); + + set pushTags; + for (AssemblyItem const& item: input) + if (item.type() == PushTag) + pushTags.insert(item.data()); + BOOST_CHECK_EQUAL(pushTags.size(), 1); +} + BOOST_AUTO_TEST_SUITE_END() } From b6f9d51cd622253352eec72517851dda5e6f8e4f Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 28 May 2015 16:20:50 +0200 Subject: [PATCH 16/90] Re-introduce string type. --- libsolidity/AST.cpp | 2 ++ libsolidity/ExpressionCompiler.cpp | 3 ++ libsolidity/Token.h | 2 +- libsolidity/Types.cpp | 20 +++++++---- libsolidity/Types.h | 22 +++++++++---- mix/CodeModel.cpp | 4 ++- mix/SolidityType.h | 1 + test/libsolidity/SolidityABIJSON.cpp | 27 +++++++++++++++ .../SolidityNameAndTypeResolution.cpp | 33 +++++++++++++++++++ 9 files changed, 100 insertions(+), 14 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 14884254e..248abfdb9 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -890,6 +890,8 @@ void IndexAccess::checkTypeRequirements(TypePointers const*) ArrayType const& type = dynamic_cast(*m_base->getType()); if (!m_index) BOOST_THROW_EXCEPTION(createTypeError("Index expression cannot be omitted.")); + if (type.isString()) + BOOST_THROW_EXCEPTION(createTypeError("Index access for string is not possible.")); m_index->expectType(IntegerType(256)); if (type.isByteArray()) m_type = make_shared(1); diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 2e513b7fc..5a9782858 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -824,7 +824,10 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) if (arrayType.getLocation() == ArrayType::Location::Storage) { if (arrayType.isByteArray()) + { + solAssert(!arrayType.isString(), "Index access to string is not allowed."); setLValue(_indexAccess); + } else setLValueToStorageItem(_indexAccess); } diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 8a373da34..bce16ed17 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -286,6 +286,7 @@ namespace solidity K(Bytes32, "bytes32", 0) \ K(Bytes, "bytes", 0) \ K(Byte, "byte", 0) \ + K(String, "string", 0) \ K(Address, "address", 0) \ K(Bool, "bool", 0) \ K(Real, "real", 0) \ @@ -312,7 +313,6 @@ namespace solidity K(Match, "match", 0) \ K(Of, "of", 0) \ K(Relocatable, "relocatable", 0) \ - T(String, "string", 0) \ K(Switch, "switch", 0) \ K(Throw, "throw", 0) \ K(Try, "try", 0) \ diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7577b83a1..0e9ea9876 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -145,6 +145,8 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) return make_shared(); else if (_typeToken == Token::Bytes) return make_shared(ArrayType::Location::Storage); + else if (_typeToken == Token::String) + return make_shared(ArrayType::Location::Storage, true); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); @@ -663,7 +665,7 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const // let us not allow assignment to memory arrays for now if (convertTo.getLocation() != Location::Storage) return false; - if (convertTo.isByteArray() != isByteArray()) + if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString()) return false; if (!getBaseType()->isImplicitlyConvertibleTo(*convertTo.getBaseType())) return false; @@ -684,8 +686,12 @@ bool ArrayType::operator==(Type const& _other) const if (_other.getCategory() != getCategory()) return false; ArrayType const& other = dynamic_cast(_other); - if (other.m_location != m_location || other.isByteArray() != isByteArray() || - other.isDynamicallySized() != isDynamicallySized()) + if ( + other.m_location != m_location || + other.isByteArray() != isByteArray() || + other.isString() != isString() || + other.isDynamicallySized() != isDynamicallySized() + ) return false; return isDynamicallySized() || getLength() == other.getLength(); } @@ -736,7 +742,9 @@ unsigned ArrayType::getSizeOnStack() const string ArrayType::toString() const { - if (isByteArray()) + if (isString()) + return "string"; + else if (isByteArray()) return "bytes"; string ret = getBaseType()->toString() + "["; if (!isDynamicallySized()) @@ -746,7 +754,7 @@ string ArrayType::toString() const TypePointer ArrayType::externalType() const { - if (m_isByteArray) + if (m_arrayKind != ArrayKind::Ordinary) return shared_from_this(); if (!m_baseType->externalType()) return TypePointer(); @@ -762,7 +770,7 @@ TypePointer ArrayType::externalType() const shared_ptr ArrayType::copyForLocation(ArrayType::Location _location) const { auto copy = make_shared(_location); - copy->m_isByteArray = m_isByteArray; + copy->m_arrayKind = m_arrayKind; if (m_baseType->getCategory() == Type::Category::Array) copy->m_baseType = dynamic_cast(*m_baseType).copyForLocation(_location); else diff --git a/libsolidity/Types.h b/libsolidity/Types.h index a69df964c..65f6e4474 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -367,10 +367,10 @@ public: virtual Category getCategory() const override { return Category::Array; } - /// Constructor for a byte array ("bytes") - explicit ArrayType(Location _location): + /// Constructor for a byte array ("bytes") and string. + explicit ArrayType(Location _location, bool _isString = false): m_location(_location), - m_isByteArray(true), + m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes), m_baseType(std::make_shared(1)) {} /// Constructor for a dynamically sized array type ("type[]") @@ -394,11 +394,17 @@ public: virtual u256 getStorageSize() const override; virtual unsigned getSizeOnStack() const override; virtual std::string toString() const override; - virtual MemberList const& getMembers() const override { return s_arrayTypeMemberList; } + virtual MemberList const& getMembers() const override + { + return isString() ? EmptyMemberList : s_arrayTypeMemberList; + } virtual TypePointer externalType() const override; Location getLocation() const { return m_location; } - bool isByteArray() const { return m_isByteArray; } + /// @returns true if this is a byte array or a string + bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; } + /// @returns true if this is a string + bool isString() const { return m_arrayKind == ArrayKind::String; } TypePointer const& getBaseType() const { solAssert(!!m_baseType, ""); return m_baseType;} u256 const& getLength() const { return m_length; } @@ -407,8 +413,12 @@ public: std::shared_ptr copyForLocation(Location _location) const; private: + /// String is interpreted as a subtype of Bytes. + enum class ArrayKind { Ordinary, Bytes, String }; + Location m_location; - bool m_isByteArray = false; ///< Byte arrays ("bytes") have different semantics from ordinary arrays. + ///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays. + ArrayKind m_arrayKind = ArrayKind::Ordinary; TypePointer m_baseType; bool m_hasDynamicLength = true; u256 m_length; diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 2b4e332c0..bfa4dada9 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -507,7 +507,9 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type) case Type::Category::Array: { ArrayType const* array = dynamic_cast(_type); - if (array->isByteArray()) + if (array->isString()) + r.type = SolidityType::Type::String; + else if (array->isByteArray()) r.type = SolidityType::Type::Bytes; else { diff --git a/mix/SolidityType.h b/mix/SolidityType.h index accdb14b4..75f47e7fa 100644 --- a/mix/SolidityType.h +++ b/mix/SolidityType.h @@ -45,6 +45,7 @@ struct SolidityType Bool, Address, Bytes, + String, Enum, Struct }; diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp index f9bf78d0a..f7390dc93 100644 --- a/test/libsolidity/SolidityABIJSON.cpp +++ b/test/libsolidity/SolidityABIJSON.cpp @@ -568,6 +568,33 @@ BOOST_AUTO_TEST_CASE(return_param_in_abi) checkInterface(sourceCode, interface); } +BOOST_AUTO_TEST_CASE(strings_and_arrays) +{ + // bug #1801 + char const* sourceCode = R"( + contract test { + function f(string a, bytes b, uint[] c) external {} + } + )"; + + char const* interface = R"( + [ + { + "constant" : false, + "name": "f", + "inputs": [ + { "name": "a", "type": "string" }, + { "name": "b", "type": "bytes" }, + { "name": "c", "type": "uint256[]" } + ], + "outputs": [], + "type" : "function" + } + ] + )"; + checkInterface(sourceCode, interface); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index c52bbf9de..48404aaac 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1783,6 +1783,39 @@ BOOST_AUTO_TEST_CASE(uninitialized_var) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(string) +{ + char const* sourceCode = R"( + contract C { + string s; + function f(string x) external { s = x; } + } + )"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(sourceCode)); +} + +BOOST_AUTO_TEST_CASE(string_index) +{ + char const* sourceCode = R"( + contract C { + string s; + function f() { var a = s[2]; } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + +BOOST_AUTO_TEST_CASE(string_length) +{ + char const* sourceCode = R"( + contract C { + string s; + function f() { var a = s.length; } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } From df3313046b1129aee39a62a6a50169c87f3071f4 Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 28 May 2015 17:05:52 +0200 Subject: [PATCH 17/90] - add validation for input parameters. - ui bug fix. --- mix/qml.qrc | 1 + mix/qml/QIntTypeView.qml | 7 +++ mix/qml/TransactionDialog.qml | 23 ++++++- mix/qml/js/InputValidator.js | 112 ++++++++++++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 mix/qml/js/InputValidator.js diff --git a/mix/qml.qrc b/mix/qml.qrc index c47a7254f..784404270 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -63,5 +63,6 @@ qml/js/Printer.js qml/js/ansi2html.js qml/js/NetworkDeployment.js + qml/js/InputValidator.js diff --git a/mix/qml/QIntTypeView.qml b/mix/qml/QIntTypeView.qml index a3c67aafc..c42e65654 100644 --- a/mix/qml/QIntTypeView.qml +++ b/mix/qml/QIntTypeView.qml @@ -21,8 +21,15 @@ Item clip: true selectByMouse: true text: value + anchors.fill: parent font.pointSize: dbgStyle.general.basicFontSize color: dbgStyle.general.basicColor + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: textinput.forceActiveFocus() + } } } } diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index e7fe22e51..a4c896d3f 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -6,6 +6,7 @@ import QtQuick.Window 2.0 import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.QEther 1.0 import "js/TransactionHelper.js" as TransactionHelper +import "js/InputValidator.js" as InputValidator import "." Dialog { @@ -503,10 +504,22 @@ Dialog { anchors.right: parent.right; Button { + text: qsTr("OK"); onClicked: { - close(); - accepted(); + var invalid = InputValidator.validate(paramsModel, paramValues); + if (invalid.length === 0) + { + close(); + accepted(); + } + else + { + errorDialog.text = qsTr("some parameters are invalid:\n"); + for (var k in invalid) + errorDialog.text += invalid[k].message + "\n"; + errorDialog.open(); + } } } @@ -514,6 +527,12 @@ Dialog { text: qsTr("Cancel"); onClicked: close(); } + + MessageDialog { + id: errorDialog + standardButtons: StandardButton.Ok + icon: StandardIcon.Critical + } } } } diff --git a/mix/qml/js/InputValidator.js b/mix/qml/js/InputValidator.js new file mode 100644 index 000000000..6e94dec6e --- /dev/null +++ b/mix/qml/js/InputValidator.js @@ -0,0 +1,112 @@ +var nbRegEx = new RegExp('^[0-9]+$'); +function validate(model, values) +{ + var inError = []; + for (var k in model) + { + if (values[model[k].name]) + { + var type = model[k].type.name; + var res; + if (type.indexOf("int") !== -1) + res = validateInt(type, values[model[k].name]); + else if (type.indexOf("bytes") !== -1) + res = validateBytes(type, values[model[k].name]); + else if (type.indexOf("bool") !== -1) + res = validateBool(type, values[model[k].name]); + else if (type.indexOf("address") !== -1) + res = validateAddress(type, values[model[k].name]); + else + res = validateAddress(type, values[model[k].name]); //we suppose that this is a ctr type. + if (!res.valid) + inError.push({ type: type, value: values, message: res.message }); + } + } + return inError; +} + +function validateInt(_type, _value) +{ + var ret = { valid: true, message: "" } + if (_value.indexOf("-") === 0) + { + _value = _value.substring(1); + if (_type.indexOf("uint") === -1) + { + ret.valid = false; + ret.message = "uint type cannot represent negative number"; + return false; + } + } + ret.valid = nbRegEx.test(_value); + if (!ret.valid) + ret.message = _value + " does not represent " + _type + " type."; + else + { + var t = _type.replace("uint", "").replace("int", ""); + var max = parseInt(t) / 4; + if (_value.length > max) + { + ret.valid = false; + ret.message = _type + " should not contains more than " + max + " digits"; + } + } + return ret; +} + +function validateAddress(_type, _value) +{ + var ret = { valid: true, message: "" } + if (_value.indexOf("<") === 0 && _value.indexOf(">") === _value.length - 1) + { + var v = _value.split(' - '); + console.log(JSON.stringify(v)); + if (v.length !== 2 || !nbRegEx.test(v[1].replace(">", ""))) // + { + ret.valid = false; + ret.message = _value + " is not a valid token for address type."; + } + } + else if (_value.indexOf("0x") !== 0) + { + ret.valid = false + ret.message = "Address type should start with 0x."; + } + else + { + _value = _value.substring(2); + if (_value.length !== 40) + { + ret.valid = false + ret.message = "Address type should contain 40 characters."; + } + } + return ret; +} + +function validateBytes(_type, _value) +{ + var ret = { valid: true, message: "" } + if (_value.length > parseInt(_type.replace("bytes", "")) ) + { + ret.valid = false; + ret.message = _type + " should not contains more than " + _type.replace("bytes", "") + " characters"; + } + return ret; +} + +function validateBool(_type, _value) +{ + var ret = { valid: true, message: "" } + if (_value !== "1" && _value !== "0") + { + ret.valid = false; + ret.message = _value + " is not in the correct bool format"; + } + return ret; +} + +function validateEnum(_type, _value) +{ +} + From b649409cbf5d798f0a4a4c05c4500332a91a8575 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 28 May 2015 22:13:30 +0200 Subject: [PATCH 18/90] Code review optimization. --- libethereum/EthereumHost.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 43af332c6..cea9339f2 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -224,7 +224,7 @@ tuple>, vector>, list> allowed; list> sessions; - auto ps = peerSessions(); + auto const& ps = peerSessions(); allowed.reserve(ps.size()); for (auto const& j: ps) { From 1482599e521d1406611969eceeb6e8c593a84544 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 29 May 2015 16:28:30 +0200 Subject: [PATCH 19/90] - Check uint, int input from c++. - Check address also by contract name. --- mix/QBigInt.cpp | 35 +++++++++++++++++++++++++++++++++++ mix/QBigInt.h | 3 +++ mix/qml/TransactionDialog.qml | 2 +- mix/qml/js/InputValidator.js | 29 +++++++++++++++++++++-------- 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/mix/QBigInt.cpp b/mix/QBigInt.cpp index 21d32a9c3..ee29cea43 100644 --- a/mix/QBigInt.cpp +++ b/mix/QBigInt.cpp @@ -57,3 +57,38 @@ QBigInt* QBigInt::divide(QBigInt* const& _value) const BigIntVariant toDivide = _value->internalValue(); return new QBigInt(boost::apply_visitor(mix::divide(), m_internalValue, toDivide)); } + +QVariantMap QBigInt::checkAgainst(QString const& _type) const +{ + QVariantMap ret; + QString type = _type; + QString capacity = type.replace("uint", "").replace("int", ""); + if (capacity.isEmpty()) + capacity = "256"; + bigint range = 256^(capacity.toInt() / 8); + bigint value = boost::get(this->internalValue()); + ret.insert("valid", true); + if (_type.startsWith("uint") && value > range - 1) + { + ret.insert("minValue", "0"); + std::ostringstream s; + s << range - 1; + ret.insert("maxValue", QString::fromStdString(s.str())); + if (value > range) + ret["valid"] = false; + } + else if (_type.startsWith("int")) + { + range = range / 2; + std::ostringstream s; + s << -range; + ret.insert("minValue", QString::fromStdString(s.str())); + s.str(""); + s.clear(); + s << range - 1; + ret.insert("maxValue", QString::fromStdString(s.str())); + if (-range > value || value > range - 1) + ret["valid"] = false; + } + return ret; +} diff --git a/mix/QBigInt.h b/mix/QBigInt.h index b549a16db..ccf487d2a 100644 --- a/mix/QBigInt.h +++ b/mix/QBigInt.h @@ -84,6 +84,7 @@ public: Q_INVOKABLE QString value() const; /// Set the value of the BigInteger used. Will use u256 type. Invokable from QML. Q_INVOKABLE void setValue(QString const& _value) { m_internalValue = dev::jsToU256(_value.toStdString()); } + Q_INVOKABLE void setBigInt(QString const& _value) { m_internalValue = bigint(_value.toStdString()); } /// Subtract by @a _value. Invokable from QML. Q_INVOKABLE QBigInt* subtract(QBigInt* const& _value) const; /// Add @a _value to the current big integer. Invokable from QML. @@ -92,6 +93,8 @@ public: Q_INVOKABLE QBigInt* multiply(QBigInt* const& _value) const; /// divide by @a _value. Invokable from QML. Q_INVOKABLE QBigInt* divide(QBigInt* const& _value) const; + /// check if the current value satisfy the given type + Q_INVOKABLE QVariantMap checkAgainst(QString const& _type) const; protected: BigIntVariant m_internalValue; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index a4c896d3f..df5ad781b 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -515,7 +515,7 @@ Dialog { } else { - errorDialog.text = qsTr("some parameters are invalid:\n"); + errorDialog.text = qsTr("Some parameters are invalid:\n"); for (var k in invalid) errorDialog.text += invalid[k].message + "\n"; errorDialog.open(); diff --git a/mix/qml/js/InputValidator.js b/mix/qml/js/InputValidator.js index 6e94dec6e..37185b898 100644 --- a/mix/qml/js/InputValidator.js +++ b/mix/qml/js/InputValidator.js @@ -1,3 +1,5 @@ +Qt.include("QEtherHelper.js") + var nbRegEx = new RegExp('^[0-9]+$'); function validate(model, values) { @@ -8,7 +10,9 @@ function validate(model, values) { var type = model[k].type.name; var res; - if (type.indexOf("int") !== -1) + if (isContractType(type)) + res = validateAddress(type, values[model[k].name]); + else if (type.indexOf("int") !== -1) res = validateInt(type, values[model[k].name]); else if (type.indexOf("bytes") !== -1) res = validateBytes(type, values[model[k].name]); @@ -17,7 +21,7 @@ function validate(model, values) else if (type.indexOf("address") !== -1) res = validateAddress(type, values[model[k].name]); else - res = validateAddress(type, values[model[k].name]); //we suppose that this is a ctr type. + res.valid = true; if (!res.valid) inError.push({ type: type, value: values, message: res.message }); } @@ -25,6 +29,16 @@ function validate(model, values) return inError; } +function isContractType(_type) +{ + for (var k in Object.keys(codeModel.contracts)) + { + if ("contract " + Object.keys(codeModel.contracts)[k] === _type) + return true; + } + return false; +} + function validateInt(_type, _value) { var ret = { valid: true, message: "" } @@ -35,7 +49,6 @@ function validateInt(_type, _value) { ret.valid = false; ret.message = "uint type cannot represent negative number"; - return false; } } ret.valid = nbRegEx.test(_value); @@ -43,12 +56,13 @@ function validateInt(_type, _value) ret.message = _value + " does not represent " + _type + " type."; else { - var t = _type.replace("uint", "").replace("int", ""); - var max = parseInt(t) / 4; - if (_value.length > max) + var bigInt = createBigInt(_value); + bigInt.setBigInt(_value); + var result = bigInt.checkAgainst(_type); + if (!result.valid) { ret.valid = false; - ret.message = _type + " should not contains more than " + max + " digits"; + ret.message = _type + " should be between " + result.minValue + " and " + result.maxValue; } } return ret; @@ -60,7 +74,6 @@ function validateAddress(_type, _value) if (_value.indexOf("<") === 0 && _value.indexOf(">") === _value.length - 1) { var v = _value.split(' - '); - console.log(JSON.stringify(v)); if (v.length !== 2 || !nbRegEx.test(v[1].replace(">", ""))) // { ret.valid = false; From 74c46b8298a9c69327441c8fd4596f2d2566f6c6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 29 May 2015 16:34:34 +0200 Subject: [PATCH 20/90] rollback --- eth/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/eth/main.cpp b/eth/main.cpp index 645465234..b7bdee78b 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -628,7 +628,6 @@ int main(int argc, char** argv) nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(), netPrefs, &nodesState); - auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); From 05c47db94769bac8afe7f18171c9c6a04f275f4a Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 29 May 2015 16:39:07 +0200 Subject: [PATCH 21/90] rollback --- eth/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/eth/main.cpp b/eth/main.cpp index b7bdee78b..645465234 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -628,6 +628,7 @@ int main(int argc, char** argv) nodeMode == NodeMode::Full ? set{"eth"/*, "shh"*/} : set(), netPrefs, &nodesState); + auto toNumber = [&](string const& s) -> unsigned { if (s == "latest") return web3.ethereum()->number(); From fcc6d2f62172eb6aa547b76653328522a0cc35c5 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 1 Jun 2015 12:38:25 +0800 Subject: [PATCH 22/90] Possible MSVC workaround. --- libethereum/BlockQueue.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 4a7a61a31..c2bd35afc 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -102,6 +102,7 @@ void BlockQueue::verifierBody() RLP r(&res.second); for (auto const& uncle: r[2]) + { try { BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); @@ -125,6 +126,7 @@ void BlockQueue::verifierBody() badBlockHeader(uncle.data(), _e.what()); throw; } + } } catch (...) { From ec0074c225ecce21ed73cee2df87af95fae216af Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Jun 2015 09:48:19 +0200 Subject: [PATCH 23/90] add ability to test uncle as brother --- test/libethereum/blockchain.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 4e98b4036..0ea8b95a8 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -547,6 +547,10 @@ mArray importUncles(mObject const& blObj, vector& vBiUncles, vector Date: Mon, 1 Jun 2015 09:50:39 +0200 Subject: [PATCH 24/90] add uncle is brother test --- .../BlockTestsFiller/bcUncleTestFiller.json | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json index aeb372f67..761bce316 100644 --- a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json @@ -85,6 +85,108 @@ ] }, + "UncleIsBrother" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + { + "overwriteAndRedoPoW" : "parentHashIsBlocksParent", + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "acde5374fce5edbc8e2a8697c15331677e6ebf0b", + "difficulty" : "131072", + "extraData" : "0x", + "gasLimit" : "4141592", + "gasUsed" : "150000", + "hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04", + "mixHash" : "b557f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770", + "nonce" : "18a524c1790fa83b", + "number" : "2", + "parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd", + "timestamp" : "142813170", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + } + ] + } + ] + }, + "uncleHeaderWithGeneration0" : { "genesisBlockHeader" : { "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", From be62f618372e41005dfe4612f102b1aeb1935939 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 19 May 2015 16:55:43 +0200 Subject: [PATCH 25/90] Test for issue #1977 Test that reproduces issue #1977 and will fail on ArchLinux with Boost version: 1.58.0-1 gcc version: 4.9.2-4 --- test/libevm/vm.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 7b589d238..9f790501d 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -438,6 +438,15 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) BOOST_AUTO_TEST_SUITE(VMTests) +// test that reproduces issue https://github.com/ethereum/cpp-ethereum/issues/1977 +BOOST_AUTO_TEST_CASE(u256_overflow_test) +{ + dev::u256 a = 14; + dev::bigint b = dev::bigint("115792089237316195423570985008687907853269984665640564039457584007913129639948"); + // to fix cast `a` to dev::bigint + BOOST_CHECK(a < b); +} + BOOST_AUTO_TEST_CASE(vmtests) { dev::test::executeTests("vmtests", "/VMTests",dev::test::getFolder(__FILE__) + "/VMTestsFiller", dev::test::doVMTests); From a61e4a70a33fde189e50bab45a67d7c5b40bbdc6 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Jun 2015 10:40:17 +0200 Subject: [PATCH 26/90] Move the u256 test to external_dependencies tests --- test/CMakeLists.txt | 1 + .../external_dependencies/CMakeLists.txt | 5 +++ .../external_dependencies/boost.cpp | 37 +++++++++++++++++++ test/libevm/vm.cpp | 9 ----- 4 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 test/libdevcore/external_dependencies/CMakeLists.txt create mode 100644 test/libdevcore/external_dependencies/boost.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 39a235c58..0812a278a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,6 +19,7 @@ endmacro() add_subdirectory(fuzzTesting) add_subdirectory(libdevcore) +add_subdirectory(libdevcore/external_dependencies) add_subdirectory(libdevcrypto) add_subdirectory(libethcore) add_subdirectory(libethereum) diff --git a/test/libdevcore/external_dependencies/CMakeLists.txt b/test/libdevcore/external_dependencies/CMakeLists.txt new file mode 100644 index 000000000..3ceda13b0 --- /dev/null +++ b/test/libdevcore/external_dependencies/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_policy(SET CMP0015 NEW) + +aux_source_directory(. SRCS) + +add_sources(${SRCS}) diff --git a/test/libdevcore/external_dependencies/boost.cpp b/test/libdevcore/external_dependencies/boost.cpp new file mode 100644 index 000000000..5212c260b --- /dev/null +++ b/test/libdevcore/external_dependencies/boost.cpp @@ -0,0 +1,37 @@ +/* + 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 boost.cpp + * @author Lefteris Karapetsas + * @date 205 + * Tests for external dependencies: Boost + */ + +#include +#include + +BOOST_AUTO_TEST_SUITE(ExtDepBoost) + +// test that reproduces issue https://github.com/ethereum/cpp-ethereum/issues/1977 +BOOST_AUTO_TEST_CASE(u256_overflow_test) +{ + dev::u256 a = 14; + dev::bigint b = dev::bigint("115792089237316195423570985008687907853269984665640564039457584007913129639948"); + // to fix cast `a` to dev::bigint + BOOST_CHECK(a < b); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 9f790501d..7b589d238 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -438,15 +438,6 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) BOOST_AUTO_TEST_SUITE(VMTests) -// test that reproduces issue https://github.com/ethereum/cpp-ethereum/issues/1977 -BOOST_AUTO_TEST_CASE(u256_overflow_test) -{ - dev::u256 a = 14; - dev::bigint b = dev::bigint("115792089237316195423570985008687907853269984665640564039457584007913129639948"); - // to fix cast `a` to dev::bigint - BOOST_CHECK(a < b); -} - BOOST_AUTO_TEST_CASE(vmtests) { dev::test::executeTests("vmtests", "/VMTests",dev::test::getFolder(__FILE__) + "/VMTestsFiller", dev::test::doVMTests); From 2c89b071d0515d7335048f71de17625ef03db25b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Jun 2015 11:09:38 +0200 Subject: [PATCH 27/90] Move external-dependencies test out of lifdevcore --- test/CMakeLists.txt | 2 +- .../CMakeLists.txt | 0 .../external_dependencies => external-dependencies}/boost.cpp | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename test/{libdevcore/external_dependencies => external-dependencies}/CMakeLists.txt (100%) rename test/{libdevcore/external_dependencies => external-dependencies}/boost.cpp (98%) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0812a278a..d39a5cca1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -19,13 +19,13 @@ endmacro() add_subdirectory(fuzzTesting) add_subdirectory(libdevcore) -add_subdirectory(libdevcore/external_dependencies) add_subdirectory(libdevcrypto) add_subdirectory(libethcore) add_subdirectory(libethereum) add_subdirectory(libevm) add_subdirectory(libnatspec) add_subdirectory(libp2p) +add_subdirectory(external-dependencies) if (JSCONSOLE) add_subdirectory(libjsengine) diff --git a/test/libdevcore/external_dependencies/CMakeLists.txt b/test/external-dependencies/CMakeLists.txt similarity index 100% rename from test/libdevcore/external_dependencies/CMakeLists.txt rename to test/external-dependencies/CMakeLists.txt diff --git a/test/libdevcore/external_dependencies/boost.cpp b/test/external-dependencies/boost.cpp similarity index 98% rename from test/libdevcore/external_dependencies/boost.cpp rename to test/external-dependencies/boost.cpp index 5212c260b..91bf384b1 100644 --- a/test/libdevcore/external_dependencies/boost.cpp +++ b/test/external-dependencies/boost.cpp @@ -16,7 +16,7 @@ */ /** @file boost.cpp * @author Lefteris Karapetsas - * @date 205 + * @date 2015 * Tests for external dependencies: Boost */ From a706397875f37bafd85e3d280ed02f341197cde2 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 1 Jun 2015 12:01:01 +0200 Subject: [PATCH 28/90] MSVS compiler error and warnings fixed --- libp2p/UDP.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index a455b5057..b032c9e73 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -65,8 +65,8 @@ protected: */ struct RLPXDatagramFace: public UDPDatagram { - static uint32_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); } - static uint32_t secondsSinceEpoch() { return std::chrono::duration_cast((std::chrono::system_clock::now()).time_since_epoch()).count(); } + static uint32_t futureFromEpoch(std::chrono::seconds _sec) { return static_cast(std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count()); } + static uint32_t secondsSinceEpoch() { return static_cast(std::chrono::duration_cast((std::chrono::system_clock::now()).time_since_epoch()).count()); } static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp); virtual uint8_t packetType() = 0; @@ -115,7 +115,7 @@ class UDPSocket: UDPSocketFace, public std::enable_shared_from_this Date: Mon, 1 Jun 2015 12:41:50 +0200 Subject: [PATCH 29/90] exception in destructor --- libdevcore/TransientDirectory.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libdevcore/TransientDirectory.cpp b/libdevcore/TransientDirectory.cpp index db702181e..3e5462700 100644 --- a/libdevcore/TransientDirectory.cpp +++ b/libdevcore/TransientDirectory.cpp @@ -19,6 +19,7 @@ * @date 2015 */ +#include #include #include "Exceptions.h" #include "TransientDirectory.h" @@ -42,5 +43,16 @@ TransientDirectory::TransientDirectory(std::string const& _path): TransientDirectory::~TransientDirectory() { - boost::filesystem::remove_all(m_path); + for (int i = 0; i < 3; ++i) + { + try + { + boost::filesystem::remove_all(m_path); + break; + } + catch (...) + { + std::this_thread::sleep_for(chrono::milliseconds(10)); + } + } } From f7ee67a8db7aa0d835744e74706495d7472ca364 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 1 Jun 2015 12:43:25 +0200 Subject: [PATCH 30/90] fixed pv61+ hash downloading stalling --- libethereum/EthereumHost.cpp | 98 +++++++++++++----------------------- libethereum/EthereumHost.h | 1 - libethereum/EthereumPeer.cpp | 20 +++----- 3 files changed, 42 insertions(+), 77 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index a50c1c706..899960c23 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -91,7 +91,10 @@ void EthereumHost::doWork() bool netChange = ensureInitialised(); auto h = m_chain.currentHash(); // If we've finished our initial sync (including getting all the blocks into the chain so as to reduce invalid transactions), start trading transactions & blocks - if (!isSyncing() && m_chain.isKnown(m_latestBlockSent)) + bool syncing = false; + DEV_GUARDED(x_sync) + syncing = isSyncing(); + if (syncing && m_chain.isKnown(m_latestBlockSent)) { if (m_newTransactions) { @@ -241,7 +244,6 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer) _peer->disable("Peer banned for previous bad behaviour."); else { - _peer->m_protocolVersion = EthereumHost::c_oldProtocolVersion; //force V60 for now if (_peer->m_protocolVersion != protocolVersion()) estimatePeerHashes(_peer); else if (_peer->m_latestBlockNumber > m_chain.number()) @@ -283,6 +285,7 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool unsigned knowns = 0; unsigned unknowns = 0; h256s neededBlocks; + bool syncByNumber = !m_syncingLatestHash; for (unsigned i = 0; i < _hashes.size(); ++i) { _peer->addRating(1); @@ -290,10 +293,14 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool auto status = m_bq.blockStatus(h); if (status == QueueStatus::Importing || status == QueueStatus::Ready || m_chain.isKnown(h)) { - clog(NetMessageSummary) << "block hash ready:" << h << ". Start blocks download..."; - m_hashes += neededBlocks; - onPeerDoneHashes(_peer, true); - return; + clog(NetMessageSummary) << "Block hash already known:" << h; + if (!syncByNumber) + { + m_hashes += neededBlocks; + clog(NetMessageSummary) << "Start blocks download..."; + onPeerDoneHashes(_peer, true); + return; + } } else if (status == QueueStatus::Bad) { @@ -308,65 +315,25 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool } else knowns++; - m_syncingLatestHash = h; - } - m_hashes += neededBlocks; - clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLatestHash; - if (_complete) - { - m_needSyncBlocks = true; - continueSync(_peer); + if (!syncByNumber) + m_syncingLatestHash = h; } - else if (m_hashes.size() > _peer->m_expectedHashes) + if (syncByNumber) { - _peer->disable("Too many hashes"); - m_hashes.clear(); - m_syncingLatestHash = h256(); - continueSync(); ///Try with some other peer, keep the chain + m_man.appendToChain(neededBlocks); // Append to download manager immediatelly + clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns"; } else - continueSync(_peer); /// Grab next hashes -} - -void EthereumHost::onPeerHashes(EthereumPeer* _peer, unsigned /*_index*/, h256s const& _hashes) -{ - Guard l(x_sync); - assert(_peer->m_asking == Asking::Nothing); - if (_hashes.empty()) { - onPeerDoneHashes(_peer, true); - return; + m_hashes += neededBlocks; // Append to local list + clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns; now at" << m_syncingLatestHash; } - unsigned knowns = 0; - unsigned unknowns = 0; - h256s neededBlocks; - for (unsigned i = 0; i < _hashes.size(); ++i) + if (_complete) { - _peer->addRating(1); - auto h = _hashes[i]; - auto status = m_bq.blockStatus(h); - if (status == QueueStatus::Importing || status == QueueStatus::Ready || m_chain.isKnown(h)) - { - clog(NetWarn) << "block hash already known:" << h; - } - else if (status == QueueStatus::Bad) - { - clog(NetWarn) << "block hash bad!" << h << ". Bailing..."; - _peer->setIdle(); - return; - } - else if (status == QueueStatus::Unknown) - { - unknowns++; - neededBlocks.push_back(h); - } - else - knowns++; + m_needSyncBlocks = true; + continueSync(_peer); } - m_man.appendToChain(neededBlocks); - clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns"; - - if (m_hashMan.isComplete()) + else if (syncByNumber && m_hashMan.isComplete()) { // Done our chain-get. m_needSyncHashes = false; @@ -376,8 +343,15 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, unsigned /*_index*/, h256s m_hashMan.reset(m_chain.number() + 1); continueSync(); } + else if (m_hashes.size() > _peer->m_expectedHashes) + { + _peer->disable("Too many hashes"); + m_hashes.clear(); + m_syncingLatestHash = h256(); + continueSync(); ///Try with some other peer, keep the chain + } else - continueSync(_peer); + continueSync(_peer); /// Grab next hashes } void EthereumHost::onPeerDoneHashes(EthereumPeer* _peer, bool _localChain) @@ -470,8 +444,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) { - Guard l(x_sync); - if (_peer->m_asking != Asking::Nothing) + if (isSyncing()) { clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; return; @@ -483,7 +456,7 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { Guard l(x_sync); - if (_peer->m_asking != Asking::Nothing) + if (isSyncing()) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; return; @@ -525,7 +498,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) _peer->m_totalDifficulty = difficulty; m_needSyncHashes = true; m_needSyncBlocks = true; - m_syncingLatestHash = _peer->m_latestHash; + m_syncingLatestHash = h; sync = true; } } @@ -648,7 +621,6 @@ bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const bool EthereumHost::isSyncing() const { - Guard l(x_sync); bool syncing = false; forEachPeer([&](EthereumPeer* _p) { diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 497255034..f8fa79a15 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -82,7 +82,6 @@ public: void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); ///< Called by peer once it has new blocks void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has new hashes void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes); ///< Called by peer once it has another sequential block of hashes during sync - void onPeerHashes(EthereumPeer* _peer, unsigned _index, h256s const& _hashes); ///< Called by peer once it has a new ordered block of hashes starting with a particular number void onPeerTransactions(EthereumPeer* _peer, RLP const& _r); ///< Called by peer when it has new transactions DownloadMan& downloadMan() { return m_man; } diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index aa979e4b8..d6b0b50c3 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -40,7 +40,6 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap m_hashSub(host()->hashDownloadMan()), m_peerCapabilityVersion(_cap.second) { - m_peerCapabilityVersion = EthereumHost::c_oldProtocolVersion; m_syncHashNumber = host()->chain().number() + 1; requestStatus(); } @@ -78,7 +77,6 @@ string toString(Asking _a) return "?"; } - void EthereumPeer::setIdle() { m_sub.doneFetch(); @@ -88,8 +86,7 @@ void EthereumPeer::setIdle() void EthereumPeer::requestStatus() { - if (m_asking != Asking::Nothing) - clog(NetWarn) << "Bad state: requesting state should be the first action"; + assert(m_asking == Asking::Nothing); setAsking(Asking::State); RLPStream s; bool latest = m_peerCapabilityVersion == host()->protocolVersion(); @@ -106,22 +103,22 @@ void EthereumPeer::requestStatus() void EthereumPeer::requestHashes() { - if (m_asking == Asking::Blocks) - return; + assert(m_asking == Asking::Nothing); m_syncHashNumber = m_hashSub.nextFetch(c_maxHashesAsk); setAsking(Asking::Hashes); RLPStream s; prep(s, GetBlockHashesByNumberPacket, 2) << m_syncHashNumber << c_maxHashesAsk; + clog(NetMessageDetail) << "Requesting block hashes for numbers " << m_syncHashNumber << "-" << m_syncHashNumber + c_maxHashesAsk - 1; sealAndSend(s); } void EthereumPeer::requestHashes(h256 const& _lastHash) { - if (m_asking == Asking::Blocks) - return; + assert(m_asking == Asking::Nothing); setAsking(Asking::Hashes); RLPStream s; prep(s, GetBlockHashesPacket, 2) << _lastHash << c_maxHashesAsk; + clog(NetMessageDetail) << "Requesting block hashes staring from " << _lastHash; sealAndSend(s); } @@ -212,7 +209,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) u256 number256 = _r[0].toInt(); unsigned number = (unsigned) number256; unsigned limit = _r[1].toInt(); - clog(NetMessageSummary) << "GetBlockHashesByNumber (" << number << "-" << number + limit << ")"; + clog(NetMessageSummary) << "GetBlockHashesByNumber (" << number << "-" << number + limit - 1 << ")"; RLPStream s; if (number <= host()->chain().number()) { @@ -248,11 +245,8 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) m_hashSub.noteHash(m_syncHashNumber + i, 1); } - if (m_protocolVersion == host()->protocolVersion()) - host()->onPeerHashes(this, m_syncHashNumber, hashes); // V61+, report hashes by number - else - host()->onPeerHashes(this, hashes); m_syncHashNumber += itemCount; + host()->onPeerHashes(this, hashes); break; } case GetBlocksPacket: From 10fe1b4cfedccadff90325de7157d5b720f3d177 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 15 May 2015 12:23:13 +0200 Subject: [PATCH 31/90] added error jump instead of STOP instraction in case of exception --- libevmasm/Assembly.cpp | 28 +++- libevmasm/Assembly.h | 6 +- libevmasm/AssemblyItem.h | 2 +- libevmasm/ControlFlowGraph.cpp | 8 +- libsolidity/ArrayUtils.cpp | 8 +- libsolidity/Compiler.cpp | 3 +- libsolidity/CompilerContext.h | 2 + libsolidity/ExpressionCompiler.cpp | 7 +- test/libsolidity/SolidityCompiler.cpp | 192 ---------------------- test/libsolidity/SolidityEndToEndTest.cpp | 1 + 10 files changed, 43 insertions(+), 214 deletions(-) delete mode 100644 test/libsolidity/SolidityCompiler.cpp diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 5cf3b787a..f492260af 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -127,7 +127,10 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con _out << " PUSH \"" << m_strings.at((h256)i.data()) << "\""; break; case PushTag: - _out << " PUSH [tag" << dec << i.data() << "]"; + if (i.data() == 0) + _out << " PUSH [ErrorTag]"; + else + _out << " PUSH [tag" << dec << i.data() << "]"; break; case PushSub: _out << " PUSH [$" << h256(i.data()).abridged() << "]"; @@ -207,6 +210,10 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes createJsonValue("PUSH tag", i.getLocation().start, i.getLocation().end, m_strings.at((h256)i.data()))); break; case PushTag: + if (i.data() == 0) + collection.append( + createJsonValue("PUSH [ErrorTag]", i.getLocation().start, i.getLocation().end, "")); + collection.append( createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, string(i.data()))); break; @@ -226,7 +233,7 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes collection.append( createJsonValue("tag", i.getLocation().start, i.getLocation().end, string(i.data()))); collection.append( - createJsonValue("JUMDEST", i.getLocation().start, i.getLocation().end)); + createJsonValue("JUMPDEST", i.getLocation().start, i.getLocation().end)); break; case PushData: collection.append(createJsonValue("PUSH data", i.getLocation().start, i.getLocation().end, toStringInHex(i.data()))); @@ -387,6 +394,11 @@ bytes Assembly::assemble() const // m_data must not change from here on for (AssemblyItem const& i: m_items) + { + // store position of the invalid jump destination + if (i.type() != Tag && tagPos[0] == 0) + tagPos[0] = ret.size(); + switch (i.type()) { case Operation: @@ -448,17 +460,23 @@ bytes Assembly::assemble() const } case Tag: tagPos[(unsigned)i.data()] = ret.size(); + assertThrow(i.data() != 0, AssemblyException, ""); ret.push_back((byte)Instruction::JUMPDEST); break; default: BOOST_THROW_EXCEPTION(InvalidOpcode()); } - + } for (auto const& i: tagRef) { bytesRef r(ret.data() + i.first, bytesPerTag); - //@todo in the failure case, we could use the position of the invalid jumpdest - toBigEndian(i.second < tagPos.size() ? tagPos[i.second] : (1 << (8 * bytesPerTag)) - 1, r); + auto tag = i.second; + if (tag >= tagPos.size()) + tag = 0; + if (tag == 0) + assertThrow(tagPos[tag] != 0, AssemblyException, ""); + + toBigEndian(tagPos[tag], r); } if (!m_data.empty()) diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index b4850f7d0..4550eb6e7 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -67,6 +67,8 @@ public: AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; } + AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); } + template Assembly& operator<<(T const& _d) { append(_d); return *this; } AssemblyItems const& getItems() const { return m_items; } AssemblyItem const& back() const { return m_items.back(); } @@ -97,7 +99,6 @@ public: const StringMap &_sourceCodes = StringMap(), bool _inJsonFormat = false ) const; - protected: std::string getLocationFromSources(StringMap const& _sourceCodes, SourceLocation const& _location) const; void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } @@ -109,7 +110,8 @@ private: Json::Value createJsonValue(std::string _name, int _begin, int _end, std::string _value = std::string(), std::string _jumpType = std::string()) const; protected: - unsigned m_usedTags = 0; + // 0 is reserved for exception + unsigned m_usedTags = 1; AssemblyItems m_items; mutable std::map m_data; std::vector m_subs; diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 7d8f3d9a4..9eca0a7d1 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -65,7 +65,7 @@ public: /// @returns the instruction of this item (only valid if type() == Operation) Instruction instruction() const { return Instruction(byte(m_data)); } - /// @returns true iff the type and data of the items are equal. + /// @returns true if the type and data of the items are equal. bool operator==(AssemblyItem const& _other) const { return m_type == _other.m_type && m_data == _other.m_data; } bool operator!=(AssemblyItem const& _other) const { return !operator==(_other); } /// Less-than operator compatible with operator==. diff --git a/libevmasm/ControlFlowGraph.cpp b/libevmasm/ControlFlowGraph.cpp index 3566bdb17..41a53aa82 100644 --- a/libevmasm/ControlFlowGraph.cpp +++ b/libevmasm/ControlFlowGraph.cpp @@ -226,7 +226,10 @@ void ControlFlowGraph::gatherKnowledge() //@todo we might have to do something like incrementing the sequence number for each JUMPDEST assertThrow(!!workQueue.back().first, OptimizerException, ""); if (!m_blocks.count(workQueue.back().first)) + { + workQueue.pop_back(); continue; // too bad, we do not know the tag, probably an invalid jump + } BasicBlock& block = m_blocks.at(workQueue.back().first); KnownStatePointer state = workQueue.back().second; workQueue.pop_back(); @@ -257,10 +260,7 @@ void ControlFlowGraph::gatherKnowledge() ); state->feedItem(m_items.at(pc++)); - if (tags.empty() || std::any_of(tags.begin(), tags.end(), [&](u256 const& _tag) - { - return !m_blocks.count(BlockId(_tag)); - })) + if (tags.empty()) { if (!unknownJumpEncountered) { diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index 448e4da2a..f59385d97 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -455,12 +455,10 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const m_context << eth::Instruction::DUP2 << load; // stack: // check out-of-bounds access - m_context << eth::Instruction::DUP2 << eth::Instruction::LT; - eth::AssemblyItem legalAccess = m_context.appendConditionalJump(); - // out-of-bounds access throws exception (just STOP for now) - m_context << eth::Instruction::STOP; + m_context << eth::Instruction::DUP2 << eth::Instruction::LT << eth::Instruction::ISZERO; + // out-of-bounds access throws exception + m_context.appendConditionalJumpTo(m_context.errorTag()); - m_context << legalAccess; // stack: m_context << eth::Instruction::SWAP1; if (_arrayType.isDynamicallySized()) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 5e24aaaa2..261473404 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -193,8 +193,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) appendReturnValuePacker(FunctionType(*fallback).getReturnParameterTypes()); } else - m_context << eth::Instruction::STOP; // function not found - + m_context.appendConditionalJumpTo(m_context.errorTag()); // function not found for (auto const& it: interfaceFunctions) { FunctionTypePointer const& functionType = it.second; diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 7bc29de1a..dbf3dcd4f 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -98,6 +98,8 @@ public: eth::AssemblyItem appendJumpToNew() { return m_asm.appendJump().tag(); } /// Appends a JUMP to a tag already on the stack CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary); + /// Appends a JUMP to an "ErrorTag" + eth::AssemblyItem errorTag() { return m_asm.errorTag(); } /// Appends a JUMP to a specific tag CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; } /// Appends pushing of a new tag and @returns the new tag. diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 2e513b7fc..a9f0ba3ef 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1102,9 +1102,10 @@ void ExpressionCompiler::appendExternalFunctionCall( ) m_context << eth::Instruction::CALLCODE; else - m_context << eth::Instruction::CALL; - auto tag = m_context.appendConditionalJump(); - m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0. + { + m_context << eth::Instruction::CALL << eth::Instruction::ISZERO; + auto tag = m_context.appendConditionalJumpTo(m_context.errorTag());// if CALL leaves 0. + } if (_functionType.valueSet()) m_context << eth::Instruction::POP; if (_functionType.gasSet()) diff --git a/test/libsolidity/SolidityCompiler.cpp b/test/libsolidity/SolidityCompiler.cpp deleted file mode 100644 index dda7847ed..000000000 --- a/test/libsolidity/SolidityCompiler.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - 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 . -*/ -/** - * @author Christian - * @date 2014 - * Unit tests for the solidity compiler. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -using namespace dev::eth; - -namespace dev -{ -namespace solidity -{ -namespace test -{ - -namespace -{ - -bytes compileContract(const string& _sourceCode) -{ - Parser parser; - ASTPointer sourceUnit; - BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared(CharStream(_sourceCode)))); - NameAndTypeResolver resolver({}); - resolver.registerDeclarations(*sourceUnit); - for (ASTPointer const& node: sourceUnit->getNodes()) - if (ContractDefinition* contract = dynamic_cast(node.get())) - { - BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); - } - for (ASTPointer const& node: sourceUnit->getNodes()) - if (ContractDefinition* contract = dynamic_cast(node.get())) - { - BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract)); - } - for (ASTPointer const& node: sourceUnit->getNodes()) - if (ContractDefinition* contract = dynamic_cast(node.get())) - { - Compiler compiler; - compiler.compileContract(*contract, map{}); - - // debug - //compiler.streamAssembly(cout); - return compiler.getAssembledBytecode(); - } - BOOST_FAIL("No contract found in source."); - return bytes(); -} - -/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation. -/// This is necessary since the compiler will add boilerplate add the beginning that is not -/// tested here. -void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset) -{ - BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size()); - auto checkStart = _compiledCode.begin() + _offset; - BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(), - _expectation.begin(), _expectation.end()); -} - -} // end anonymous namespace - -BOOST_AUTO_TEST_SUITE(SolidityCompiler) - -BOOST_AUTO_TEST_CASE(smoke_test) -{ - char const* sourceCode = "contract test {\n" - " function f() { var x = 2; }\n" - "}\n"; - bytes code = compileContract(sourceCode); - - unsigned boilerplateSize = 73; - bytes expectation({byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x0, // initialize local variable x - byte(Instruction::PUSH1), 0x2, - byte(Instruction::SWAP1), - byte(Instruction::POP), - byte(Instruction::JUMPDEST), - byte(Instruction::POP), - byte(Instruction::JUMP)}); - checkCodePresentAt(code, expectation, boilerplateSize); -} - -BOOST_AUTO_TEST_CASE(ifStatement) -{ - char const* sourceCode = "contract test {\n" - " function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" - "}\n"; - bytes code = compileContract(sourceCode); - unsigned shift = 60; - unsigned boilerplateSize = 73; - bytes expectation({ - byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x0, - byte(Instruction::DUP1), - byte(Instruction::ISZERO), - byte(Instruction::PUSH1), byte(0x0f + shift), // "false" target - byte(Instruction::JUMPI), - // "if" body - byte(Instruction::PUSH1), 0x4d, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x21 + shift), - byte(Instruction::JUMP), - // new check "else if" condition - byte(Instruction::JUMPDEST), - byte(Instruction::DUP1), - byte(Instruction::ISZERO), - byte(Instruction::ISZERO), - byte(Instruction::PUSH1), byte(0x1c + shift), - byte(Instruction::JUMPI), - // "else if" body - byte(Instruction::PUSH1), 0x4e, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x20 + shift), - byte(Instruction::JUMP), - // "else" body - byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x4f, - byte(Instruction::POP), - }); - checkCodePresentAt(code, expectation, boilerplateSize); -} - -BOOST_AUTO_TEST_CASE(loops) -{ - char const* sourceCode = "contract test {\n" - " function f() { while(true){1;break;2;continue;3;return;4;} }" - "}\n"; - bytes code = compileContract(sourceCode); - unsigned shift = 60; - unsigned boilerplateSize = 73; - bytes expectation({byte(Instruction::JUMPDEST), - byte(Instruction::JUMPDEST), - byte(Instruction::PUSH1), 0x1, - byte(Instruction::ISZERO), - byte(Instruction::PUSH1), byte(0x21 + shift), - byte(Instruction::JUMPI), - byte(Instruction::PUSH1), 0x1, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x21 + shift), - byte(Instruction::JUMP), // break - byte(Instruction::PUSH1), 0x2, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x2 + shift), - byte(Instruction::JUMP), // continue - byte(Instruction::PUSH1), 0x3, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x22 + shift), - byte(Instruction::JUMP), // return - byte(Instruction::PUSH1), 0x4, - byte(Instruction::POP), - byte(Instruction::PUSH1), byte(0x2 + shift), - byte(Instruction::JUMP), - byte(Instruction::JUMPDEST), - byte(Instruction::JUMPDEST), - byte(Instruction::JUMP)}); - - checkCodePresentAt(code, expectation, boilerplateSize); -} - -BOOST_AUTO_TEST_SUITE_END() - -} -} -} // end namespaces diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 503615a5a..f8d20d70f 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1784,6 +1784,7 @@ BOOST_AUTO_TEST_CASE(contracts_as_addresses) } )"; compileAndRun(sourceCode, 20); + auto res = callContractFunction("getBalance()"); BOOST_REQUIRE(callContractFunction("getBalance()") == encodeArgs(u256(20 - 5), u256(5))); } From fb564b222ddc581bfbfb73c4f02f646b3d937979 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 19 May 2015 12:58:12 +0200 Subject: [PATCH 32/90] fixed mistake because of conflict resolving --- libsolidity/ExpressionCompiler.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index a9f0ba3ef..063af7ce6 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1102,10 +1102,11 @@ void ExpressionCompiler::appendExternalFunctionCall( ) m_context << eth::Instruction::CALLCODE; else - { - m_context << eth::Instruction::CALL << eth::Instruction::ISZERO; - auto tag = m_context.appendConditionalJumpTo(m_context.errorTag());// if CALL leaves 0. - } + m_context << eth::Instruction::CALL; + + m_context << eth::Instruction::ISZERO; + auto tag = m_context.appendConditionalJumpTo(m_context.errorTag());// if CALL leaves 0. + if (_functionType.valueSet()) m_context << eth::Instruction::POP; if (_functionType.gasSet()) From 74549bd60fff00dc0b01d4ba9e8ab7af43c7078b Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 19 May 2015 14:55:12 +0200 Subject: [PATCH 33/90] added test to check evm exception --- test/libsolidity/SolidityEndToEndTest.cpp | 24 +++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index f8d20d70f..faa5dad4d 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4111,6 +4111,30 @@ BOOST_AUTO_TEST_CASE(struct_delete_struct_in_mapping) BOOST_CHECK(callContractFunction("deleteIt()") == encodeArgs(0)); } +BOOST_AUTO_TEST_CASE(evm_exceptions) +{ + char const* sourceCode = R"( + contract A { + uint[3] arr; + bool public test = false; + function getElement(uint i) returns (uint) + { + return arr[i]; + } + function testIt() returns (bool) + { + uint i = this.getElement(5); + test = true; + return true; + } + } + )"; + compileAndRun(sourceCode, 0, "A"); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(false)); + BOOST_CHECK(callContractFunction("testIt()") == encodeArgs()); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(false)); +} + BOOST_AUTO_TEST_SUITE_END() } From d89589febc52aa7a85a013dfefb0f52eb5da93bd Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 19 May 2015 15:44:58 +0200 Subject: [PATCH 34/90] style fixes --- libevmasm/Assembly.h | 2 +- libsolidity/CompilerContext.h | 2 +- libsolidity/ExpressionCompiler.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 4550eb6e7..3c82125a1 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -67,7 +67,7 @@ public: AssemblyItem appendJumpI() { auto ret = append(newPushTag()); append(Instruction::JUMPI); return ret; } AssemblyItem appendJump(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMP); return ret; } AssemblyItem appendJumpI(AssemblyItem const& _tag) { auto ret = append(_tag.pushTag()); append(Instruction::JUMPI); return ret; } - AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); } + AssemblyItem errorTag() { return AssemblyItem(PushTag, 0); } template Assembly& operator<<(T const& _d) { append(_d); return *this; } AssemblyItems const& getItems() const { return m_items; } diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index dbf3dcd4f..573e0b576 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -98,7 +98,7 @@ public: eth::AssemblyItem appendJumpToNew() { return m_asm.appendJump().tag(); } /// Appends a JUMP to a tag already on the stack CompilerContext& appendJump(eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary); - /// Appends a JUMP to an "ErrorTag" + /// Returns an "ErrorTag" eth::AssemblyItem errorTag() { return m_asm.errorTag(); } /// Appends a JUMP to a specific tag CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm.appendJump(_tag); return *this; } diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 063af7ce6..c8aece85a 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1104,8 +1104,9 @@ void ExpressionCompiler::appendExternalFunctionCall( else m_context << eth::Instruction::CALL; + //Propagate error condition (if CALL pushes 0 on stack). m_context << eth::Instruction::ISZERO; - auto tag = m_context.appendConditionalJumpTo(m_context.errorTag());// if CALL leaves 0. + auto tag = m_context.appendConditionalJumpTo(m_context.errorTag()); if (_functionType.valueSet()) m_context << eth::Instruction::POP; From 77e1d116ca21fff8983fa67810f7c07806e95251 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 21 May 2015 12:10:26 +0200 Subject: [PATCH 35/90] one more test to test the call of non-existed function Conflicts: test/libsolidity/SolidityEndToEndTest.cpp --- libsolidity/ExpressionCompiler.cpp | 2 +- test/libsolidity/SolidityEndToEndTest.cpp | 28 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index c8aece85a..ae8bcaeee 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1106,7 +1106,7 @@ void ExpressionCompiler::appendExternalFunctionCall( //Propagate error condition (if CALL pushes 0 on stack). m_context << eth::Instruction::ISZERO; - auto tag = m_context.appendConditionalJumpTo(m_context.errorTag()); + m_context.appendConditionalJumpTo(m_context.errorTag()); if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index faa5dad4d..839ad7928 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4111,7 +4111,7 @@ BOOST_AUTO_TEST_CASE(struct_delete_struct_in_mapping) BOOST_CHECK(callContractFunction("deleteIt()") == encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(evm_exceptions) +BOOST_AUTO_TEST_CASE(evm_exceptions_out_of_band_access) { char const* sourceCode = R"( contract A { @@ -4135,6 +4135,32 @@ BOOST_AUTO_TEST_CASE(evm_exceptions) BOOST_CHECK(callContractFunction("test()") == encodeArgs(false)); } +BOOST_AUTO_TEST_CASE(evm_exceptions_when_calling_non_existing_function) +{ + char const* sourceCode = R"( + contract A { + uint public test = 0; + function badFunction() returns (uint) + { + this.call("123"); + test = 1; + return 2; + } + function testIt() returns (bool) + { + this.badFunction(); + test = 2; + return true; + } + } + )"; + compileAndRun(sourceCode, 0, "A"); + + BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); + BOOST_CHECK(callContractFunction("testIt()") == encodeArgs()); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); +} + BOOST_AUTO_TEST_SUITE_END() } From 52fad1282c64f003c7d60244d21f368f0a269013 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Wed, 20 May 2015 13:15:01 +0200 Subject: [PATCH 36/90] corrected asm-json output --- libevmasm/Assembly.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index f492260af..dabf646c1 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -213,9 +213,9 @@ Json::Value Assembly::streamAsmJson(ostream& _out, StringMap const& _sourceCodes if (i.data() == 0) collection.append( createJsonValue("PUSH [ErrorTag]", i.getLocation().start, i.getLocation().end, "")); - - collection.append( - createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, string(i.data()))); + else + collection.append( + createJsonValue("PUSH [tag]", i.getLocation().start, i.getLocation().end, string(i.data()))); break; case PushSub: collection.append( From 4b0e0d86914d5d52e620524c4d8cc952397983cf Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 21 May 2015 13:02:24 +0200 Subject: [PATCH 37/90] test for exception in constructor --- test/libsolidity/SolidityEndToEndTest.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 839ad7928..76952c676 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4161,6 +4161,23 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_when_calling_non_existing_function) BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); } +BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor) +{ + char const* sourceCode = R"( + contract A { + uint public test = 0; + function A() + { + this.call("123"); + test = 1; + } + } + )"; + compileAndRun(sourceCode, 0, "A"); + + BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); +} + BOOST_AUTO_TEST_SUITE_END() } From 803bea66544d5d2c0f7ee112566dbfb054e5d52f Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 21 May 2015 13:45:32 +0200 Subject: [PATCH 38/90] test for constructor (out of band exception) --- test/libsolidity/SolidityEndToEndTest.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 76952c676..c150a488c 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4161,7 +4161,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_when_calling_non_existing_function) BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); } -BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor) +BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) { char const* sourceCode = R"( contract A { @@ -4169,7 +4169,25 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor) function A() { this.call("123"); - test = 1; + ++test; + } + } + )"; + compileAndRun(sourceCode, 0, "A"); + + BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); +} + +BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_band) +{ + char const* sourceCode = R"( + contract A { + uint public test = 0; + uint[3] arr; + function A() + { + test = arr[5]; + ++test; } } )"; From 5996d912a2efeaceeeecba382e49d2e884f47d44 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 22 May 2015 14:07:05 +0200 Subject: [PATCH 39/90] remove line for debugging --- test/libsolidity/SolidityEndToEndTest.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index c150a488c..e4c5b47f1 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -1784,7 +1784,6 @@ BOOST_AUTO_TEST_CASE(contracts_as_addresses) } )"; compileAndRun(sourceCode, 20); - auto res = callContractFunction("getBalance()"); BOOST_REQUIRE(callContractFunction("getBalance()") == encodeArgs(u256(20 - 5), u256(5))); } From 7ef2c7dc4424ac6858b43f9be04ab6f3dfd5b597 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 22 May 2015 17:48:38 +0200 Subject: [PATCH 40/90] modified the test --- test/libsolidity/SolidityEndToEndTest.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index e4c5b47f1..538174ab5 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4164,24 +4164,32 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) { char const* sourceCode = R"( contract A { - uint public test = 0; function A() { this.call("123"); + + } + } + contract B { + uint public test = 1; + function testIt() + { + A a; ++test; } } )"; - compileAndRun(sourceCode, 0, "A"); + compileAndRun(sourceCode, 0, "B"); - BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); + BOOST_CHECK(callContractFunction("testIt()") == encodeArgs()); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(2)); } BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_band) { char const* sourceCode = R"( contract A { - uint public test = 0; + uint public test = 1; uint[3] arr; function A() { From a723fb7e813e098ea50fa1f9ba7e62d35db01c8a Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 26 May 2015 15:05:58 +0200 Subject: [PATCH 41/90] special handle of send --- libsolidity/ExpressionCompiler.cpp | 18 +++++++++++++----- libsolidity/ExpressionCompiler.h | 3 ++- test/libsolidity/SolidityEndToEndTest.cpp | 1 - 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index ae8bcaeee..e8ac8ff8b 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -534,7 +534,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) true, true ), - {} + {}, + true ); break; case Location::Suicide: @@ -1034,8 +1035,8 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) void ExpressionCompiler::appendExternalFunctionCall( FunctionType const& _functionType, - vector> const& _arguments -) + vector> const& _arguments, + bool isSend) { solAssert(_functionType.takesArbitraryParameters() || _arguments.size() == _functionType.getParameterTypes().size(), ""); @@ -1105,8 +1106,15 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << eth::Instruction::CALL; //Propagate error condition (if CALL pushes 0 on stack). - m_context << eth::Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); + if (!isSend) + { + m_context << eth::Instruction::ISZERO; + m_context.appendConditionalJumpTo(m_context.errorTag()); + } else + { + auto tag = m_context.appendConditionalJump(); + m_context << eth::Instruction::STOP << tag; + } if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 954e32c84..6f47762b9 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -100,7 +100,8 @@ private: /// Appends code to call a function of the given type with the given arguments. void appendExternalFunctionCall( FunctionType const& _functionType, - std::vector> const& _arguments + std::vector> const& _arguments, + bool isSend = false ); /// Appends code that evaluates the given arguments and moves the result to memory encoded as /// specified by the ABI. The memory offset is expected to be on the stack and is updated by diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 538174ab5..efebbb2f0 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4167,7 +4167,6 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) function A() { this.call("123"); - } } contract B { From 0d55798adf4757eb26393555f0b8c2ae12de8ed7 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Thu, 28 May 2015 14:48:37 +0200 Subject: [PATCH 42/90] removed exception when function is not found --- libsolidity/Compiler.cpp | 2 +- libsolidity/ExpressionCompiler.cpp | 18 ++++--------- libsolidity/ExpressionCompiler.h | 6 +---- test/libsolidity/SolidityEndToEndTest.cpp | 32 ++--------------------- 4 files changed, 9 insertions(+), 49 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 261473404..93d786bed 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -193,7 +193,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) appendReturnValuePacker(FunctionType(*fallback).getReturnParameterTypes()); } else - m_context.appendConditionalJumpTo(m_context.errorTag()); // function not found + m_context << eth::Instruction::STOP; // function not found for (auto const& it: interfaceFunctions) { FunctionTypePointer const& functionType = it.second; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index e8ac8ff8b..d618c6311 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -534,8 +534,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) true, true ), - {}, - true + {} ); break; case Location::Suicide: @@ -1035,8 +1034,8 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) void ExpressionCompiler::appendExternalFunctionCall( FunctionType const& _functionType, - vector> const& _arguments, - bool isSend) + vector> const& _arguments + ) { solAssert(_functionType.takesArbitraryParameters() || _arguments.size() == _functionType.getParameterTypes().size(), ""); @@ -1106,15 +1105,8 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << eth::Instruction::CALL; //Propagate error condition (if CALL pushes 0 on stack). - if (!isSend) - { - m_context << eth::Instruction::ISZERO; - m_context.appendConditionalJumpTo(m_context.errorTag()); - } else - { - auto tag = m_context.appendConditionalJump(); - m_context << eth::Instruction::STOP << tag; - } + auto tag = m_context.appendConditionalJump(); + m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.// } if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 6f47762b9..174e16d8d 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -98,11 +98,7 @@ private: void appendHighBitsCleanup(IntegerType const& _typeOnStack); /// Appends code to call a function of the given type with the given arguments. - void appendExternalFunctionCall( - FunctionType const& _functionType, - std::vector> const& _arguments, - bool isSend = false - ); + void appendExternalFunctionCall(FunctionType const& _functionType, std::vector> const& _arguments); /// Appends code that evaluates the given arguments and moves the result to memory encoded as /// specified by the ABI. The memory offset is expected to be on the stack and is updated by /// this call. If @a _padToWordBoundaries is set to false, all values are concatenated without diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index efebbb2f0..d2faaae08 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4080,7 +4080,6 @@ BOOST_AUTO_TEST_CASE(struct_delete_member) } )"; compileAndRun(sourceCode, 0, "test"); - auto res = callContractFunction("deleteMember()"); BOOST_CHECK(callContractFunction("deleteMember()") == encodeArgs(0)); } @@ -4106,7 +4105,6 @@ BOOST_AUTO_TEST_CASE(struct_delete_struct_in_mapping) } )"; compileAndRun(sourceCode, 0, "test"); - auto res = callContractFunction("deleteIt()"); BOOST_CHECK(callContractFunction("deleteIt()") == encodeArgs(0)); } @@ -4134,32 +4132,6 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_out_of_band_access) BOOST_CHECK(callContractFunction("test()") == encodeArgs(false)); } -BOOST_AUTO_TEST_CASE(evm_exceptions_when_calling_non_existing_function) -{ - char const* sourceCode = R"( - contract A { - uint public test = 0; - function badFunction() returns (uint) - { - this.call("123"); - test = 1; - return 2; - } - function testIt() returns (bool) - { - this.badFunction(); - test = 2; - return true; - } - } - )"; - compileAndRun(sourceCode, 0, "A"); - - BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); - BOOST_CHECK(callContractFunction("testIt()") == encodeArgs()); - BOOST_CHECK(callContractFunction("test()") == encodeArgs(0)); -} - BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) { char const* sourceCode = R"( @@ -4184,7 +4156,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) BOOST_CHECK(callContractFunction("test()") == encodeArgs(2)); } -BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_band) +BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) { char const* sourceCode = R"( contract A { @@ -4199,7 +4171,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_band) )"; compileAndRun(sourceCode, 0, "A"); - BOOST_CHECK(callContractFunction("test()") == encodeArgs(1)); + //BOOST_CHECK(m_output.empty()); todo } BOOST_AUTO_TEST_SUITE_END() From e8148a444f6f9d5906f0f0f9f9853dc4ea054259 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 29 May 2015 15:39:42 +0200 Subject: [PATCH 43/90] style fixes in test/libsolidity/solidityExecutionFramework.h fixed the test --- test/libsolidity/SolidityEndToEndTest.cpp | 4 +- test/libsolidity/solidityExecutionFramework.h | 281 ++++++++++-------- 2 files changed, 150 insertions(+), 135 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index d2faaae08..ef7b5c2a4 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4169,9 +4169,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) } } )"; - compileAndRun(sourceCode, 0, "A"); - - //BOOST_CHECK(m_output.empty()); todo + BOOST_CHECK(execute(sourceCode, 0, "A").empty()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index fa25fb12c..2c70415eb 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -40,142 +40,159 @@ namespace test class ExecutionFramework { public: - ExecutionFramework() { g_logVerbosity = 0; } - - bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - m_compiler.reset(false, m_addStandardSources); - m_compiler.addSource("", _sourceCode); - ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); - - bytes code = m_compiler.getBytecode(_contractName); - sendMessage(code, true, _value); - BOOST_REQUIRE(!m_output.empty()); - return m_output; - } - - template - bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, - Args const&... _arguments) - { - FixedHash<4> hash(dev::sha3(_sig)); - sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); - return m_output; - } - - template - bytes const& callContractFunction(std::string _sig, Args const&... _arguments) - { - return callContractFunctionWithValue(_sig, 0, _arguments...); - } - - template - void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) - { - bytes solidityResult = callContractFunction(_sig, _arguments...); - bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); - BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match." - "\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult)); - } - - template - void testSolidityAgainstCppOnRange(std::string _sig, CppFunction const& _cppFunction, - u256 const& _rangeStart, u256 const& _rangeEnd) - { - for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) - { - bytes solidityResult = callContractFunction(_sig, argument); - bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); - BOOST_CHECK_MESSAGE(solidityResult == cppResult, "Computed values do not match." - "\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult) + - "\nArgument: " + toHex(encode(argument))); - } - } - - static bytes encode(bool _value) { return encode(byte(_value)); } - static bytes encode(int _value) { return encode(u256(_value)); } - static bytes encode(char const* _value) { return encode(std::string(_value)); } - static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } - static bytes encode(u256 const& _value) { return toBigEndian(_value); } - static bytes encode(h256 const& _value) { return _value.asBytes(); } - static bytes encode(bytes const& _value, bool _padLeft = true) - { - bytes padding = bytes((32 - _value.size() % 32) % 32, 0); - return _padLeft ? padding + _value : _value + padding; - } - static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } - - template - static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) - { - return encode(_firstArg) + encodeArgs(_followingArgs...); - } - static bytes encodeArgs() - { - return bytes(); - } + ExecutionFramework() { g_logVerbosity = 0; } + + bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + m_compiler.reset(false, m_addStandardSources); + m_compiler.addSource("", _sourceCode); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); + + bytes code = m_compiler.getBytecode(_contractName); + sendMessage(code, true, _value); + return m_output; + } + + bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + execute(_sourceCode, _value, _contractName); + BOOST_REQUIRE(!m_output.empty()); + return m_output; + } + + template + bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) + { + FixedHash<4> hash(dev::sha3(_sig)); + sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); + return m_output; + } + + template + bytes const& callContractFunction(std::string _sig, Args const&... _arguments) + { + return callContractFunctionWithValue(_sig, 0, _arguments...); + } + + template + void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) + { + bytes solidityResult = callContractFunction(_sig, _arguments...); + bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, "Computed values do not match.\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult)); + } + + template + void testSolidityAgainstCppOnRange( + std::string _sig, + CppFunction const& _cppFunction, + u256 const& _rangeStart, + u256 const& _rangeEnd + ) + { + for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) + { + bytes solidityResult = callContractFunction(_sig, argument); + bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult) + + "\nArgument: " + + toHex(encode(argument)) + ); + } + } + + static bytes encode(bool _value) { return encode(byte(_value)); } + static bytes encode(int _value) { return encode(u256(_value)); } + static bytes encode(char const* _value) { return encode(std::string(_value)); } + static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } + static bytes encode(u256 const& _value) { return toBigEndian(_value); } + static bytes encode(h256 const& _value) { return _value.asBytes(); } + static bytes encode(bytes const& _value, bool _padLeft = true) + { + bytes padding = bytes((32 - _value.size() % 32) % 32, 0); + return _padLeft ? padding + _value : _value + padding; + } + static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } + + template + static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) + { + return encode(_firstArg) + encodeArgs(_followingArgs...); + } + static bytes encodeArgs() + { + return bytes(); + } private: - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - _cppFunction(_arguments...); - return bytes(); - } - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - return encode(_cppFunction(_arguments...)); - } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + _cppFunction(_arguments...); + return bytes(); + } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + return encode(_cppFunction(_arguments...)); + } protected: - void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) - { - m_state.addBalance(m_sender, _value); // just in case - eth::Executive executive(m_state, eth::LastHashes(), 0); - eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) - : eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); - bytes transactionRLP = t.rlp(); - try - { - // this will throw since the transaction is invalid, but it should nevertheless store the transaction - executive.initialize(&transactionRLP); - executive.execute(); - } - catch (...) {} - if (_isCreation) - { - BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); - m_contractAddress = executive.newAddress(); - BOOST_REQUIRE(m_contractAddress); - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - } - else - { - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); - } - BOOST_REQUIRE(executive.go()); - m_state.noteSending(m_sender); - executive.finalize(); - m_gasUsed = executive.gasUsed(); - m_output = executive.out().toVector(); - m_logs = executive.logs(); - } - - bool m_optimize = false; - bool m_addStandardSources = false; - dev::solidity::CompilerStack m_compiler; - Address m_sender; - Address m_contractAddress; - eth::State m_state; - u256 const m_gasPrice = 100 * eth::szabo; - u256 const m_gas = 100000000; - bytes m_output; - eth::LogEntries m_logs; - u256 m_gasUsed; + void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) + { + m_state.addBalance(m_sender, _value); // just in case + eth::Executive executive(m_state, eth::LastHashes(), 0); + eth::Transaction t = _isCreation ? eth::Transaction( + _value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec() + ) : eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); + + bytes transactionRLP = t.rlp(); + try + { + // this will throw since the transaction is invalid, but it should nevertheless store the transaction + executive.initialize(&transactionRLP); + executive.execute(); + } + catch (...) {} + if (_isCreation) + { + BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); + m_contractAddress = executive.newAddress(); + BOOST_REQUIRE(m_contractAddress); + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + } + else + { + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + } + BOOST_REQUIRE(executive.go()); + m_state.noteSending(m_sender); + executive.finalize(); + m_gasUsed = executive.gasUsed(); + m_output = executive.out().toVector(); + m_logs = executive.logs(); + } + + bool m_optimize = false; + bool m_addStandardSources = false; + dev::solidity::CompilerStack m_compiler; + Address m_sender; + Address m_contractAddress; + eth::State m_state; + u256 const m_gasPrice = 100 * eth::szabo; + u256 const m_gas = 100000000; + bytes m_output; + eth::LogEntries m_logs; + u256 m_gasUsed; }; } From 7512689becc4e623a1e576350abd0c191b57242d Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Fri, 29 May 2015 18:38:57 +0200 Subject: [PATCH 44/90] style fixes --- libsolidity/ExpressionCompiler.cpp | 4 +- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- test/libsolidity/solidityExecutionFramework.h | 284 +++++++++--------- 3 files changed, 144 insertions(+), 146 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index d618c6311..6a246f441 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1035,7 +1035,7 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) void ExpressionCompiler::appendExternalFunctionCall( FunctionType const& _functionType, vector> const& _arguments - ) +) { solAssert(_functionType.takesArbitraryParameters() || _arguments.size() == _functionType.getParameterTypes().size(), ""); @@ -1106,7 +1106,7 @@ void ExpressionCompiler::appendExternalFunctionCall( //Propagate error condition (if CALL pushes 0 on stack). auto tag = m_context.appendConditionalJump(); - m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0.// } + m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0. if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index ef7b5c2a4..db115b104 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4145,7 +4145,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_call_fail) uint public test = 1; function testIt() { - A a; + A a = new A(); ++test; } } diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 2c70415eb..879667fde 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -40,159 +40,157 @@ namespace test class ExecutionFramework { public: - ExecutionFramework() { g_logVerbosity = 0; } - - bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - m_compiler.reset(false, m_addStandardSources); - m_compiler.addSource("", _sourceCode); - ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); - - bytes code = m_compiler.getBytecode(_contractName); - sendMessage(code, true, _value); - return m_output; - } - - bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - execute(_sourceCode, _value, _contractName); - BOOST_REQUIRE(!m_output.empty()); - return m_output; - } - - template - bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) - { - FixedHash<4> hash(dev::sha3(_sig)); - sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); - return m_output; - } - - template - bytes const& callContractFunction(std::string _sig, Args const&... _arguments) - { - return callContractFunctionWithValue(_sig, 0, _arguments...); - } - - template - void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) - { - bytes solidityResult = callContractFunction(_sig, _arguments...); - bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); - BOOST_CHECK_MESSAGE( - solidityResult == cppResult, "Computed values do not match.\nSolidity: " + toHex(solidityResult) + "\nC++: " + toHex(cppResult)); - } - - template - void testSolidityAgainstCppOnRange( - std::string _sig, - CppFunction const& _cppFunction, - u256 const& _rangeStart, - u256 const& _rangeEnd - ) - { - for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) + ExecutionFramework() { g_logVerbosity = 0; } + + bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { - bytes solidityResult = callContractFunction(_sig, argument); - bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); - BOOST_CHECK_MESSAGE( - solidityResult == cppResult, - "Computed values do not match.\nSolidity: " + - toHex(solidityResult) + - "\nC++: " + - toHex(cppResult) + - "\nArgument: " + - toHex(encode(argument)) - ); + m_compiler.reset(false, m_addStandardSources); + m_compiler.addSource("", _sourceCode); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); + bytes code = m_compiler.getBytecode(_contractName); + sendMessage(code, true, _value); + return m_output; } - } - - static bytes encode(bool _value) { return encode(byte(_value)); } - static bytes encode(int _value) { return encode(u256(_value)); } - static bytes encode(char const* _value) { return encode(std::string(_value)); } - static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } - static bytes encode(u256 const& _value) { return toBigEndian(_value); } - static bytes encode(h256 const& _value) { return _value.asBytes(); } - static bytes encode(bytes const& _value, bool _padLeft = true) - { - bytes padding = bytes((32 - _value.size() % 32) % 32, 0); - return _padLeft ? padding + _value : _value + padding; - } - static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } - - template - static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) - { - return encode(_firstArg) + encodeArgs(_followingArgs...); - } - static bytes encodeArgs() - { - return bytes(); - } -private: - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - _cppFunction(_arguments...); - return bytes(); - } - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - return encode(_cppFunction(_arguments...)); - } + bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + execute(_sourceCode, _value, _contractName); + BOOST_REQUIRE(!m_output.empty()); + return m_output; + } -protected: - void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) - { - m_state.addBalance(m_sender, _value); // just in case - eth::Executive executive(m_state, eth::LastHashes(), 0); - eth::Transaction t = _isCreation ? eth::Transaction( - _value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec() - ) : eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); - - bytes transactionRLP = t.rlp(); - try + template + bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) { - // this will throw since the transaction is invalid, but it should nevertheless store the transaction - executive.initialize(&transactionRLP); - executive.execute(); + FixedHash<4> hash(dev::sha3(_sig)); + sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); + return m_output; } - catch (...) {} - if (_isCreation) + + template + bytes const& callContractFunction(std::string _sig, Args const&... _arguments) { - BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); - m_contractAddress = executive.newAddress(); - BOOST_REQUIRE(m_contractAddress); - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + return callContractFunctionWithValue(_sig, 0, _arguments...); } - else + + template + void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) { - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + bytes solidityResult = callContractFunction(_sig, _arguments...); + bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult)); } - BOOST_REQUIRE(executive.go()); - m_state.noteSending(m_sender); - executive.finalize(); - m_gasUsed = executive.gasUsed(); - m_output = executive.out().toVector(); - m_logs = executive.logs(); - } - - bool m_optimize = false; - bool m_addStandardSources = false; - dev::solidity::CompilerStack m_compiler; - Address m_sender; - Address m_contractAddress; - eth::State m_state; - u256 const m_gasPrice = 100 * eth::szabo; - u256 const m_gas = 100000000; - bytes m_output; - eth::LogEntries m_logs; - u256 m_gasUsed; + + template + void testSolidityAgainstCppOnRange(std::string _sig, CppFunction const& _cppFunction, u256 const& _rangeStart, u256 const& _rangeEnd) + { + for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) + { + bytes solidityResult = callContractFunction(_sig, argument); + bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult) + + "\nArgument: " + + toHex(encode(argument)) + ); + } + } + + static bytes encode(bool _value) { return encode(byte(_value)); } + static bytes encode(int _value) { return encode(u256(_value)); } + static bytes encode(char const* _value) { return encode(std::string(_value)); } + static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } + static bytes encode(u256 const& _value) { return toBigEndian(_value); } + static bytes encode(h256 const& _value) { return _value.asBytes(); } + static bytes encode(bytes const& _value, bool _padLeft = true) + { + bytes padding = bytes((32 - _value.size() % 32) % 32, 0); + return _padLeft ? padding + _value : _value + padding; + } + static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } + + template + static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) + { + return encode(_firstArg) + encodeArgs(_followingArgs...); + } + static bytes encodeArgs() + { + return bytes(); + } + +private: + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + _cppFunction(_arguments...); + return bytes(); + } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + return encode(_cppFunction(_arguments...)); + } + +protected: + void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) + { + m_state.addBalance(m_sender, _value); // just in case + eth::Executive executive(m_state, eth::LastHashes(), 0); + eth::Transaction t = + _isCreation ? + eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : + eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); + bytes transactionRLP = t.rlp(); + try + { + // this will throw since the transaction is invalid, but it should nevertheless store the transaction + executive.initialize(&transactionRLP); + executive.execute(); + } + catch (...) {} + if (_isCreation) + { + BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); + m_contractAddress = executive.newAddress(); + BOOST_REQUIRE(m_contractAddress); + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + } + else + { + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + } + BOOST_REQUIRE(executive.go()); + m_state.noteSending(m_sender); + executive.finalize(); + m_gasUsed = executive.gasUsed(); + m_output = executive.out().toVector(); + m_logs = executive.logs(); + } + + bool m_optimize = false; + bool m_addStandardSources = false; + dev::solidity::CompilerStack m_compiler; + Address m_sender; + Address m_contractAddress; + eth::State m_state; + u256 const m_gasPrice = 100 * eth::szabo; + u256 const m_gas = 100000000; + bytes m_output; + eth::LogEntries m_logs; + u256 m_gasUsed; }; } From 8ece3534ad0d8369dd12e6f75b31a6872698ea93 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 1 Jun 2015 13:25:02 +0200 Subject: [PATCH 45/90] Gas estimates for JSON compiler. --- solc/jsonCompiler.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index d47903fca..7bde3e47c 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,61 @@ Json::Value functionHashes(ContractDefinition const& _contract) return functionHashes; } +Json::Value gasToJson(GasEstimator::GasConsumption const& _gas) +{ + if (_gas.isInfinite || _gas.value > std::numeric_limits::max()) + return Json::Value(Json::nullValue); + else + return Json::Value(Json::LargestUInt(_gas.value)); +} + +Json::Value estimateGas(CompilerStack const& _compiler, string const& _contract) +{ + Json::Value gasEstimates(Json::objectValue); + using Gas = GasEstimator::GasConsumption; + if (!_compiler.getAssemblyItems(_contract) && !_compiler.getRuntimeAssemblyItems(_contract)) + return gasEstimates; + if (eth::AssemblyItems const* items = _compiler.getAssemblyItems(_contract)) + { + Gas gas = GasEstimator::functionalEstimation(*items); + u256 bytecodeSize(_compiler.getRuntimeBytecode(_contract).size()); + Json::Value creationGas(Json::arrayValue); + creationGas[0] = gasToJson(gas); + creationGas[1] = gasToJson(bytecodeSize * eth::c_createDataGas); + gasEstimates["creation"] = creationGas; + } + if (eth::AssemblyItems const* items = _compiler.getRuntimeAssemblyItems(_contract)) + { + ContractDefinition const& contract = _compiler.getContractDefinition(_contract); + Json::Value externalFunctions(Json::objectValue); + for (auto it: contract.getInterfaceFunctions()) + { + string sig = it.second->externalSignature(); + externalFunctions[sig] = gasToJson(GasEstimator::functionalEstimation(*items, sig)); + } + gasEstimates["external"] = externalFunctions; + Json::Value internalFunctions(Json::objectValue); + for (auto const& it: contract.getDefinedFunctions()) + { + if (it->isPartOfExternalInterface() || it->isConstructor()) + continue; + size_t entry = _compiler.getFunctionEntryPoint(_contract, *it); + GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite(); + if (entry > 0) + gas = GasEstimator::functionalEstimation(*items, entry, *it); + FunctionType type(*it); + string sig = it->getName() + "("; + auto end = type.getParameterTypes().end(); + for (auto it = type.getParameterTypes().begin(); it != end; ++it) + sig += (*it)->toString() + (it + 1 == end ? "" : ","); + sig += ")"; + internalFunctions[sig] = gasToJson(gas); + } + gasEstimates["internal"] = internalFunctions; + } + return gasEstimates; +} + string compile(string _input, bool _optimize) { StringMap sources; @@ -109,6 +165,7 @@ string compile(string _input, bool _optimize) contractData["bytecode"] = toHex(compiler.getBytecode(contractName)); contractData["opcodes"] = eth::disassemble(compiler.getBytecode(contractName)); contractData["functionHashes"] = functionHashes(compiler.getContractDefinition(contractName)); + contractData["gasEstimates"] = estimateGas(compiler, contractName); ostringstream unused; contractData["assembly"] = compiler.streamAssembly(unused, contractName, sources, true); output["contracts"][contractName] = contractData; From 2d076b8954bcf9e9aa1c6262d88f6b0dc6d70e1b Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Mon, 1 Jun 2015 13:03:29 +0200 Subject: [PATCH 46/90] corrected intends in solidityExecutionFramwork.h --- test/libsolidity/solidityExecutionFramework.h | 294 +++++++++--------- 1 file changed, 147 insertions(+), 147 deletions(-) diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 879667fde..29f3c4710 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -40,157 +40,157 @@ namespace test class ExecutionFramework { public: - ExecutionFramework() { g_logVerbosity = 0; } - - bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - m_compiler.reset(false, m_addStandardSources); - m_compiler.addSource("", _sourceCode); - ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); - bytes code = m_compiler.getBytecode(_contractName); - sendMessage(code, true, _value); - return m_output; - } - - bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") - { - execute(_sourceCode, _value, _contractName); - BOOST_REQUIRE(!m_output.empty()); - return m_output; - } - - template - bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) - { - FixedHash<4> hash(dev::sha3(_sig)); - sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); - return m_output; - } - - template - bytes const& callContractFunction(std::string _sig, Args const&... _arguments) - { - return callContractFunctionWithValue(_sig, 0, _arguments...); - } - - template - void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) - { - bytes solidityResult = callContractFunction(_sig, _arguments...); - bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); - BOOST_CHECK_MESSAGE( - solidityResult == cppResult, - "Computed values do not match.\nSolidity: " + - toHex(solidityResult) + - "\nC++: " + - toHex(cppResult)); - } - - template - void testSolidityAgainstCppOnRange(std::string _sig, CppFunction const& _cppFunction, u256 const& _rangeStart, u256 const& _rangeEnd) - { - for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) - { - bytes solidityResult = callContractFunction(_sig, argument); - bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); - BOOST_CHECK_MESSAGE( - solidityResult == cppResult, - "Computed values do not match.\nSolidity: " + - toHex(solidityResult) + - "\nC++: " + - toHex(cppResult) + - "\nArgument: " + - toHex(encode(argument)) - ); - } - } - - static bytes encode(bool _value) { return encode(byte(_value)); } - static bytes encode(int _value) { return encode(u256(_value)); } - static bytes encode(char const* _value) { return encode(std::string(_value)); } - static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } - static bytes encode(u256 const& _value) { return toBigEndian(_value); } - static bytes encode(h256 const& _value) { return _value.asBytes(); } - static bytes encode(bytes const& _value, bool _padLeft = true) - { - bytes padding = bytes((32 - _value.size() % 32) % 32, 0); - return _padLeft ? padding + _value : _value + padding; - } - static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } - - template - static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) - { - return encode(_firstArg) + encodeArgs(_followingArgs...); - } - static bytes encodeArgs() - { - return bytes(); - } +ExecutionFramework() { g_logVerbosity = 0; } + + bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + m_compiler.reset(false, m_addStandardSources); + m_compiler.addSource("", _sourceCode); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize), "Compiling contract failed"); + bytes code = m_compiler.getBytecode(_contractName); + sendMessage(code, true, _value); + return m_output; + } + + bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + { + execute(_sourceCode, _value, _contractName); + BOOST_REQUIRE(!m_output.empty()); + return m_output; + } + + template + bytes const& callContractFunctionWithValue(std::string _sig, u256 const& _value, Args const&... _arguments) + { + FixedHash<4> hash(dev::sha3(_sig)); + sendMessage(hash.asBytes() + encodeArgs(_arguments...), false, _value); + return m_output; + } + + template + bytes const& callContractFunction(std::string _sig, Args const&... _arguments) + { + return callContractFunctionWithValue(_sig, 0, _arguments...); + } + + template + void testSolidityAgainstCpp(std::string _sig, CppFunction const& _cppFunction, Args const&... _arguments) + { + bytes solidityResult = callContractFunction(_sig, _arguments...); + bytes cppResult = callCppAndEncodeResult(_cppFunction, _arguments...); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult)); + } + + template + void testSolidityAgainstCppOnRange(std::string _sig, CppFunction const& _cppFunction, u256 const& _rangeStart, u256 const& _rangeEnd) + { + for (u256 argument = _rangeStart; argument < _rangeEnd; ++argument) + { + bytes solidityResult = callContractFunction(_sig, argument); + bytes cppResult = callCppAndEncodeResult(_cppFunction, argument); + BOOST_CHECK_MESSAGE( + solidityResult == cppResult, + "Computed values do not match.\nSolidity: " + + toHex(solidityResult) + + "\nC++: " + + toHex(cppResult) + + "\nArgument: " + + toHex(encode(argument)) + ); + } + } + + static bytes encode(bool _value) { return encode(byte(_value)); } + static bytes encode(int _value) { return encode(u256(_value)); } + static bytes encode(char const* _value) { return encode(std::string(_value)); } + static bytes encode(byte _value) { return bytes(31, 0) + bytes{_value}; } + static bytes encode(u256 const& _value) { return toBigEndian(_value); } + static bytes encode(h256 const& _value) { return _value.asBytes(); } + static bytes encode(bytes const& _value, bool _padLeft = true) + { + bytes padding = bytes((32 - _value.size() % 32) % 32, 0); + return _padLeft ? padding + _value : _value + padding; + } + static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } + + template + static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) + { + return encode(_firstArg) + encodeArgs(_followingArgs...); + } + static bytes encodeArgs() + { + return bytes(); + } private: - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - _cppFunction(_arguments...); - return bytes(); - } - template - auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) - -> typename std::enable_if::value, bytes>::type - { - return encode(_cppFunction(_arguments...)); - } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + _cppFunction(_arguments...); + return bytes(); + } + template + auto callCppAndEncodeResult(CppFunction const& _cppFunction, Args const&... _arguments) + -> typename std::enable_if::value, bytes>::type + { + return encode(_cppFunction(_arguments...)); + } protected: - void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) - { - m_state.addBalance(m_sender, _value); // just in case - eth::Executive executive(m_state, eth::LastHashes(), 0); - eth::Transaction t = - _isCreation ? - eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : - eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); - bytes transactionRLP = t.rlp(); - try - { - // this will throw since the transaction is invalid, but it should nevertheless store the transaction - executive.initialize(&transactionRLP); - executive.execute(); - } - catch (...) {} - if (_isCreation) - { - BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); - m_contractAddress = executive.newAddress(); - BOOST_REQUIRE(m_contractAddress); - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - } - else - { - BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); - BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); - } - BOOST_REQUIRE(executive.go()); - m_state.noteSending(m_sender); - executive.finalize(); - m_gasUsed = executive.gasUsed(); - m_output = executive.out().toVector(); - m_logs = executive.logs(); - } - - bool m_optimize = false; - bool m_addStandardSources = false; - dev::solidity::CompilerStack m_compiler; - Address m_sender; - Address m_contractAddress; - eth::State m_state; - u256 const m_gasPrice = 100 * eth::szabo; - u256 const m_gas = 100000000; - bytes m_output; - eth::LogEntries m_logs; - u256 m_gasUsed; + void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0) + { + m_state.addBalance(m_sender, _value); // just in case + eth::Executive executive(m_state, eth::LastHashes(), 0); + eth::Transaction t = + _isCreation ? + eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : + eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); + bytes transactionRLP = t.rlp(); + try + { + // this will throw since the transaction is invalid, but it should nevertheless store the transaction + executive.initialize(&transactionRLP); + executive.execute(); + } + catch (...) {} + if (_isCreation) + { + BOOST_REQUIRE(!executive.create(m_sender, _value, m_gasPrice, m_gas, &_data, m_sender)); + m_contractAddress = executive.newAddress(); + BOOST_REQUIRE(m_contractAddress); + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + } + else + { + BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); + BOOST_REQUIRE(!executive.call(m_contractAddress, m_contractAddress, m_sender, _value, m_gasPrice, &_data, m_gas, m_sender)); + } + BOOST_REQUIRE(executive.go()); + m_state.noteSending(m_sender); + executive.finalize(); + m_gasUsed = executive.gasUsed(); + m_output = executive.out().toVector(); + m_logs = executive.logs(); + } + + bool m_optimize = false; + bool m_addStandardSources = false; + dev::solidity::CompilerStack m_compiler; + Address m_sender; + Address m_contractAddress; + eth::State m_state; + u256 const m_gasPrice = 100 * eth::szabo; + u256 const m_gas = 100000000; + bytes m_output; + eth::LogEntries m_logs; + u256 m_gasUsed; }; } From 850c21eb3abf6c4e8ea701c0e9ed6065f14fdad6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 1 Jun 2015 20:10:49 +0800 Subject: [PATCH 47/90] Avoid redownloading chain for non-breaking changes. --- libethereum/Client.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index e7d7a543b..96353ade2 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -44,10 +44,11 @@ VersionChecker::VersionChecker(string const& _dbPath): try { auto protocolVersion = (unsigned)status[0]; + (void)protocolVersion; auto minorProtocolVersion = (unsigned)status[1]; auto databaseVersion = (unsigned)status[2]; m_action = - protocolVersion != eth::c_protocolVersion || databaseVersion != c_databaseVersion ? + databaseVersion != c_databaseVersion ? WithExisting::Kill : minorProtocolVersion != eth::c_minorProtocolVersion ? WithExisting::Verify From d1f19fe2d4fe75788669535af5e8aa40b791d89a Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 1 Jun 2015 20:11:59 +0800 Subject: [PATCH 48/90] Fix for windows. Better failure reporting on consensus issues. --- libethereum/Executive.cpp | 11 ++++++----- libethereum/Executive.h | 1 + libethereum/State.cpp | 33 ++++++++++++++++++++++++++++++++- libethereum/Transaction.cpp | 21 +++++++++++++++++++++ libethereum/Transaction.h | 3 +++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 09cdc6b04..8c77903ef 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -32,6 +32,7 @@ using namespace dev; using namespace dev::eth; const char* VMTraceChannel::name() { return "EVM"; } +const char* ExecutiveWarnChannel::name() { return WarnChannel::name(); } Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): m_s(_s), @@ -63,7 +64,7 @@ void Executive::initialize(Transaction const& _transaction) u256 startGasUsed = m_s.gasUsed(); if (startGasUsed + (bigint)m_t.gas() > m_s.m_currentBlock.gasLimit) { - clog(StateDetail) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Too much gas used in this block: Require <" << (m_s.m_currentBlock.gasLimit - startGasUsed) << " Got" << m_t.gas(); m_excepted = TransactionException::BlockGasLimitReached; BOOST_THROW_EXCEPTION(BlockGasLimitReached() << RequirementError((bigint)(m_s.m_currentBlock.gasLimit - startGasUsed), (bigint)m_t.gas())); } @@ -71,7 +72,7 @@ void Executive::initialize(Transaction const& _transaction) // Check gas cost is enough. if (!m_t.checkPayment()) { - clog(StateDetail) << "Not enough gas to pay for the transaction: Require >" << m_t.gasRequired() << " Got" << m_t.gas(); + clog(ExecutiveWarnChannel) << "Not enough gas to pay for the transaction: Require >" << m_t.gasRequired() << " Got" << m_t.gas(); m_excepted = TransactionException::OutOfGas; BOOST_THROW_EXCEPTION(OutOfGasBase() << RequirementError(m_t.gasRequired(), (bigint)m_t.gas())); } @@ -84,13 +85,13 @@ void Executive::initialize(Transaction const& _transaction) } catch (...) { - clog(StateDetail) << "Invalid Signature"; + clog(ExecutiveWarnChannel) << "Invalid Signature"; m_excepted = TransactionException::InvalidSignature; throw; } if (m_t.nonce() != nonceReq) { - clog(StateDetail) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce(); + clog(ExecutiveWarnChannel) << "Invalid Nonce: Require" << nonceReq << " Got" << m_t.nonce(); m_excepted = TransactionException::InvalidNonce; BOOST_THROW_EXCEPTION(InvalidNonce() << RequirementError((bigint)nonceReq, (bigint)m_t.nonce())); } @@ -100,7 +101,7 @@ void Executive::initialize(Transaction const& _transaction) m_totalCost = m_t.value() + m_gasCost; if (m_s.balance(m_t.sender()) < m_totalCost) { - clog(StateDetail) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender()); + clog(ExecutiveWarnChannel) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender()); m_excepted = TransactionException::NotEnoughCash; BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(m_totalCost, (bigint)m_s.balance(m_t.sender()))); } diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 949e2dc34..447f76eb9 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -36,6 +36,7 @@ class ExtVM; 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; }; /** * @brief Message-call/contract-creation executor; useful for executing transactions. diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 23405912c..20249f2eb 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -592,6 +592,24 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ss.str(); } +template +class LogOverride +{ +public: + LogOverride(bool _value): m_old(g_logOverride.count(&typeid(Channel)) ? (int)g_logOverride[&typeid(Channel)] : c_null) { g_logOverride[&typeid(Channel)] = _value; } + ~LogOverride() + { + if (m_old == c_null) + g_logOverride.erase(&typeid(Channel)); + else + g_logOverride[&typeid(Channel)] = (bool)m_old; + } + +private: + static const int c_null = -1; + int m_old; +}; + u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) { // m_currentBlock is assumed to be prepopulated and reset. @@ -624,7 +642,19 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement unsigned i = 0; for (auto const& tr: rlp[1]) { - execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + try { + LogOverride o(false); + execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + } + catch (...) + { + badBlock(_block, "Invalid transaction"); + cwarn << " Transaction Index:" << i; + LogOverride o(true); + execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); + throw; + } + RLPStream receiptRLP; m_receipts.back().streamRLP(receiptRLP); receipts.push_back(receiptRLP.out()); @@ -1163,6 +1193,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per ctrace << "Executing" << e.t() << "on" << h; ctrace << toHex(e.t().rlp()); #endif + (void)_onOp; if (!e.execute()) #if ETH_VMTRACE e.go(e.simpleTrace()); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 975af53a5..b8d8d64c1 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -39,6 +39,27 @@ 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) { if (!!dynamic_cast(&_e)) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 09d6cd54c..935b78c2a 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -235,5 +235,8 @@ 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); } + } } From 208d504314a11abda493d3b9672d1581c49c51c9 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 1 Jun 2015 20:13:49 +0800 Subject: [PATCH 49/90] Fixes #2052 --- libethereum/State.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 20249f2eb..b35ef98ce 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1193,10 +1193,12 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per ctrace << "Executing" << e.t() << "on" << h; ctrace << toHex(e.t().rlp()); #endif - (void)_onOp; if (!e.execute()) #if ETH_VMTRACE + { + (void)_onOp; e.go(e.simpleTrace()); + } #else e.go(_onOp); #endif From b325a5c3b2053a45a8c841001be03cfad743c9ea Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 1 Jun 2015 15:43:55 +0200 Subject: [PATCH 50/90] Mutex guard m_fulls on eval() --- libethcore/EthashAux.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 06da22f98..4b546404a 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -240,8 +240,9 @@ Ethash::Result EthashAux::eval(BlockInfo const& _header, Nonce const& _nonce) Ethash::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) { - if (FullType dag = get()->m_fulls[_seedHash].lock()) - return dag->compute(_headerHash, _nonce); + DEV_GUARDED(get()->x_fulls) + if (FullType dag = get()->m_fulls[_seedHash].lock()) + return dag->compute(_headerHash, _nonce); DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce)) { return Ethash::Result{ ~h256(), h256() }; From f070e3b493e5cf90eb7329ce5efd8e83b4947fc0 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Mon, 1 Jun 2015 16:32:04 +0200 Subject: [PATCH 51/90] a minor update --- libdevcore/TransientDirectory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/TransientDirectory.cpp b/libdevcore/TransientDirectory.cpp index 3e5462700..3c88e42a3 100644 --- a/libdevcore/TransientDirectory.cpp +++ b/libdevcore/TransientDirectory.cpp @@ -52,7 +52,7 @@ TransientDirectory::~TransientDirectory() } catch (...) { - std::this_thread::sleep_for(chrono::milliseconds(10)); + this_thread::sleep_for(chrono::milliseconds(10)); } } } From 1f8bd0fe680b1350a5a930f7c8a96089ab959e39 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 1 Jun 2015 17:34:11 +0300 Subject: [PATCH 52/90] BlockWeight: uncle POW issue --- test/libethereum/blockchain.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 0ea8b95a8..0ff7e57f3 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -214,9 +214,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) uncleStream.appendRaw(uncleRlp.out()); } - // update unclehash in case of invalid uncles - current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); - updatePoW(current_BlockHeader); + if (vBiUncles.size()) + { + // update unclehash in case of invalid uncles + current_BlockHeader.sha3Uncles = sha3(uncleStream.out()); + updatePoW(current_BlockHeader); + } if (blObj.count("blockHeader")) overwriteBlockHeader(current_BlockHeader, blObj); @@ -242,7 +245,10 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) blObj["rlp"] = toHex(block2.out(), 2, HexPrefix::Add); if (sha3(RLP(state.blockData())[0].data()) != sha3(RLP(block2.out())[0].data())) - cnote << "block header mismatch\n"; + { + cnote << "block header mismatch state.blockData() vs updated state.info()\n"; + cerr << toHex(state.blockData()) << "vs" << toHex(block2.out()); + } if (sha3(RLP(state.blockData())[1].data()) != sha3(RLP(block2.out())[1].data())) cnote << "txs mismatch\n"; From 32458c0808ce6a6e396ab66281a5c22d58ef0929 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Mon, 1 Jun 2015 16:39:09 +0200 Subject: [PATCH 53/90] fixed CALL case. added exception --- libsolidity/ExpressionCompiler.cpp | 4 ++-- test/libsolidity/solidityExecutionFramework.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index 6a246f441..ae8bcaeee 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -1105,8 +1105,8 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context << eth::Instruction::CALL; //Propagate error condition (if CALL pushes 0 on stack). - auto tag = m_context.appendConditionalJump(); - m_context << eth::Instruction::STOP << tag; // STOP if CALL leaves 0. + m_context << eth::Instruction::ISZERO; + m_context.appendConditionalJumpTo(m_context.errorTag()); if (_functionType.valueSet()) m_context << eth::Instruction::POP; diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 29f3c4710..ddbbb0161 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -40,7 +40,7 @@ namespace test class ExecutionFramework { public: -ExecutionFramework() { g_logVerbosity = 0; } + ExecutionFramework() { g_logVerbosity = 0; } bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { From 214542eb5e62cb6b909580bd6d98163c850ebe69 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Mon, 1 Jun 2015 16:48:13 +0200 Subject: [PATCH 54/90] renamed the test framwork function. --- test/libsolidity/SolidityEndToEndTest.cpp | 2 +- test/libsolidity/solidityExecutionFramework.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index db115b104..9f6f27d7d 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4169,7 +4169,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) } } )"; - BOOST_CHECK(execute(sourceCode, 0, "A").empty()); + BOOST_CHECK(compileAndRunWthoutCheck(sourceCode, 0, "A").empty()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index ddbbb0161..c29257dd9 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -42,7 +42,7 @@ class ExecutionFramework public: ExecutionFramework() { g_logVerbosity = 0; } - bytes const& execute(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") + bytes const& compileAndRunWthoutCheck(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { m_compiler.reset(false, m_addStandardSources); m_compiler.addSource("", _sourceCode); @@ -54,7 +54,7 @@ public: bytes const& compileAndRun(std::string const& _sourceCode, u256 const& _value = 0, std::string const& _contractName = "") { - execute(_sourceCode, _value, _contractName); + compileAndRunWthoutCheck(_sourceCode, _value, _contractName); BOOST_REQUIRE(!m_output.empty()); return m_output; } From 120611e9d4c6ac5b223f34ae8a7db84c995e1a07 Mon Sep 17 00:00:00 2001 From: winsvega Date: Thu, 21 May 2015 17:52:39 +0300 Subject: [PATCH 55/90] Random Code --- test/fuzzTesting/CMakeLists.txt | 7 +- test/fuzzTesting/createRandomStateTest.cpp | 57 +---------- test/fuzzTesting/fuzzHelper.cpp | 112 +++++++++++++++++++++ test/fuzzTesting/fuzzHelper.h | 75 ++++++++++++++ test/libethereum/blockchain.cpp | 9 +- 5 files changed, 205 insertions(+), 55 deletions(-) create mode 100644 test/fuzzTesting/fuzzHelper.cpp create mode 100644 test/fuzzTesting/fuzzHelper.h diff --git a/test/fuzzTesting/CMakeLists.txt b/test/fuzzTesting/CMakeLists.txt index b0b3b0776..371d6504d 100644 --- a/test/fuzzTesting/CMakeLists.txt +++ b/test/fuzzTesting/CMakeLists.txt @@ -9,10 +9,13 @@ include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") -add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp") -add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") +add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp") +add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp" ) add_executable(checkRandomStateTest "./checkRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp") +list(APPEND SRCS "./fuzzHelper.cpp") +add_sources(${SRCS}) + target_link_libraries(createRandomVMTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) target_link_libraries(createRandomVMTest ethereum) target_link_libraries(createRandomVMTest ethcore) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index e0cb35dd1..65bfa2cfa 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -37,6 +37,7 @@ #include #include #include +#include using namespace std; using namespace json_spirit; @@ -47,55 +48,7 @@ void doStateTests(json_spirit::mValue& _v); int main(int argc, char *argv[]) { g_logVerbosity = 0; - - // create random code - - boost::random::mt19937 gen; - - auto now = chrono::steady_clock::now().time_since_epoch(); - auto timeSinceEpoch = chrono::duration_cast(now).count(); - gen.seed(static_cast(timeSinceEpoch)); - // set min and max length of the random evm code - boost::random::uniform_int_distribution<> lengthOfCodeDist(8, 24); - boost::random::uniform_int_distribution<> reasonableInputValuesSize(0, 7); - boost::random::uniform_int_distribution<> opcodeDist(0, 255); - boost::random::uniform_int_distribution<> BlockInfoOpcodeDist(0x40, 0x45); - boost::random::uniform_int_distribution<> uniformInt(0, 0x7fffffff); - boost::random::variate_generator > randGenInputValue(gen, reasonableInputValuesSize); - boost::random::variate_generator > randGenUniformInt(gen, uniformInt); - boost::random::variate_generator > randGen(gen, opcodeDist); - boost::random::variate_generator > randGenBlockInfoOpcode(gen, BlockInfoOpcodeDist); - - std::vector reasonableInputValues; - reasonableInputValues.push_back(0); - reasonableInputValues.push_back(1); - reasonableInputValues.push_back(50000); - reasonableInputValues.push_back(u256("0x10000000000000000000000000000000000000000")); - reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffff")); - reasonableInputValues.push_back(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe")); - reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); - reasonableInputValues.push_back(u256("0x945304eb96065b2a98b57a48a06ae28d285a71b5")); - reasonableInputValues.push_back(randGenUniformInt()); - - int lengthOfCode = lengthOfCodeDist(gen); - string randomCode; - - for (int i = 0; i < lengthOfCode; ++i) - { - // pre-fill stack to avoid that most of the test fail with a stackunderflow - if (i < 8 && (randGen() < 192)) - { - randomCode += randGen() < 32 ? toHex(toCompactBigEndian((uint8_t)randGenBlockInfoOpcode())) : "7f" + toHex(reasonableInputValues[randGenInputValue()]); - continue; - } - - uint8_t opcode = randGen(); - // disregard all invalid commands, except of one (0x0c) - if ((dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || (randGen() > 250))) - randomCode += toHex(toCompactBigEndian(opcode)); - else - i--; - } + string randomCode = dev::test::RandomCode::generate(25); string const s = R"( { @@ -147,16 +100,16 @@ int main(int argc, char *argv[]) read_string(s, v); // insert new random code - v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + (randGen() > 128 ? "55" : "") + (randGen() > 128 ? "60005155" : ""); + v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode; // insert new data in tx v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomCode; // insert new value in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = toString(randGenUniformInt()); + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = dev::test::RandomCode::randomUniInt(); // insert new gasLimit in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = "0x" + toHex(toCompactBigEndian((int)randGenUniformInt())); + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = dev::test::RandomCode::randomUniInt(); // fill test doStateTests(v); diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp new file mode 100644 index 000000000..5b3b0a7f0 --- /dev/null +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -0,0 +1,112 @@ +/* + 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 fuzzHelper.cpp + * @author Dimitry Khokhlov + * @date 2015 + */ + +#include "fuzzHelper.h" + +#include +#include +#include +#include + +namespace dev +{ +namespace test +{ + +boost::random::mt19937 RandomCode::gen; +boostIntDistrib RandomCode::opCodeDist = boostIntDistrib (0, 255); +boostIntDistrib RandomCode::opLengDist = boostIntDistrib (1, 32); +boostIntDistrib RandomCode::uniIntDist = boostIntDistrib (0, 0x7fffffff); + +boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist); +boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); +boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); + + +std::string RandomCode::rndByteSequence(int length) +{ + refreshSeed(); + std::string hash; + length = std::max(1, length); + for (auto i = 0; i < length; i++) + { + uint8_t byte = randOpCodeGen(); + hash += toCompactHex(byte); + } + return hash; +} + +std::string RandomCode::fillArguments(int num) +{ + std::string code; + for (auto i = 0; i < num; i++) + { + int length = randOpLengGen(); + int pushCode = 96 + length - 1; + code += toCompactHex(pushCode) + rndByteSequence(length); + } + return code; +} + +//generate smart random code +std::string RandomCode::generate(int maxOpNumber, CodeOptions options) +{ + refreshSeed(); + std::string code; + boostIntDistrib sizeDist (0, maxOpNumber); + boostIntGenerator rndSizeGen(gen, sizeDist); + int size = (int)rndSizeGen(); + for (auto i = 0; i < size; i++) + { + uint8_t opcode = randOpCodeGen(); + dev::eth::InstructionInfo info = dev::eth::instructionInfo((dev::eth::Instruction) opcode); + + if (info.name.find_first_of("INVALID_INSTRUCTION") > 0) + { + //Byte code is yet not implemented + if (options == CodeOptions::DontUseUndefinedOpCodes) + { + i--; + continue; + } + } + else + code += fillArguments(info.args); + code += toCompactHex(opcode); + } + return code; +} + +std::string RandomCode::randomUniInt() +{ + refreshSeed(); + return "0x" + toCompactHex((int)randUniIntGen()); +} + +void RandomCode::refreshSeed() +{ + auto now = std::chrono::steady_clock::now().time_since_epoch(); + auto timeSinceEpoch = std::chrono::duration_cast(now).count(); + gen.seed(static_cast(timeSinceEpoch)); +} + +} +} diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h new file mode 100644 index 000000000..c3e15a24f --- /dev/null +++ b/test/fuzzTesting/fuzzHelper.h @@ -0,0 +1,75 @@ +/* + 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 fuzzHelper.h + * @author Dimitry Khokhlov + * @date 2015 + */ + +#include +#include +#include + +#include +#include +#include + +#pragma once + +namespace dev +{ +namespace test +{ + +typedef boost::random::uniform_int_distribution<> boostIntDistrib; +typedef boost::random::variate_generator boostIntGenerator; + +enum class CodeOptions +{ + UseUndefinedOpCodes, + DontUseUndefinedOpCodes +}; + +class RandomCode +{ +public: + /// Generate random vm code + static std::string generate(int maxOpNumber = 1, CodeOptions options = CodeOptions::DontUseUndefinedOpCodes); + + /// Generate random byte string of a given length + static std::string rndByteSequence(int length = 1); + + /// Generate random uniForm Int with reasonable value 0..0x7fffffff + static std::string randomUniInt(); + +private: + static std::string fillArguments(int num); + static void refreshSeed(); + + static boost::random::mt19937 gen; ///< Random generator + static boostIntDistrib opCodeDist; ///< 0..255 opcodes + static boostIntDistrib opLengDist; ///< 1..32 byte string + static boostIntDistrib uniIntDist; ///< 0..0x7fffffff + + static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from + static boostIntGenerator randOpCodeGen; ///< Generate random value from opCodeDist + static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist +}; + + + +} +} diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 0ea8b95a8..a654712fe 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -19,7 +19,7 @@ * @date 2015 * block test functions. */ - +#include "test/fuzzTesting/fuzzHelper.h" #include #include #include @@ -811,4 +811,11 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) dev::test::userDefinedTest(dev::test::doBlockchainTests); } +BOOST_AUTO_TEST_CASE(rndCode) +{ + cerr << "Testing Random Code: "; + std::string code = dev::test::RandomCode::generate(10); + cerr << code; +} + BOOST_AUTO_TEST_SUITE_END() From 7788d4f6d9eacebbafcd740c2cb652233ef24bb3 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 22 May 2015 17:28:47 +0300 Subject: [PATCH 56/90] undo vmTest --- test/libethereum/blockchain.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index a654712fe..085a855d4 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -813,8 +813,16 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) BOOST_AUTO_TEST_CASE(rndCode) { + std::string code; cerr << "Testing Random Code: "; - std::string code = dev::test::RandomCode::generate(10); + try + { + code = dev::test::RandomCode::generate(10); + } + catch(...) + { + BOOST_ERROR("Exception thrown when generating random code!"); + } cerr << code; } From 3c6f053a79ab75370aface29579263583fc610d4 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 22 May 2015 21:04:12 +0300 Subject: [PATCH 57/90] Random Codes With Probability --- test/fuzzTesting/createRandomStateTest.cpp | 175 +++++++++++++++------ test/fuzzTesting/fuzzHelper.cpp | 16 +- test/fuzzTesting/fuzzHelper.h | 35 ++++- 3 files changed, 169 insertions(+), 57 deletions(-) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index 65bfa2cfa..f93cbfa6e 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -44,60 +44,139 @@ using namespace json_spirit; using namespace dev; void doStateTests(json_spirit::mValue& _v); +void doChristophAlgo(); +void doRandomCodeAlgo(); + +string const c_testExample = R"( +{ + "randomStatetest" : { + "env" : { + "currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5", + "currentDifficulty" : "5623894562375", + "currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "currentNumber" : "0", + "currentTimestamp" : "1", + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "0", + "code" : "0x6001600101600055", + "nonce" : "0", + "storage" : { + } + }, + "945304eb96065b2a98b57a48a06ae28d285a71b5" : { + "balance" : "46", + "code" : "0x6000355415600957005b60203560003555", + "nonce" : "0", + "storage" : { + } + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "code" : "0x", + "nonce" : "0", + "storage" : { + } + } + }, + "transaction" : { + "data" : "0x42", + "gasLimit" : "400000", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000" + } + } +} +)"; int main(int argc, char *argv[]) +{ + //doChristophAlgo(); + doRandomCodeAlgo(); + return 0; +} + +void doChristophAlgo() { g_logVerbosity = 0; - string randomCode = dev::test::RandomCode::generate(25); - string const s = R"( + // create random code + boost::random::mt19937 gen; + auto now = chrono::steady_clock::now().time_since_epoch(); + auto timeSinceEpoch = chrono::duration_cast(now).count(); + gen.seed(static_cast(timeSinceEpoch)); + + // set min and max length of the random evm code + boost::random::uniform_int_distribution<> lengthOfCodeDist(8, 24); + boost::random::uniform_int_distribution<> reasonableInputValuesSize(0, 7); + boost::random::uniform_int_distribution<> opcodeDist(0, 255); + boost::random::uniform_int_distribution<> BlockInfoOpcodeDist(0x40, 0x45); + boost::random::uniform_int_distribution<> uniformInt(0, 0x7fffffff); + boost::random::variate_generator > randGenInputValue(gen, reasonableInputValuesSize); + boost::random::variate_generator > randGenUniformInt(gen, uniformInt); + boost::random::variate_generator > randGen(gen, opcodeDist); + boost::random::variate_generator > randGenBlockInfoOpcode(gen, BlockInfoOpcodeDist); + + std::vector reasonableInputValues; + reasonableInputValues.push_back(0); + reasonableInputValues.push_back(1); + reasonableInputValues.push_back(50000); + reasonableInputValues.push_back(u256("0x10000000000000000000000000000000000000000")); + reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffff")); + reasonableInputValues.push_back(u256("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe")); + reasonableInputValues.push_back(u256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); + reasonableInputValues.push_back(u256("0x945304eb96065b2a98b57a48a06ae28d285a71b5")); + reasonableInputValues.push_back(randGenUniformInt()); + + int lengthOfCode = lengthOfCodeDist(gen); + string randomCode; + for (int i = 0; i < lengthOfCode; ++i) { - "randomStatetest" : { - "env" : { - "currentCoinbase" : "945304eb96065b2a98b57a48a06ae28d285a71b5", - "currentDifficulty" : "5623894562375", - "currentGasLimit" : "115792089237316195423570985008687907853269984665640564039457584007913129639935", - "currentNumber" : "0", - "currentTimestamp" : "1", - "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" - }, - "pre" : { - "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { - "balance" : "0", - "code" : "0x6001600101600055", - "nonce" : "0", - "storage" : { - } - }, - "945304eb96065b2a98b57a48a06ae28d285a71b5" : { - "balance" : "46", - "code" : "0x6000355415600957005b60203560003555", - "nonce" : "0", - "storage" : { - } - }, - "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { - "balance" : "1000000000000000000", - "code" : "0x", - "nonce" : "0", - "storage" : { - } - } - }, - "transaction" : { - "data" : "0x42", - "gasLimit" : "400000", - "gasPrice" : "1", - "nonce" : "0", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "100000" - } + // pre-fill stack to avoid that most of the test fail with a stackunderflow + if (i < 8 && (randGen() < 192)) + { + randomCode += randGen() < 32 ? toHex(toCompactBigEndian((uint8_t)randGenBlockInfoOpcode())) : "7f" + toHex(reasonableInputValues[randGenInputValue()]); + continue; } + uint8_t opcode = randGen(); + // disregard all invalid commands, except of one (0x0c) + if ((dev::eth::isValidInstruction(dev::eth::Instruction(opcode)) || (randGen() > 250))) + randomCode += toHex(toCompactBigEndian(opcode)); + else + i--; } -)"; + mValue v; - read_string(s, v); + read_string(c_testExample, v); + // insert new random code + v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode + (randGen() > 128 ? "55" : "") + (randGen() > 128 ? "60005155" : ""); + // insert new data in tx + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomCode; + // insert new value in tx + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = toString(randGenUniformInt()); + // insert new gasLimit in tx + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = "0x" + toHex(toCompactBigEndian((int)randGenUniformInt())); + // fill test + doStateTests(v); + // stream to output for further handling by the bash script + cout << json_spirit::write_string(v, true); +} + +void doRandomCodeAlgo() +{ + g_logVerbosity = 0; + dev::test::RandomCodeOptions options; + options.setWeight(dev::eth::Instruction::STOP, 10); //default 50 + options.setWeight(dev::eth::Instruction::SSTORE, 70); + string randomCode = dev::test::RandomCode::generate(15); + + mValue v; + read_string(c_testExample, v); // insert new random code v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode; @@ -116,10 +195,10 @@ int main(int argc, char *argv[]) // stream to output for further handling by the bash script cout << json_spirit::write_string(v, true); - - return 0; } + + void doStateTests(json_spirit::mValue& _v) { eth::VMFactory::setKind(eth::VMKind::Interpreter); @@ -159,3 +238,5 @@ void doStateTests(json_spirit::mValue& _v) } } + + diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 5b3b0a7f0..ba0e58575 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -40,7 +40,6 @@ boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist) boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); - std::string RandomCode::rndByteSequence(int length) { refreshSeed(); @@ -67,22 +66,28 @@ std::string RandomCode::fillArguments(int num) } //generate smart random code -std::string RandomCode::generate(int maxOpNumber, CodeOptions options) +std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) { refreshSeed(); std::string code; + + //random opCode amount boostIntDistrib sizeDist (0, maxOpNumber); boostIntGenerator rndSizeGen(gen, sizeDist); int size = (int)rndSizeGen(); + + boostWeightGenerator randOpCodeWeight (gen, options.opCodeProbability); + bool weightsDefined = options.opCodeProbability.probabilities().size() == 255; + for (auto i = 0; i < size; i++) { - uint8_t opcode = randOpCodeGen(); + uint8_t opcode = weightsDefined ? randOpCodeWeight() : randOpCodeGen(); dev::eth::InstructionInfo info = dev::eth::instructionInfo((dev::eth::Instruction) opcode); if (info.name.find_first_of("INVALID_INSTRUCTION") > 0) { //Byte code is yet not implemented - if (options == CodeOptions::DontUseUndefinedOpCodes) + if (options.useUndefinedOpCodes == false) { i--; continue; @@ -90,7 +95,8 @@ std::string RandomCode::generate(int maxOpNumber, CodeOptions options) } else code += fillArguments(info.args); - code += toCompactHex(opcode); + std::string byte = toCompactHex(opcode); + code += (byte == "") ? "00" : byte; } return code; } diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index c3e15a24f..29d3b19ea 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -26,6 +26,7 @@ #include #include #include +#include #pragma once @@ -35,19 +36,43 @@ namespace test { typedef boost::random::uniform_int_distribution<> boostIntDistrib; +typedef boost::random::discrete_distribution<> boostDescreteDistrib; + typedef boost::random::variate_generator boostIntGenerator; +typedef boost::random::variate_generator boostWeightGenerator; -enum class CodeOptions +struct RandomCodeOptions { - UseUndefinedOpCodes, - DontUseUndefinedOpCodes +public: + RandomCodeOptions() : useUndefinedOpCodes(false) { + //each op code with same weight-probability + for (auto i = 0; i < 255; i++) + mapWeights.insert(std::pair(i, 50)); + setWeights(); + } + void setWeight(dev::eth::Instruction opCode, int weight) + { + mapWeights.at((int)opCode) = weight; + setWeights(); + } + bool useUndefinedOpCodes; + boostDescreteDistrib opCodeProbability; +private: + void setWeights() + { + std::vector weights; + for (auto const& element: mapWeights) + weights.push_back(element.second); + opCodeProbability = boostDescreteDistrib(weights); + } + std::map mapWeights; }; class RandomCode { public: /// Generate random vm code - static std::string generate(int maxOpNumber = 1, CodeOptions options = CodeOptions::DontUseUndefinedOpCodes); + static std::string generate(int maxOpNumber = 1, RandomCodeOptions options = RandomCodeOptions()); /// Generate random byte string of a given length static std::string rndByteSequence(int length = 1); @@ -64,7 +89,7 @@ private: static boostIntDistrib opLengDist; ///< 1..32 byte string static boostIntDistrib uniIntDist; ///< 0..0x7fffffff - static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from + static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from uniIntDist static boostIntGenerator randOpCodeGen; ///< Generate random value from opCodeDist static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist }; From b43c4f11456c0eea5fea3bf17fc6e57fb1f90c76 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Tue, 26 May 2015 16:27:22 +0300 Subject: [PATCH 58/90] Random test code --- test/TestHelper.cpp | 4 +++- test/TestHelper.h | 1 + test/fuzzTesting/createRandomStateTest.cpp | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 476d1ecf9..4836ce7f3 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -328,7 +328,7 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost) { // export output - m_TestObject["out"] = _output.size() > 4096 ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add); + m_TestObject["out"] = (_output.size() > 4096 && !Options::get().fulloutput) ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add); // export logs m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); @@ -760,6 +760,8 @@ Options::Options() else singleTestName = std::move(name1); } + else if (arg == "--fulloutput") + fulloutput = true; } } diff --git a/test/TestHelper.h b/test/TestHelper.h index fc6c77fad..8f0c73bf3 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -184,6 +184,7 @@ public: bool stats = false; ///< Execution time stats std::string statsOutFile; ///< Stats output file. "out" for standard output bool checkState = false;///< Throw error when checking test states + bool fulloutput = false;///< Replace large output to just it's length /// Test selection /// @{ diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index f93cbfa6e..e2c0600b6 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -173,7 +173,8 @@ void doRandomCodeAlgo() dev::test::RandomCodeOptions options; options.setWeight(dev::eth::Instruction::STOP, 10); //default 50 options.setWeight(dev::eth::Instruction::SSTORE, 70); - string randomCode = dev::test::RandomCode::generate(15); + string randomCode = dev::test::RandomCode::generate(10); + string randomData = dev::test::RandomCode::generate(10); mValue v; read_string(c_testExample, v); @@ -182,7 +183,7 @@ void doRandomCodeAlgo() v.get_obj().find("randomStatetest")->second.get_obj().find("pre")->second.get_obj().begin()->second.get_obj()["code"] = "0x" + randomCode; // insert new data in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomCode; + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomData; // insert new value in tx v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = dev::test::RandomCode::randomUniInt(); From b429e1cfde0259c0beb70a49b32d9c35319ed5de Mon Sep 17 00:00:00 2001 From: Dimitry Date: Tue, 26 May 2015 16:51:29 +0300 Subject: [PATCH 59/90] Random Code: Style --- test/fuzzTesting/createRandomStateTest.cpp | 5 ----- test/libethereum/blockchain.cpp | 15 --------------- 2 files changed, 20 deletions(-) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index e2c0600b6..622ccb1ac 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -198,8 +198,6 @@ void doRandomCodeAlgo() cout << json_spirit::write_string(v, true); } - - void doStateTests(json_spirit::mValue& _v) { eth::VMFactory::setKind(eth::VMKind::Interpreter); @@ -238,6 +236,3 @@ void doStateTests(json_spirit::mValue& _v) #endif } } - - - diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 085a855d4..67b3955ff 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -811,19 +811,4 @@ BOOST_AUTO_TEST_CASE(userDefinedFile) dev::test::userDefinedTest(dev::test::doBlockchainTests); } -BOOST_AUTO_TEST_CASE(rndCode) -{ - std::string code; - cerr << "Testing Random Code: "; - try - { - code = dev::test::RandomCode::generate(10); - } - catch(...) - { - BOOST_ERROR("Exception thrown when generating random code!"); - } - cerr << code; -} - BOOST_AUTO_TEST_SUITE_END() From 8ea48967f1aa1c4dbb9e2acf1623b48afcc41cf1 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Tue, 26 May 2015 18:24:47 +0300 Subject: [PATCH 60/90] Random Code: fulloutput option + test --- test/TestHelper.cpp | 1 - test/fuzzTesting/createRandomStateTest.cpp | 8 ++++++++ test/fuzzTesting/fuzzHelper.cpp | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 4836ce7f3..5ace49e5d 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -771,7 +771,6 @@ Options const& Options::get() return instance; } - LastHashes lastHashes(u256 _currentBlockNumber) { LastHashes ret; diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index 622ccb1ac..ea726c09d 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -96,6 +96,14 @@ string const c_testExample = R"( int main(int argc, char *argv[]) { + for (auto i = 0; i < argc; ++i) + { + auto arg = std::string{argv[i]}; + dev::test::Options& options = const_cast(dev::test::Options::get()); + if (arg == "--fulloutput") + options.fulloutput = true; + } + //doChristophAlgo(); doRandomCodeAlgo(); return 0; diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index ba0e58575..0b50868c5 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -114,5 +114,24 @@ void RandomCode::refreshSeed() gen.seed(static_cast(timeSinceEpoch)); } +BOOST_AUTO_TEST_SUITE(RandomCodeTests) + +BOOST_AUTO_TEST_CASE(rndCode) +{ + std::string code; + std::cerr << "Testing Random Code: "; + try + { + code = dev::test::RandomCode::generate(10); + } + catch(...) + { + BOOST_ERROR("Exception thrown when generating random code!"); + } + std::cerr << code; +} + +BOOST_AUTO_TEST_SUITE_END() + } } From 50d6e8cb31f9b80033ca4f92babc493a99ba75e3 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 27 May 2015 15:45:00 +0300 Subject: [PATCH 61/90] Random Code: exceptions when filling rnd StateTest --- test/fuzzTesting/createRandomStateTest.cpp | 23 ++++++++++++---------- test/fuzzTesting/fuzzHelper.h | 2 -- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index ea726c09d..c0c07b53e 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -218,15 +218,19 @@ void doStateTests(json_spirit::mValue& _v) assert(o.count("env") > 0); assert(o.count("pre") > 0); assert(o.count("transaction") > 0); - - test::ImportTest importer(o, true); - - eth::State theState = importer.m_statePre; bytes output; + eth::State theState; try { - output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + test::ImportTest importer(o, true); + eth::State theState = importer.m_statePre; + output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + #if ETH_FATDB + importer.exportTest(output, theState); + #else + cout << "You can not fill tests when FATDB is switched off"; + #endif } catch (Exception const& _e) { @@ -237,10 +241,9 @@ void doStateTests(json_spirit::mValue& _v) { cnote << "state execution did throw an exception: " << _e.what(); } -#if ETH_FATDB - importer.exportTest(output, theState); -#else - cout << "You can not fill tests when FATDB is switched off"; -#endif + catch (...) + { + cnote << "state execution did throw an exception!"; + } } } diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 29d3b19ea..26580cb26 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -94,7 +94,5 @@ private: static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist }; - - } } From 0021abf270c20d74796e64609a35e44a57489404 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 27 May 2015 22:51:53 +0300 Subject: [PATCH 62/90] Random Code: smart opcode fuzz --- test/fuzzTesting/createRandomStateTest.cpp | 15 ++- test/fuzzTesting/fuzzHelper.cpp | 119 ++++++++++++++++++--- test/fuzzTesting/fuzzHelper.h | 41 ++++--- 3 files changed, 134 insertions(+), 41 deletions(-) diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index c0c07b53e..d0cd82c01 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -181,8 +181,15 @@ void doRandomCodeAlgo() dev::test::RandomCodeOptions options; options.setWeight(dev::eth::Instruction::STOP, 10); //default 50 options.setWeight(dev::eth::Instruction::SSTORE, 70); - string randomCode = dev::test::RandomCode::generate(10); - string randomData = dev::test::RandomCode::generate(10); + options.setWeight(dev::eth::Instruction::CALL, 75); + options.addAddress(Address("0xffffffffffffffffffffffffffffffffffffffff")); + options.addAddress(Address("0x1000000000000000000000000000000000000000")); + options.addAddress(Address("0x095e7baea6a6c7c4c2dfeb977efac326af552d87")); //coinbase + options.addAddress(Address("0x945304eb96065b2a98b57a48a06ae28d285a71b5")); + options.addAddress(Address("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b")); + options.smartCodeProbability = 35; + string randomCode = dev::test::RandomCode::generate(10, options); + string randomData = dev::test::RandomCode::generate(10, options); mValue v; read_string(c_testExample, v); @@ -194,10 +201,10 @@ void doRandomCodeAlgo() v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["data"] = "0x" + randomData; // insert new value in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = dev::test::RandomCode::randomUniInt(); + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["value"] = dev::test::RandomCode::randomUniIntHex(); // insert new gasLimit in tx - v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = dev::test::RandomCode::randomUniInt(); + v.get_obj().find("randomStatetest")->second.get_obj().find("transaction")->second.get_obj()["gasLimit"] = dev::test::RandomCode::randomUniIntHex(); // fill test doStateTests(v); diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 0b50868c5..b4905709e 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -40,11 +40,11 @@ boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist) boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); -std::string RandomCode::rndByteSequence(int length) +std::string RandomCode::rndByteSequence(int length, SizeStrictness sizeType) { refreshSeed(); std::string hash; - length = std::max(1, length); + length = (sizeType == SizeStrictness::Strict) ? std::max(1, length) : randomUniInt() % length; for (auto i = 0; i < length; i++) { uint8_t byte = randOpCodeGen(); @@ -53,18 +53,6 @@ std::string RandomCode::rndByteSequence(int length) return hash; } -std::string RandomCode::fillArguments(int num) -{ - std::string code; - for (auto i = 0; i < num; i++) - { - int length = randOpLengGen(); - int pushCode = 96 + length - 1; - code += toCompactHex(pushCode) + rndByteSequence(length); - } - return code; -} - //generate smart random code std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) { @@ -94,19 +82,25 @@ std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) } } else - code += fillArguments(info.args); + code += fillArguments((dev::eth::Instruction) opcode, options); std::string byte = toCompactHex(opcode); code += (byte == "") ? "00" : byte; } return code; } -std::string RandomCode::randomUniInt() +std::string RandomCode::randomUniIntHex() { refreshSeed(); return "0x" + toCompactHex((int)randUniIntGen()); } +int RandomCode::randomUniInt() +{ + refreshSeed(); + return (int)randUniIntGen(); +} + void RandomCode::refreshSeed() { auto now = std::chrono::steady_clock::now().time_since_epoch(); @@ -114,6 +108,99 @@ void RandomCode::refreshSeed() gen.seed(static_cast(timeSinceEpoch)); } +std::string RandomCode::getPushCode(std::string hex) +{ + int length = hex.length()/2; + int pushCode = 96 + length - 1; + return toCompactHex(pushCode) + hex; +} + +std::string RandomCode::getPushCode(int value) +{ + std::string hexString = toCompactHex(value); + return getPushCode(hexString); +} + +std::string RandomCode::fillArguments(dev::eth::Instruction opcode, RandomCodeOptions options) +{ + dev::eth::InstructionInfo info = dev::eth::instructionInfo(opcode); + + std::string code; + bool smart = false; + unsigned num = info.args; + int rand = randOpCodeGen() % 100; + if (rand < options.smartCodeProbability) + smart = true; + + if (smart) + { + switch (opcode) + { + case dev::eth::Instruction::CALL: + //(CALL gaslimit address value memstart1 memlen1 memstart2 memlen2) + code += getPushCode(randUniIntGen() % 32); //memlen2 + code += getPushCode(randUniIntGen() % 32); //memstart2 + code += getPushCode(randUniIntGen() % 32); //memlen1 + code += getPushCode(randUniIntGen() % 32); //memlen1 + code += getPushCode(randUniIntGen()); //value + code += getPushCode(toString(options.getRandomAddress()));//address + code += getPushCode(randUniIntGen()); //gaslimit + break; + default: + smart = false; + } + } + + if (smart == false) + for (unsigned i = 0; i < num; i++) + { + //generate random parameters + int length = randOpLengGen(); + code += getPushCode(rndByteSequence(length)); + } + return code; +} + + +//Ramdom Code Options +RandomCodeOptions::RandomCodeOptions() : useUndefinedOpCodes(false), smartCodeProbability(50) +{ + //each op code with same weight-probability + for (auto i = 0; i < 255; i++) + mapWeights.insert(std::pair(i, 50)); + setWeights(); +} + +void RandomCodeOptions::setWeight(dev::eth::Instruction opCode, int weight) +{ + mapWeights.at((int)opCode) = weight; + setWeights(); +} + +void RandomCodeOptions::addAddress(dev::Address address) +{ + addressList.push_back(address); +} + +dev::Address RandomCodeOptions::getRandomAddress() +{ + if (addressList.size() > 0) + { + int index = RandomCode::randomUniInt() % addressList.size(); + return addressList[index]; + } + return Address(RandomCode::rndByteSequence(20)); +} + +void RandomCodeOptions::setWeights() +{ + std::vector weights; + for (auto const& element: mapWeights) + weights.push_back(element.second); + opCodeProbability = boostDescreteDistrib(weights); +} + + BOOST_AUTO_TEST_SUITE(RandomCodeTests) BOOST_AUTO_TEST_CASE(rndCode) diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 26580cb26..593f49328 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -44,28 +44,24 @@ typedef boost::random::variate_generator struct RandomCodeOptions { public: - RandomCodeOptions() : useUndefinedOpCodes(false) { - //each op code with same weight-probability - for (auto i = 0; i < 255; i++) - mapWeights.insert(std::pair(i, 50)); - setWeights(); - } - void setWeight(dev::eth::Instruction opCode, int weight) - { - mapWeights.at((int)opCode) = weight; - setWeights(); - } + RandomCodeOptions(); + void setWeight(dev::eth::Instruction opCode, int weight); + void addAddress(dev::Address address); + dev::Address getRandomAddress(); + bool useUndefinedOpCodes; + int smartCodeProbability; boostDescreteDistrib opCodeProbability; private: - void setWeights() - { - std::vector weights; - for (auto const& element: mapWeights) - weights.push_back(element.second); - opCodeProbability = boostDescreteDistrib(weights); - } + void setWeights(); std::map mapWeights; + std::vector addressList; +}; + +enum class SizeStrictness +{ + Strict, + Random }; class RandomCode @@ -75,13 +71,16 @@ public: static std::string generate(int maxOpNumber = 1, RandomCodeOptions options = RandomCodeOptions()); /// Generate random byte string of a given length - static std::string rndByteSequence(int length = 1); + static std::string rndByteSequence(int length = 1, SizeStrictness sizeType = SizeStrictness::Strict); /// Generate random uniForm Int with reasonable value 0..0x7fffffff - static std::string randomUniInt(); + static std::string randomUniIntHex(); + static int randomUniInt(); private: - static std::string fillArguments(int num); + static std::string fillArguments(dev::eth::Instruction opcode, RandomCodeOptions options); + static std::string getPushCode(int value); + static std::string getPushCode(std::string hex); static void refreshSeed(); static boost::random::mt19937 gen; ///< Random generator From b1f4f683268792fd11c4a092acc5af743beb2397 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Fri, 29 May 2015 17:06:11 +0300 Subject: [PATCH 63/90] Random Code: cath fill exceptions --- test/TestHelper.cpp | 2 +- test/fuzzTesting/createRandomStateTest.cpp | 38 ++++++++++++---------- test/fuzzTesting/fuzzHelper.cpp | 2 +- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 5ace49e5d..793e05652 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -588,7 +588,7 @@ void userDefinedTest(std::function doTests) oSingleTest[pos->first] = pos->second; json_spirit::mValue v_singleTest(oSingleTest); - doTests(v_singleTest, false); + doTests(v_singleTest, test::Options::get().fillTests); } catch (Exception const& _e) { diff --git a/test/fuzzTesting/createRandomStateTest.cpp b/test/fuzzTesting/createRandomStateTest.cpp index d0cd82c01..d533ac2da 100644 --- a/test/fuzzTesting/createRandomStateTest.cpp +++ b/test/fuzzTesting/createRandomStateTest.cpp @@ -226,31 +226,33 @@ void doStateTests(json_spirit::mValue& _v) assert(o.count("pre") > 0); assert(o.count("transaction") > 0); bytes output; - eth::State theState; try { test::ImportTest importer(o, true); eth::State theState = importer.m_statePre; - output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; - #if ETH_FATDB - importer.exportTest(output, theState); - #else - cout << "You can not fill tests when FATDB is switched off"; - #endif - } - catch (Exception const& _e) - { - cnote << "state execution did throw an exception: " << diagnostic_information(_e); - theState.commit(); - } - catch (std::exception const& _e) - { - cnote << "state execution did throw an exception: " << _e.what(); + try + { + output = theState.execute(test::lastHashes(importer.m_environment.currentBlock.number), importer.m_transaction).output; + } + catch (Exception const& _e) + { + cnote << "state execution did throw an exception: " << diagnostic_information(_e); + theState.commit(); + } + catch (std::exception const& _e) + { + cnote << "state execution did throw an exception: " << _e.what(); + } +#if ETH_FATDB + importer.exportTest(output, theState); +#else + cout << "You can not fill tests when FATDB is switched off"; +#endif } - catch (...) + catch(...) { - cnote << "state execution did throw an exception!"; + cnote << "Error filling test, probably..."; } } } diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index b4905709e..4ddd30c0f 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -128,7 +128,7 @@ std::string RandomCode::fillArguments(dev::eth::Instruction opcode, RandomCodeOp std::string code; bool smart = false; unsigned num = info.args; - int rand = randOpCodeGen() % 100; + int rand = randUniIntGen() % 100; if (rand < options.smartCodeProbability) smart = true; From b6d904167690f43c1180e5bffc32339df7e7ad0f Mon Sep 17 00:00:00 2001 From: Dimitry Date: Fri, 29 May 2015 17:33:24 +0300 Subject: [PATCH 64/90] Random code: style --- test/fuzzTesting/fuzzHelper.cpp | 46 ++++++++++++++++----------------- test/fuzzTesting/fuzzHelper.h | 14 +++++----- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 4ddd30c0f..7d7896947 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -40,12 +40,12 @@ boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist) boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); -std::string RandomCode::rndByteSequence(int length, SizeStrictness sizeType) +std::string RandomCode::rndByteSequence(int _length, SizeStrictness sizeType) { refreshSeed(); std::string hash; - length = (sizeType == SizeStrictness::Strict) ? std::max(1, length) : randomUniInt() % length; - for (auto i = 0; i < length; i++) + _length = (sizeType == SizeStrictness::Strict) ? std::max(1, _length) : randomUniInt() % _length; + for (auto i = 0; i < _length; i++) { uint8_t byte = randOpCodeGen(); hash += toCompactHex(byte); @@ -54,18 +54,18 @@ std::string RandomCode::rndByteSequence(int length, SizeStrictness sizeType) } //generate smart random code -std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) +std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options) { refreshSeed(); std::string code; //random opCode amount - boostIntDistrib sizeDist (0, maxOpNumber); + boostIntDistrib sizeDist (0, _maxOpNumber); boostIntGenerator rndSizeGen(gen, sizeDist); int size = (int)rndSizeGen(); - boostWeightGenerator randOpCodeWeight (gen, options.opCodeProbability); - bool weightsDefined = options.opCodeProbability.probabilities().size() == 255; + boostWeightGenerator randOpCodeWeight (gen, _options.opCodeProbability); + bool weightsDefined = _options.opCodeProbability.probabilities().size() == 255; for (auto i = 0; i < size; i++) { @@ -75,14 +75,14 @@ std::string RandomCode::generate(int maxOpNumber, RandomCodeOptions options) if (info.name.find_first_of("INVALID_INSTRUCTION") > 0) { //Byte code is yet not implemented - if (options.useUndefinedOpCodes == false) + if (_options.useUndefinedOpCodes == false) { i--; continue; } } else - code += fillArguments((dev::eth::Instruction) opcode, options); + code += fillArguments((dev::eth::Instruction) opcode, _options); std::string byte = toCompactHex(opcode); code += (byte == "") ? "00" : byte; } @@ -108,33 +108,33 @@ void RandomCode::refreshSeed() gen.seed(static_cast(timeSinceEpoch)); } -std::string RandomCode::getPushCode(std::string hex) +std::string RandomCode::getPushCode(std::string const& _hex) { - int length = hex.length()/2; + int length = _hex.length() / 2; int pushCode = 96 + length - 1; - return toCompactHex(pushCode) + hex; + return toCompactHex(pushCode) + _hex; } -std::string RandomCode::getPushCode(int value) +std::string RandomCode::getPushCode(int _value) { - std::string hexString = toCompactHex(value); + std::string hexString = toCompactHex(_value); return getPushCode(hexString); } -std::string RandomCode::fillArguments(dev::eth::Instruction opcode, RandomCodeOptions options) +std::string RandomCode::fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const& _options) { - dev::eth::InstructionInfo info = dev::eth::instructionInfo(opcode); + dev::eth::InstructionInfo info = dev::eth::instructionInfo(_opcode); std::string code; bool smart = false; unsigned num = info.args; int rand = randUniIntGen() % 100; - if (rand < options.smartCodeProbability) + if (rand < _options.smartCodeProbability) smart = true; if (smart) { - switch (opcode) + switch (_opcode) { case dev::eth::Instruction::CALL: //(CALL gaslimit address value memstart1 memlen1 memstart2 memlen2) @@ -143,7 +143,7 @@ std::string RandomCode::fillArguments(dev::eth::Instruction opcode, RandomCodeOp code += getPushCode(randUniIntGen() % 32); //memlen1 code += getPushCode(randUniIntGen() % 32); //memlen1 code += getPushCode(randUniIntGen()); //value - code += getPushCode(toString(options.getRandomAddress()));//address + code += getPushCode(toString(_options.getRandomAddress()));//address code += getPushCode(randUniIntGen()); //gaslimit break; default: @@ -171,15 +171,15 @@ RandomCodeOptions::RandomCodeOptions() : useUndefinedOpCodes(false), smartCodePr setWeights(); } -void RandomCodeOptions::setWeight(dev::eth::Instruction opCode, int weight) +void RandomCodeOptions::setWeight(dev::eth::Instruction _opCode, int _weight) { - mapWeights.at((int)opCode) = weight; + mapWeights.at((int)_opCode) = _weight; setWeights(); } -void RandomCodeOptions::addAddress(dev::Address address) +void RandomCodeOptions::addAddress(dev::Address const& _address) { - addressList.push_back(address); + addressList.push_back(_address); } dev::Address RandomCodeOptions::getRandomAddress() diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 593f49328..7cdce54ac 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -45,8 +45,8 @@ struct RandomCodeOptions { public: RandomCodeOptions(); - void setWeight(dev::eth::Instruction opCode, int weight); - void addAddress(dev::Address address); + void setWeight(dev::eth::Instruction _opCode, int _weight); + void addAddress(dev::Address const& _address); dev::Address getRandomAddress(); bool useUndefinedOpCodes; @@ -68,19 +68,19 @@ class RandomCode { public: /// Generate random vm code - static std::string generate(int maxOpNumber = 1, RandomCodeOptions options = RandomCodeOptions()); + static std::string generate(int _maxOpNumber = 1, RandomCodeOptions _options = RandomCodeOptions()); /// Generate random byte string of a given length - static std::string rndByteSequence(int length = 1, SizeStrictness sizeType = SizeStrictness::Strict); + static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict); /// Generate random uniForm Int with reasonable value 0..0x7fffffff static std::string randomUniIntHex(); static int randomUniInt(); private: - static std::string fillArguments(dev::eth::Instruction opcode, RandomCodeOptions options); - static std::string getPushCode(int value); - static std::string getPushCode(std::string hex); + static std::string fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const& _options); + static std::string getPushCode(int _value); + static std::string getPushCode(std::string const& _hex); static void refreshSeed(); static boost::random::mt19937 gen; ///< Random generator From 3bcee73c84f9dc169adc5351e225e6996d043d51 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Mon, 1 Jun 2015 14:07:31 +0300 Subject: [PATCH 65/90] Random Code: build issues --- test/fuzzTesting/fuzzHelper.cpp | 6 +++--- test/fuzzTesting/fuzzHelper.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/fuzzTesting/fuzzHelper.cpp b/test/fuzzTesting/fuzzHelper.cpp index 7d7896947..3b6cf19c9 100644 --- a/test/fuzzTesting/fuzzHelper.cpp +++ b/test/fuzzTesting/fuzzHelper.cpp @@ -40,11 +40,11 @@ boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist) boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); -std::string RandomCode::rndByteSequence(int _length, SizeStrictness sizeType) +std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType) { refreshSeed(); std::string hash; - _length = (sizeType == SizeStrictness::Strict) ? std::max(1, _length) : randomUniInt() % _length; + _length = (_sizeType == SizeStrictness::Strict) ? std::max(1, _length) : randomUniInt() % _length; for (auto i = 0; i < _length; i++) { uint8_t byte = randOpCodeGen(); @@ -182,7 +182,7 @@ void RandomCodeOptions::addAddress(dev::Address const& _address) addressList.push_back(_address); } -dev::Address RandomCodeOptions::getRandomAddress() +dev::Address RandomCodeOptions::getRandomAddress() const { if (addressList.size() > 0) { diff --git a/test/fuzzTesting/fuzzHelper.h b/test/fuzzTesting/fuzzHelper.h index 7cdce54ac..371e40fbf 100644 --- a/test/fuzzTesting/fuzzHelper.h +++ b/test/fuzzTesting/fuzzHelper.h @@ -47,7 +47,7 @@ public: RandomCodeOptions(); void setWeight(dev::eth::Instruction _opCode, int _weight); void addAddress(dev::Address const& _address); - dev::Address getRandomAddress(); + dev::Address getRandomAddress() const; bool useUndefinedOpCodes; int smartCodeProbability; From b81ae7d4708f088f44f04eb5c7a5eca003aba404 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 1 Jun 2015 18:30:05 +0200 Subject: [PATCH 66/90] Do not put duplicate labels for accessor functions. --- libsolidity/Compiler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 93d786bed..6425367dd 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -288,7 +288,6 @@ bool Compiler::visit(VariableDeclaration const& _variableDeclaration) m_breakTags.clear(); m_continueTags.clear(); - m_context << m_context.getFunctionEntryLabel(_variableDeclaration); ExpressionCompiler(m_context, m_optimize).appendStateVariableAccessor(_variableDeclaration); return false; From 06f5bfc2cff3ebf66094854f3fc0ffd94859ec7f Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Jun 2015 16:51:48 +0200 Subject: [PATCH 67/90] add ambiguous push test --- .../vmPushDupSwapTestFiller.json | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/test/libevm/VMTestsFiller/vmPushDupSwapTestFiller.json b/test/libevm/VMTestsFiller/vmPushDupSwapTestFiller.json index f1c9c676c..00253eabd 100644 --- a/test/libevm/VMTestsFiller/vmPushDupSwapTestFiller.json +++ b/test/libevm/VMTestsFiller/vmPushDupSwapTestFiller.json @@ -2446,5 +2446,64 @@ "gasPrice" : "100000000000000", "gas" : "100000" } + }, + + + "push32Undefined": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "100000000000000000000000", + "nonce" : "0", + "code" : "0x7f010203600055", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "100000" + } + }, + + "push32Undefined2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "1000000", + "currentDifficulty" : "256", + "currentTimestamp" : "1", + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "pre" : { + "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { + "balance" : "100000000000000000000000", + "nonce" : "0", + "code" : "0x7f0102030000000000000000000000000000000000000000000000000000000000600055", + "storage": {} + } + }, + "exec" : { + "address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6", + "origin" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "caller" : "cd1722f3947def4cf144679da39c4c32bdc35681", + "value" : "1000000000000000000", + "data" : "", + "gasPrice" : "100000000000000", + "gas" : "100000" + } } + + } From 76868a89edc476065329b5fe52bcb667bcc3e94e Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Jun 2015 16:57:53 +0200 Subject: [PATCH 68/90] add debug info for BlockQueueStatus --- libethereum/BlockQueue.cpp | 12 ++++++++++++ libethereum/BlockQueue.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index c2bd35afc..013d8a000 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -418,3 +418,15 @@ void BlockQueue::retryAllUnknown() m_unknown.clear(); m_moreToVerify.notify_all(); } + +std::ostream& dev::eth::operator<<(std::ostream& _out, BlockQueueStatus const& _bqs) +{ + _out << "verified: " << _bqs.verified << endl; + _out << "verifying: " << _bqs.verifying << endl; + _out << "unverified: " << _bqs.unverified << endl; + _out << "future: " << _bqs.future << endl; + _out << "unknown: " << _bqs.unknown << endl; + _out << "bad: " << _bqs.bad << endl; + + return _out; +} diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index d0437739d..45043559b 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -136,5 +136,7 @@ private: bool m_deleting = false; ///< Exit condition for verifiers. }; +std::ostream& operator<<(std::ostream& _out, BlockQueueStatus const& _s); + } } From 30b531d0ad0442b890d8222d9e1e837fe5bb3084 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Jun 2015 16:59:06 +0200 Subject: [PATCH 69/90] fix block chain tests creation --- test/libethereum/blockchain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 0ff7e57f3..72cbc51dc 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -168,6 +168,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { uncleBlockQueue.import(&uncle.out(), bc); uncleBlockQueueList.push_back(uncle.out()); + // wait until block is verified + this_thread::sleep_for(chrono::seconds(1)); } catch(...) { From fddc206d849bfb5ab9a9a4503252910d190b3a5b Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 2 Jun 2015 09:34:27 +0200 Subject: [PATCH 70/90] add EqualUncleInTwoDifferentBlocks test Conflicts: test/libethereum/blockchain.cpp --- .../BlockTestsFiller/bcUncleTestFiller.json | 123 ++++++++++++++++++ test/libethereum/blockchain.cpp | 67 ++++++---- 2 files changed, 166 insertions(+), 24 deletions(-) diff --git a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json index 761bce316..1d4d7e186 100644 --- a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json @@ -151,6 +151,10 @@ ] }, { + "blockHeader" : { + "bruncle" : "1" + }, + "transactions" : [ { "data" : "", @@ -2562,5 +2566,124 @@ ] } ] + }, + + "EqualUncleInTwoDifferentBlocks" : { + "genesisBlockHeader" : { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "0x8888f1f195afa192cfee860698584c030f4c9db1", + "difficulty" : "131072", + "extraData" : "0x42", + "gasLimit" : "3141592", + "gasUsed" : "0", + "number" : "0", + "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "receiptTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "0xf99eb1626cfa6db435c0836235942d7ccaa935f1ae247d3f1c21e495685f903a", + "timestamp" : "0x54c98c81", + "mixHash" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "nonce" : "0x0102030405060708", + "transactionsTrie" : "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + }, + "expect" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "20" + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "nonce" : "2" + } + }, + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "10000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "blocks" : [ + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "1", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + { + "bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "coinbase" : "bcde5374fce5edbc8e2a8697c15331677e6ebf0b", + "difficulty" : "131072", + "extraData" : "0x", + "gasLimit" : "3141592", + "gasUsed" : "0", + "hash" : "9de9879b6a81d1b6c4993c63c90a3c9d1e775f14572694778e828bc64972ae04", + "mixHash" : "b557f905d29ed0fca99d65d0adcce698dee97cf72a13c7cd8d7a7826b8eee770", + "nonce" : "18a524c1790fa83b", + "number" : "2", + "parentHash" : "6134fc6b5d99ee03c4aab1592640f6f9dcbc850668d75d631aee34989b938fae", + "receiptTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "stateRoot" : "ff640b30d613c35dad43e3693329e1b1ee6350f989cf46a288025a1cbfdab9cd", + "timestamp" : "0x54c98c82", + "transactionsTrie" : "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "uncleHash" : "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" + } + ] + }, + { + "transactions" : [ + { + "data" : "", + "gasLimit" : "314159", + "gasPrice" : "1", + "nonce" : "2", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "10" + } + ], + "uncleHeaders" : [ + { + "sameAsPreviousBlockUncle" : "3" + } + ] + } + ] } } diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 72cbc51dc..91234605a 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -33,6 +33,9 @@ using namespace dev::eth; namespace dev { namespace test { +typedef std::vector uncleList; +typedef std::pair blockSet; + BlockInfo constructBlock(mObject& _o); bytes createBlockRLPFromFields(mObject& _tObj); RLPStream createFullBlockFromHeader(BlockInfo const& _bi, bytes const& _txs = RLPEmptyList, bytes const& _uncles = RLPEmptyList); @@ -42,7 +45,7 @@ mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi); void overwriteBlockHeader(BlockInfo& _current_BlockHeader, mObject& _blObj); BlockInfo constructBlock(mObject& _o); void updatePoW(BlockInfo& _bi); -mArray importUncles(mObject const& blObj, vector& vBiUncles, vector const& vBiBlocks); +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet); void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) { @@ -65,8 +68,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); //Imported blocks from the start - typedef std::vector uncleList; - typedef std::pair blockSet; std::vector blockSets; importer.importState(o["pre"].get_obj(), trueState); @@ -138,7 +139,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) bc.sync(uncleQueue, state.db(), 4); bc.attemptImport(block, state.db()); vBiBlocks.push_back(BlockInfo(block)); - state.sync(bc); } @@ -156,7 +156,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) //get uncles vector vBiUncles; - blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks); + blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks, blockSets); BlockQueue uncleBlockQueue; uncleList uncleBlockQueueList; @@ -176,7 +176,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) cnote << "error in importing uncle! This produces an invalid block (May be by purpose for testing)."; } } - bc.sync(uncleBlockQueue, state.db(), 4); state.commitToMine(bc); @@ -216,6 +215,12 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) uncleStream.appendRaw(uncleRlp.out()); } + if (blObj.count("blockHeader")) + overwriteBlockHeader(current_BlockHeader, blObj); + + if (blObj.count("blockHeader") && blObj["blockHeader"].get_obj().count("bruncle")) + current_BlockHeader.populateFromParent(vBiBlocks[vBiBlocks.size() -1]); + if (vBiUncles.size()) { // update unclehash in case of invalid uncles @@ -223,9 +228,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) updatePoW(current_BlockHeader); } - if (blObj.count("blockHeader")) - overwriteBlockHeader(current_BlockHeader, blObj); - // write block header mObject oBlockHeader; writeBlockHeaderToJson(oBlockHeader, current_BlockHeader); @@ -496,36 +498,48 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) // helping functions -mArray importUncles(mObject const& blObj, vector& vBiUncles, vector const& vBiBlocks) +mArray importUncles(mObject const& _blObj, vector& _vBiUncles, vector const& _vBiBlocks, std::vector _blockSet) { // write uncle list mArray aUncleList; mObject uncleHeaderObj_pre; - for (auto const& uHObj: blObj.at("uncleHeaders").get_array()) + for (auto const& uHObj: _blObj.at("uncleHeaders").get_array()) { mObject uncleHeaderObj = uHObj.get_obj(); if (uncleHeaderObj.count("sameAsPreviousSibling")) { - writeBlockHeaderToJson(uncleHeaderObj_pre, vBiUncles[vBiUncles.size()-1]); + writeBlockHeaderToJson(uncleHeaderObj_pre, _vBiUncles[_vBiUncles.size()-1]); aUncleList.push_back(uncleHeaderObj_pre); - vBiUncles.push_back(vBiUncles[vBiUncles.size()-1]); + _vBiUncles.push_back(_vBiUncles[_vBiUncles.size()-1]); uncleHeaderObj_pre = uncleHeaderObj; continue; } if (uncleHeaderObj.count("sameAsBlock")) { - size_t number = (size_t)toInt(uncleHeaderObj["sameAsBlock"]); uncleHeaderObj.erase("sameAsBlock"); - BlockInfo currentUncle = vBiBlocks[number]; + BlockInfo currentUncle = _vBiBlocks[number]; writeBlockHeaderToJson(uncleHeaderObj, currentUncle); aUncleList.push_back(uncleHeaderObj); - vBiUncles.push_back(currentUncle); + _vBiUncles.push_back(currentUncle); uncleHeaderObj_pre = uncleHeaderObj; continue; } + + if (uncleHeaderObj.count("sameAsPreviousBlockUncle")) + { + bytes uncleRLP = _blockSet[(size_t)toInt(uncleHeaderObj["sameAsPreviousBlockUncle"])].second[0]; + BlockInfo uncleHeader(uncleRLP); + writeBlockHeaderToJson(uncleHeaderObj, uncleHeader); + aUncleList.push_back(uncleHeaderObj); + + _vBiUncles.push_back(uncleHeader); + uncleHeaderObj_pre = uncleHeaderObj; + continue; + } + string overwrite = "false"; if (uncleHeaderObj.count("overwriteAndRedoPoW")) { @@ -538,12 +552,12 @@ mArray importUncles(mObject const& blObj, vector& vBiUncles, vector& vBiUncles, vector Date: Mon, 1 Jun 2015 21:48:06 +0200 Subject: [PATCH 71/90] fix bruncle test --- test/libethereum/BlockTestsFiller/bcUncleTestFiller.json | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json index 1d4d7e186..76f0f0d46 100644 --- a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json +++ b/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json @@ -156,15 +156,6 @@ }, "transactions" : [ - { - "data" : "", - "gasLimit" : "314159", - "gasPrice" : "1", - "nonce" : "2", - "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", - "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", - "value" : "10" - } ], "uncleHeaders" : [ { From 6f9e7ef3c88446729813b566184514098f2ccd05 Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Mon, 1 Jun 2015 22:27:24 +0200 Subject: [PATCH 72/90] style --- test/libevm/VMTestsFiller/vmPushDupSwapTestFiller.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/libevm/VMTestsFiller/vmPushDupSwapTestFiller.json b/test/libevm/VMTestsFiller/vmPushDupSwapTestFiller.json index 00253eabd..1316dfb70 100644 --- a/test/libevm/VMTestsFiller/vmPushDupSwapTestFiller.json +++ b/test/libevm/VMTestsFiller/vmPushDupSwapTestFiller.json @@ -2448,7 +2448,6 @@ } }, - "push32Undefined": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", @@ -2504,6 +2503,4 @@ "gas" : "100000" } } - - } From a67d783379256d94bcb1bfbc56c2e89bf40667a2 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Tue, 2 Jun 2015 15:44:13 +0800 Subject: [PATCH 73/90] Code cleanup. --- libp2p/UDP.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libp2p/UDP.h b/libp2p/UDP.h index b032c9e73..ce2a570b2 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -115,7 +115,7 @@ class UDPSocket: UDPSocketFace, public std::enable_shared_from_this::disconnectWithError(boost::system::err } } -} \ No newline at end of file +} From 81a7f463851e308e9427959c8d6f40b00b8c75aa Mon Sep 17 00:00:00 2001 From: CJentzsch Date: Tue, 2 Jun 2015 10:13:12 +0200 Subject: [PATCH 74/90] forbid uncle to be your brother --- libethcore/Exceptions.h | 15 ++++++++------- libethereum/State.cpp | 8 ++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index 8b73c96fe..9362e4fed 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -49,27 +49,28 @@ struct FeeTooSmall: virtual dev::Exception {}; struct TooMuchGasUsed: virtual dev::Exception {}; struct ExtraDataTooBig: virtual dev::Exception {}; struct InvalidSignature: virtual dev::Exception {}; -class InvalidBlockFormat: virtual public 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 {}; -class UncleInChain: virtual public 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 {}; -class InvalidTransactionsHash: virtual public dev::Exception {}; +struct InvalidTransactionsHash: virtual dev::Exception {}; struct InvalidTransaction: virtual dev::Exception {}; struct InvalidDifficulty: virtual dev::Exception {}; -class InvalidGasLimit: virtual public 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 {}; -class InvalidNonce: virtual public dev::Exception {}; -class InvalidBlockHeaderItemCount: virtual public dev::Exception {}; -class InvalidBlockNonce: virtual public 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 {}; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index b35ef98ce..09765d9ee 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -726,6 +726,14 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement 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); // tdIncrease += uncle.difficulty; From 9ad3cdfcb5f4fc843216e093b4021c5621abc461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jun 2015 11:33:34 +0200 Subject: [PATCH 75/90] Boost mutiprecision number comparison bug workaround 2 I add fixed version of boost/multiprecision/detail/number_compare.hpp to sources. It is injected with #included if buggy version of boost detected. --- libdevcore/Common.h | 18 +- ...recision_number_compare_bug_workaround.hpp | 520 ++++++++++++++++++ 2 files changed, 524 insertions(+), 14 deletions(-) create mode 100644 libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 346bb53cf..453c17e6f 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -45,6 +45,10 @@ #pragma warning(push) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" +#include +#if (BOOST_VERSION == 105800) + #include "boost_multiprecision_number_compare_bug_workaround.hpp" +#endif #include #pragma warning(pop) #pragma GCC diagnostic pop @@ -85,20 +89,6 @@ using u160s = std::vector; using u256Set = std::set; using u160Set = std::set; -// Workaround for mixed type big int comparison bug introduced in boost 1.58 -// https://svn.boost.org/trac/boost/ticket/11328 -#define ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(_OP) \ - template auto operator _OP (_T const& a, _U const& b) -> typename std::enable_if::value && std::is_same<_U, bigint>::value, bool>::type { return (bigint)a _OP b; } \ - template auto operator _OP (_U const& a, _T const& b) -> typename std::enable_if::value && std::is_same<_U, bigint>::value, bool>::type { return a _OP (bigint)b; } - -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(==) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(!=) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(>=) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(<=) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(<) -ETH_BIGINT_WRONG_COMPARISON_WORKAROUND(>) - - extern const u256 UndefinedU256; // Map types. diff --git a/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp b/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp new file mode 100644 index 000000000..dae591dfb --- /dev/null +++ b/libdevcore/boost_multiprecision_number_compare_bug_workaround.hpp @@ -0,0 +1,520 @@ + +// This is a copy of boost/multiprecision/detail/number_compare.hpp from boost 1.59 to replace buggy version from 1.58. + +#ifdef BOOST_MP_COMPARE_HPP +#error This bug workaround header must be included before original boost/multiprecision/detail/number_compare.hpp +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Copyright 2012 John Maddock. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MP_COMPARE_HPP +#define BOOST_MP_COMPARE_HPP + +// A copy of boost/multiprecision/traits/is_backend.hpp +#ifndef BOOST_MP_IS_BACKEND_HPP +#define BOOST_MP_IS_BACKEND_HPP + +#include +#include +#include +#include +#include + +namespace boost{ namespace multiprecision{ namespace detail{ + + BOOST_MPL_HAS_XXX_TRAIT_DEF(signed_types) + BOOST_MPL_HAS_XXX_TRAIT_DEF(unsigned_types) + BOOST_MPL_HAS_XXX_TRAIT_DEF(float_types) + + template + struct is_backend + { + static const bool value = has_signed_types::value && has_unsigned_types::value && has_float_types::value; + }; + + template + struct other_backend + { + typedef typename boost::conditional< + boost::is_same, number >::value, + number, number >::type type; + }; + + template + struct number_from_backend + { + typedef typename boost::conditional < + boost::is_convertible >::value, + number, + typename other_backend::type > ::type type; + }; + + template + struct is_first_backend_imp{ static const bool value = false; }; + template + struct is_first_backend_imp{ static const bool value = is_convertible >::value || is_convertible >::value; }; + + template + struct is_first_backend : is_first_backend_imp::value, T, U> {}; + + template + struct is_second_backend_imp{ static const bool value = false; }; + template + struct is_second_backend_imp{ static const bool value = is_convertible >::value || is_convertible >::value; }; + + template + struct is_second_backend : is_second_backend_imp::value, T, U> {}; + +} +} +} + +#endif // BOOST_MP_IS_BACKEND_HPP + +// +// Comparison operators for number. +// + +namespace boost{ namespace multiprecision{ + +namespace default_ops{ + +template +inline bool eval_eq(const B& a, const B& b) +{ + return a.compare(b) == 0; +} +template +inline typename enable_if_c::value, bool>::type eval_eq(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(b); + return eval_eq(a, t.backend()); +} +template +inline typename enable_if_c::value, bool>::type eval_eq(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(a); + return eval_eq(t.backend(), b); +} + +template +inline bool eval_lt(const B& a, const B& b) +{ + return a.compare(b) < 0; +} +template +inline typename enable_if_c::value, bool>::type eval_lt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(b); + return eval_lt(a, t.backend()); +} +template +inline typename enable_if_c::value, bool>::type eval_lt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(a); + return eval_lt(t.backend(), b); +} + +template +inline bool eval_gt(const B& a, const B& b) +{ + return a.compare(b) > 0; +} +template +inline typename enable_if_c::value, bool>::type eval_gt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(b); + return eval_gt(a, t.backend()); +} +template +inline typename enable_if_c::value, bool>::type eval_gt(const T& a, const U& b) +{ + typename boost::multiprecision::detail::number_from_backend::type t(a); + return eval_gt(t.backend(), b); +} + +} // namespace default_ops + +namespace detail{ + +template +struct is_valid_mixed_compare : public mpl::false_ {}; + +template +struct is_valid_mixed_compare, Val> : public is_convertible > {}; + +template +struct is_valid_mixed_compare, number > : public mpl::false_ {}; + +template +struct is_valid_mixed_compare, expression > + : public mpl::bool_, number >::value> {}; + +template +struct is_valid_mixed_compare, number > + : public mpl::bool_, number >::value> {}; + +template +inline BOOST_CONSTEXPR typename boost::enable_if_c::value != number_kind_floating_point, bool>::type is_unordered_value(const number&) +{ + return false; +} +template +inline BOOST_CONSTEXPR typename boost::enable_if_c::value == number_kind_floating_point, bool>::type is_unordered_value(const number& a) +{ + using default_ops::eval_fpclassify; + return eval_fpclassify(a.backend()) == FP_NAN; +} + +template +inline BOOST_CONSTEXPR typename boost::enable_if_c::value != number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic&) +{ + return false; +} +template +inline BOOST_CONSTEXPR typename boost::enable_if_c::value == number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic& a) +{ + return (boost::math::isnan)(a); +} + +template +inline BOOST_CONSTEXPR bool is_unordered_comparison(const T& a, const U& b) +{ + return is_unordered_value(a) || is_unordered_value(b); +} + +} + +template +inline bool operator == (const number& a, const number& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_eq(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator == (const number& a, const Arithmetic& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_eq(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator == (const Arithmetic& a, const number& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_eq(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator == (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_eq; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return eval_eq(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator == (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_eq; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return eval_eq(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator == (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_eq; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return eval_eq(t.backend(), t2.backend()); +} + +template +inline bool operator != (const number& a, const number& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return true; + return !eval_eq(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator != (const number& a, const Arithmetic& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return true; + return !eval_eq(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator != (const Arithmetic& a, const number& b) +{ + using default_ops::eval_eq; + if(detail::is_unordered_comparison(a, b)) return true; + return !eval_eq(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator != (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_eq; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return true; + return !eval_eq(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator != (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_eq; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return true; + return !eval_eq(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator != (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_eq; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return true; + return !eval_eq(t.backend(), t2.backend()); +} + +template +inline bool operator < (const number& a, const number& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_lt(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator < (const number& a, const Arithmetic& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_lt(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator < (const Arithmetic& a, const number& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_gt(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator < (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_gt; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return eval_gt(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator < (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_lt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return eval_lt(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator < (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_lt; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return eval_lt(t.backend(), t2.backend()); +} + +template +inline bool operator > (const number& a, const number& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_gt(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator > (const number& a, const Arithmetic& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_gt(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator > (const Arithmetic& a, const number& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return eval_lt(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator > (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_lt; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return a > t; +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator > (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_gt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return t > b; +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator > (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_gt; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return t > t2; +} + +template +inline bool operator <= (const number& a, const number& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_gt(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator <= (const number& a, const Arithmetic& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_gt(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator <= (const Arithmetic& a, const number& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_lt(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator <= (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_lt; + if(detail::is_unordered_value(a) || detail::is_unordered_value(b)) + return false; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return !eval_lt(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator <= (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_gt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return !eval_gt(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator <= (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_gt; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return !eval_gt(t.backend(), t2.backend()); +} + +template +inline bool operator >= (const number& a, const number& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_lt(a.backend(), b.backend()); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator >= (const number& a, const Arithmetic& b) +{ + using default_ops::eval_lt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_lt(a.backend(), number::canonical_value(b)); +} +template +inline typename enable_if_c, Arithmetic>::value, bool>::type + operator >= (const Arithmetic& a, const number& b) +{ + using default_ops::eval_gt; + if(detail::is_unordered_comparison(a, b)) return false; + return !eval_gt(b.backend(), number::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator >= (const Arithmetic& a, const detail::expression& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_gt; + result_type t(b); + if(detail::is_unordered_comparison(a, t)) return false; + return !eval_gt(t.backend(), result_type::canonical_value(a)); +} +template +inline typename enable_if_c::result_type, Arithmetic>::value, bool>::type + operator >= (const detail::expression& a, const Arithmetic& b) +{ + typedef typename detail::expression::result_type result_type; + using default_ops::eval_lt; + result_type t(a); + if(detail::is_unordered_comparison(t, b)) return false; + return !eval_lt(t.backend(), result_type::canonical_value(b)); +} +template +inline typename enable_if::result_type, typename detail::expression::result_type>, bool>::type + operator >= (const detail::expression& a, const detail::expression& b) +{ + using default_ops::eval_lt; + typename detail::expression::result_type t(a); + typename detail::expression::result_type t2(b); + if(detail::is_unordered_comparison(t, t2)) return false; + return !eval_lt(t.backend(), t2.backend()); +} + + +}} // namespaces + +#endif // BOOST_MP_COMPARE_HPP From 49d753b3027ddccb29358fa6bb280f6e8ad56c20 Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 2 Jun 2015 12:37:45 +0200 Subject: [PATCH 76/90] fixed isSyncing usage --- libethereum/EthereumHost.cpp | 12 +++++------- libethereum/EthereumHost.h | 4 ++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 899960c23..d90bf57e2 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -91,10 +91,7 @@ void EthereumHost::doWork() bool netChange = ensureInitialised(); auto h = m_chain.currentHash(); // If we've finished our initial sync (including getting all the blocks into the chain so as to reduce invalid transactions), start trading transactions & blocks - bool syncing = false; - DEV_GUARDED(x_sync) - syncing = isSyncing(); - if (syncing && m_chain.isKnown(m_latestBlockSent)) + if (isSyncing() && m_chain.isKnown(m_latestBlockSent)) { if (m_newTransactions) { @@ -444,7 +441,8 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) { - if (isSyncing()) + Guard l(x_sync); + if (isSyncingInternal()) { clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; return; @@ -456,7 +454,7 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { Guard l(x_sync); - if (isSyncing()) + if (isSyncingInternal()) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; return; @@ -619,7 +617,7 @@ bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const } } -bool EthereumHost::isSyncing() const +bool EthereumHost::isSyncingInternal() const { bool syncing = false; forEachPeer([&](EthereumPeer* _p) diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index f8fa79a15..ad18bccc7 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -70,8 +70,7 @@ public: void reset(); DownloadMan const& downloadMan() const { return m_man; } - bool isSyncing() const; - + bool isSyncing() const { Guard l(x_sync); return isSyncingInternal(); } bool isBanned(p2p::NodeId _id) const { return !!m_banned.count(_id); } void noteNewTransactions() { m_newTransactions = true; } @@ -93,6 +92,7 @@ private: std::pair>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); void forEachPeerPtr(std::function)> const& _f) const; void forEachPeer(std::function const& _f) const; + bool isSyncingInternal() const; /// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network. void doWork(); From c95ddc044dd96edf23212aea7da1e0aa91cf9688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 2 Jun 2015 13:08:39 +0200 Subject: [PATCH 77/90] Style improvements --- alethzero/Debugger.cpp | 2 +- mix/MixClient.cpp | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/alethzero/Debugger.cpp b/alethzero/Debugger.cpp index 21ef3b711..fafa25b2e 100644 --- a/alethzero/Debugger.cpp +++ b/alethzero/Debugger.cpp @@ -104,7 +104,7 @@ bool DebugSession::populate(dev::eth::Executive& _executive, dev::eth::Transacti levels.push_back(&history.back()); else levels.resize(ext.depth); - history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, (u256)gas, lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); + history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, static_cast(gas), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); }; _executive.go(onOp); _executive.finalize(); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index b011e0cec..aa469d8a0 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -180,8 +180,20 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c else levels.resize(ext.depth); - machineStates.emplace_back(MachineState({steps, vm.curPC(), inst, newMemSize, (u256)gas, - vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels, codeIndex, dataIndex})); + 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 + }); }; execution.go(onOp); From fdeadf93305f0eb9ceb303d6b221cc7980821ead Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 2 Jun 2015 13:41:20 +0200 Subject: [PATCH 78/90] renamed isSyncingInternal --- libethereum/EthereumHost.cpp | 6 +++--- libethereum/EthereumHost.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index d90bf57e2..ddb6bdc52 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -442,7 +442,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) { Guard l(x_sync); - if (isSyncingInternal()) + if (isSyncing_UNSAFE()) { clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; return; @@ -454,7 +454,7 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { Guard l(x_sync); - if (isSyncingInternal()) + if (isSyncing_UNSAFE()) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; return; @@ -617,7 +617,7 @@ bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const } } -bool EthereumHost::isSyncingInternal() const +bool EthereumHost::isSyncing_UNSAFE() const { bool syncing = false; forEachPeer([&](EthereumPeer* _p) diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index ad18bccc7..a8ae6dd66 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -70,7 +70,7 @@ public: void reset(); DownloadMan const& downloadMan() const { return m_man; } - bool isSyncing() const { Guard l(x_sync); return isSyncingInternal(); } + bool isSyncing() const { Guard l(x_sync); return isSyncing_UNSAFE(); } bool isBanned(p2p::NodeId _id) const { return !!m_banned.count(_id); } void noteNewTransactions() { m_newTransactions = true; } @@ -92,7 +92,7 @@ private: std::pair>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); void forEachPeerPtr(std::function)> const& _f) const; void forEachPeer(std::function const& _f) const; - bool isSyncingInternal() const; + bool isSyncing_UNSAFE() const; /// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network. void doWork(); From d3b42295ee1e6bb079ae70993eb1deb2bb5c76cd Mon Sep 17 00:00:00 2001 From: arkpar Date: Tue, 2 Jun 2015 13:47:36 +0200 Subject: [PATCH 79/90] comments for isSyncing --- libethereum/EthereumHost.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index ddb6bdc52..564e37315 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -619,6 +619,8 @@ bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const bool EthereumHost::isSyncing_UNSAFE() const { + /// We need actual peer information here to handle the case when we are the first ever peer on the network to mine. + /// I.e. on a new private network the first node mining has noone to sync with and should start block propogation immediately. bool syncing = false; forEachPeer([&](EthereumPeer* _p) { From 86447d4a40ba86a1c8961515c7f70bde3b7163e3 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 2 Jun 2015 14:00:48 +0200 Subject: [PATCH 80/90] bug fix: #2020 --- mix/QBigInt.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mix/QBigInt.cpp b/mix/QBigInt.cpp index ee29cea43..7d7dd3857 100644 --- a/mix/QBigInt.cpp +++ b/mix/QBigInt.cpp @@ -65,7 +65,9 @@ QVariantMap QBigInt::checkAgainst(QString const& _type) const QString capacity = type.replace("uint", "").replace("int", ""); if (capacity.isEmpty()) capacity = "256"; - bigint range = 256^(capacity.toInt() / 8); + bigint range = 1; + for (int k = 0; k < capacity.toInt() / 8; ++k) + range = range * 256; bigint value = boost::get(this->internalValue()); ret.insert("valid", true); if (_type.startsWith("uint") && value > range - 1) From ff1f386df84234bac89c1d0e790cfcbd165e6fd1 Mon Sep 17 00:00:00 2001 From: gluk256 Date: Tue, 2 Jun 2015 15:54:39 +0200 Subject: [PATCH 81/90] Update TransientDirectory.cpp switched to no-throw version of remove_all() --- libdevcore/TransientDirectory.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/libdevcore/TransientDirectory.cpp b/libdevcore/TransientDirectory.cpp index 3c88e42a3..c632514ef 100644 --- a/libdevcore/TransientDirectory.cpp +++ b/libdevcore/TransientDirectory.cpp @@ -24,6 +24,7 @@ #include "Exceptions.h" #include "TransientDirectory.h" #include "CommonIO.h" +#include "Log.h" using namespace std; using namespace dev; @@ -43,16 +44,19 @@ TransientDirectory::TransientDirectory(std::string const& _path): TransientDirectory::~TransientDirectory() { - for (int i = 0; i < 3; ++i) - { - try - { - boost::filesystem::remove_all(m_path); - break; - } - catch (...) - { - this_thread::sleep_for(chrono::milliseconds(10)); - } - } + boost::system::error_code ec; + boost::filesystem::remove_all(m_path, ec); + if (0 == ec) + return; + + // In some cases, antivirus runnig on Windows will scan all the newly created directories. + // As a consequence, directory is locked and can not be deleted immediately. + // Retry after 10 milliseconds usually is successful. + // This will help our tests run smoothly in such environment. + this_thread::sleep_for(chrono::milliseconds(10)); + + ec.clear(); + boost::filesystem::remove_all(m_path, ec); + if (ec != 0) + cwarn << "Failed to delete directory '" << m_path << "': " << ec.message(); } From 7b8a4cebd891fa9ff067802f593afcdf221ea586 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 3 Jun 2015 12:00:59 +0200 Subject: [PATCH 82/90] Better code. --- libethereum/EthereumHost.cpp | 6 +++--- libethereum/EthereumHost.h | 2 +- libp2p/Session.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index cea9339f2..533304fa6 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -218,11 +218,11 @@ void EthereumHost::maintainTransactions() } } -tuple>, vector>, list>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow) +tuple>, vector>, vector>> EthereumHost::randomSelection(unsigned _percent, std::function const& _allow) { vector> chosen; vector> allowed; - list> sessions; + vector> sessions; auto const& ps = peerSessions(); allowed.reserve(ps.size()); @@ -243,7 +243,7 @@ tuple>, vector>, list>, std::vector>, std::list>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); + std::tuple>, std::vector>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); /// Session is tell us that we may need (re-)syncing with the peer. void noteNeedsSyncing(EthereumPeer* _who); diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 1c037e783..2a16007ca 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -319,7 +319,7 @@ void Session::send(bytes&& _msg) void Session::write() { - bytes *out; + bytes const* out; DEV_GUARDED(x_writeQueue) { m_io->writeSingleFramePacket(&m_writeQueue[0], m_writeQueue[0]); From 371d23decc70bde894ef794aa9e7fc08237535a1 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Jun 2015 16:10:21 +0200 Subject: [PATCH 83/90] Check if GPU has over 2GB of memory If the user's machine contains no OpenCL device that has enough GPU memory then don't allow creation of a GPU miner. Instead default to CPU. --- ethminer/MinerAux.h | 12 +++++- libethash-cl/ethash_cl_miner.cpp | 65 +++++++++++++++++++++++++++----- libethash-cl/ethash_cl_miner.h | 1 + libethcore/Ethash.cpp | 5 +++ libethcore/Ethash.h | 1 + 5 files changed, 72 insertions(+), 12 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 47fd2e2ae..bae4b942c 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -171,8 +171,16 @@ public: m_minerType = MinerType::CPU; else if (arg == "-G" || arg == "--opencl") { - m_minerType = MinerType::GPU; - miningThreads = 1; + if (!ProofOfWork::GPUMiner::haveSufficientGPUMemory()) + { + cout << "No GPU device with sufficient memory was found. Defaulting to CPU" << endl; + m_minerType = MinerType::CPU; + } + else + { + m_minerType = MinerType::GPU; + miningThreads = 1; + } } else if (arg == "--no-precompute") { diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 93ce9ab22..7e2dfd46e 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -35,6 +35,7 @@ #include "ethash_cl_miner_kernel.h" #define ETHASH_BYTES 32 +#define ETHASH_CL_MINIMUM_MEMORY 2000000000 // workaround lame platforms #if !CL_VERSION_1_2 @@ -47,6 +48,9 @@ using namespace std; +// TODO: If at any point we can use libdevcore in here then we should switch to using a LogChannel +#define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl + static void add_definition(std::string& source, char const* id, unsigned value) { char buf[256]; @@ -72,7 +76,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return std::string(); } @@ -82,7 +86,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return std::string(); } @@ -107,7 +111,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return 0; } @@ -116,12 +120,53 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return 0; } return devices.size(); } +bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId) +{ + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + ETHCL_LOG("No OpenCL platforms found."); + 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) + { + cl_ulong result; + device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result); + if (result >= ETHASH_CL_MINIMUM_MEMORY) + { + ETHCL_LOG( + "Found suitable OpenCL device [" << device.getInfo() + << "] with " << result << " bytes of GPU memory" + ); + return true; + } + else + ETHCL_LOG( + "OpenCL device " << device.getInfo() + << " has insufficient GPU memory." << result << + " bytes of memory found < " << ETHASH_CL_MINIMUM_MEMORY << " bytes of memory required" + ); + } + return false; +} + void ethash_cl_miner::finish() { if (m_queue()) @@ -135,7 +180,7 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return false; } @@ -143,25 +188,25 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work _platformId = std::min(_platformId, platforms.size() - 1); - cout << "Using platform: " << platforms[_platformId].getInfo().c_str() << endl; + ETHCL_LOG("Using platform: " << platforms[_platformId].getInfo().c_str()); // get GPU device of the default platform std::vector devices; platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return false; } // use selected device cl::Device& device = devices[std::min(_deviceId, devices.size() - 1)]; std::string device_version = device.getInfo(); - cout << "Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")" << endl; + ETHCL_LOG("Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")"); if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) { - cout << "OpenCL 1.0 is not supported." << endl; + ETHCL_LOG("OpenCL 1.0 is not supported."); return false; } if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) @@ -193,7 +238,7 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work } catch (cl::Error err) { - cout << program.getBuildInfo(device).c_str(); + ETHCL_LOG(program.getBuildInfo(device).c_str()); return false; } m_hash_kernel = cl::Kernel(program, "ethash_hash"); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 43bfa2336..ef6745d76 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -35,6 +35,7 @@ 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); bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0); void finish(); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f62c1f9cd..0be0b520c 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -363,6 +363,11 @@ 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); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 86540678f..9986c6a03 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -115,6 +115,7 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } static std::string platformInfo(); + static bool haveSufficientGPUMemory(); static unsigned getNumDevices(); static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } From 3e2fc17e8139d418a6e39ee91d0a8b3c23f6fd9f Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Jun 2015 16:57:24 +0200 Subject: [PATCH 84/90] Print additional info if DAG creation fails --- libethcore/EthashAux.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 4b546404a..0c1e84ebc 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -137,7 +137,10 @@ EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback full = ethash_full_new(_light, _cb); // cdebug << "Called OK."; if (!full) - BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new()")); + { + clog(DAGChannel) << "DAG Generation Failure. Reason: " << strerror(errno); + BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new")); + } } EthashAux::FullAllocation::~FullAllocation() From bedddefda06c6c4934653d3e6e5056dd5d04ff8b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Jun 2015 17:09:23 +0200 Subject: [PATCH 85/90] Implement memory check function also for the CPU - Should fix the build, since Ethash is an interface. --- libethcore/Ethash.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9986c6a03..075b0522b 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -87,6 +87,7 @@ 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 setDefaultDevice(unsigned) {} static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } From 1a37f2b3dadb851f1377ac336d42c323050d98a9 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 3 Jun 2015 17:14:20 +0200 Subject: [PATCH 86/90] fixed blockchain kill --- libethereum/Client.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 96353ade2..1491c83d7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -269,9 +269,11 @@ void Client::killChain() { WriteGuard l(x_postMine); WriteGuard l2(x_preMine); + WriteGuard l3(x_working); m_preMine = State(); m_postMine = State(); + m_working = State(); m_stateDB = OverlayDB(); m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); @@ -284,6 +286,7 @@ void Client::killChain() if (auto h = m_host.lock()) h->reset(); + startedWorking(); doWork(); startWorking(); From bf6ec8e32a1855d1609740d565c527e76544b319 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 22 May 2015 16:21:34 +0300 Subject: [PATCH 87/90] evmJit warnings fix --- evmjit/libevmjit-cpp/Env.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index 86a65dbab..4d7865bd0 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -54,7 +54,7 @@ extern "C" if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) { u256 gas = *io_gas; - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + h256 address(_env->create(endowment, gas, {_initBeg, (size_t)_initSize}, {}), h256::AlignRight); *io_gas = static_cast(gas); *o_address = address; } @@ -69,8 +69,8 @@ extern "C" params.senderAddress = _env->myAddress; params.receiveAddress = right160(*_receiveAddress); params.codeAddress = right160(*_codeAddress); - params.data = {_inBeg, _inSize}; - params.out = {_outBeg, _outSize}; + params.data = {_inBeg, (size_t)_inSize}; + params.out = {_outBeg, (size_t)_outSize}; params.onOp = {}; const auto isCall = params.receiveAddress == params.codeAddress; // OPT: The same address pointer can be used if not CODECALL @@ -102,7 +102,7 @@ extern "C" EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) { - auto hash = sha3({_begin, _size}); + auto hash = sha3({_begin, (size_t)_size}); *o_hash = hash; } @@ -130,7 +130,7 @@ extern "C" if (_topic4) topics.push_back(*_topic4); - _env->log(std::move(topics), {_beg, _size}); + _env->log(std::move(topics), {_beg, (size_t)_size}); } } From 78e6e007d654590c7b72a740a23fbbcbf3428222 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 3 Jun 2015 20:00:38 +0300 Subject: [PATCH 88/90] TransactionTest: V = unit64+28 --- .../ttTransactionTestFiller.json | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json b/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json index 5b24b9e51..410434d1d 100644 --- a/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json +++ b/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json @@ -63,12 +63,12 @@ } }, - "V_overflow64bit" : { + "V_overflow64bitPlus27" : { "expect" : "invalid", "transaction" : { "data" : "0x5544", - "gasLimit" : "21000", + "gasLimit" : "22000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -79,6 +79,22 @@ } }, + "V_overflow64bitPlus28" : { + "expect" : "invalid", + "transaction" : + { + "data" : "0x5544", + "gasLimit" : "22000", + "gasPrice" : "1", + "nonce" : "3", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10", + "v" : "18446744073709551644", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" + } + }, + "V_overflow64bitSigned" : { "expect" : "invalid", "transaction" : From e0c3095bdaaf486fc8d59bafdb2ce3df66a00e97 Mon Sep 17 00:00:00 2001 From: Vlad Gluhovsky Date: Wed, 3 Jun 2015 19:22:34 +0200 Subject: [PATCH 89/90] refactored the topic naming conventions --- alethzero/MainWin.cpp | 6 ++--- libweb3jsonrpc/WebThreeStubServerBase.cpp | 12 +++++----- libwhisper/Common.cpp | 24 +++++++++---------- libwhisper/Common.h | 28 +++++++++++------------ libwhisper/Interface.h | 24 ++++++++----------- libwhisper/Message.cpp | 20 ++++++++-------- libwhisper/Message.h | 20 ++++++++-------- libwhisper/WhisperHost.cpp | 4 ++-- libwhisper/WhisperHost.h | 6 ++--- test/libwhisper/whisperMessage.cpp | 8 +++---- 10 files changed, 73 insertions(+), 79 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 6a11736a4..59698bac3 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1803,7 +1803,7 @@ void Main::on_accounts_doubleClicked() } } -static shh::FullTopic topicFromText(QString _s) +static shh::Topics topicFromText(QString _s) { shh::BuildTopic ret; while (_s.size()) @@ -2187,10 +2187,10 @@ void Main::refreshWhispers() shh::Envelope const& e = w.second; shh::Message m; for (pair const& i: m_server->ids()) - if (!!(m = e.open(shh::FullTopic(), i.second))) + if (!!(m = e.open(shh::Topics(), i.second))) break; if (!m) - m = e.open(shh::FullTopic()); + m = e.open(shh::Topics()); QString msg; if (m.from()) diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index 6b714f2ac..ff7b84dc4 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -267,7 +267,7 @@ static shh::Envelope toSealed(Json::Value const& _json, shh::Message const& _m, return _m.seal(_from, bt, ttl, workToProve); } -static pair toWatch(Json::Value const& _json) +static pair toWatch(Json::Value const& _json) { shh::BuildTopic bt; Public to; @@ -985,7 +985,7 @@ string WebThreeStubServerBase::shh_newFilter(Json::Value const& _json) try { - pair w = toWatch(_json); + pair w = toWatch(_json); auto ret = face()->installWatch(w.first); m_shhWatches.insert(make_pair(ret, w.second)); return toJS(ret); @@ -1025,10 +1025,10 @@ Json::Value WebThreeStubServerBase::shh_getFilterChanges(string const& _filterId if (pub) { cwarn << "Silently decrypting message from identity" << pub << ": User validation hook goes here."; - m = e.open(face()->fullTopic(id), m_shhIds[pub]); + m = e.open(face()->fullTopics(id), m_shhIds[pub]); } else - m = e.open(face()->fullTopic(id)); + m = e.open(face()->fullTopics(id)); if (!m) continue; ret.append(toJson(h, e, m)); @@ -1058,10 +1058,10 @@ Json::Value WebThreeStubServerBase::shh_getMessages(string const& _filterId) if (pub) { cwarn << "Silently decrypting message from identity" << pub << ": User validation hook goes here."; - m = e.open(face()->fullTopic(id), m_shhIds[pub]); + m = e.open(face()->fullTopics(id), m_shhIds[pub]); } else - m = e.open(face()->fullTopic(id)); + m = e.open(face()->fullTopics(id)); if (!m) continue; ret.append(toJson(h, e, m)); diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index dd9172c70..526072842 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -28,26 +28,26 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -CollapsedTopicPart dev::shh::collapse(FullTopicPart const& _p) +AbridgedTopic dev::shh::abridge(Topic const& _p) { - return CollapsedTopicPart(sha3(_p)); + return AbridgedTopic(sha3(_p)); } -CollapsedTopic dev::shh::collapse(FullTopic const& _fullTopic) +AbridgedTopics dev::shh::abridge(Topics const& _topics) { - CollapsedTopic ret; - ret.reserve(_fullTopic.size()); - for (auto const& ft: _fullTopic) - ret.push_back(collapse(ft)); + AbridgedTopics ret; + ret.reserve(_topics.size()); + for (auto const& t : _topics) + ret.push_back(abridge(t)); return ret; } -CollapsedTopic BuildTopic::toTopic() const +AbridgedTopics BuildTopic::toAbridgedTopics() const { - CollapsedTopic ret; + AbridgedTopics ret; ret.reserve(m_parts.size()); for (auto const& h: m_parts) - ret.push_back(collapse(h)); + ret.push_back(abridge(h)); return ret; } @@ -71,7 +71,7 @@ bool TopicFilter::matches(Envelope const& _e) const for (unsigned i = 0; i < t.size(); ++i) { for (auto et: _e.topic()) - if (((t[i].first ^ et) & t[i].second) == CollapsedTopicPart()) + if (((t[i].first ^ et) & t[i].second) == AbridgedTopic()) goto NEXT_TOPICPART; // failed to match topicmask against any topics: move on to next mask goto NEXT_TOPICMASK; @@ -89,7 +89,7 @@ TopicMask BuildTopicMask::toTopicMask() const TopicMask ret; ret.reserve(m_parts.size()); for (auto const& h: m_parts) - ret.push_back(make_pair(collapse(h), ~CollapsedTopicPart())); + ret.push_back(make_pair(abridge(h), ~AbridgedTopic())); return ret; } diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 480b79350..b575166b4 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -60,14 +60,14 @@ enum WhisperPacket PacketCount }; -using CollapsedTopicPart = FixedHash<4>; -using FullTopicPart = h256; +using AbridgedTopic = FixedHash<4>; +using Topic = h256; -using CollapsedTopic = std::vector; -using FullTopic = h256s; +using AbridgedTopics = std::vector; +using Topics = h256s; -CollapsedTopicPart collapse(FullTopicPart const& _fullTopicPart); -CollapsedTopic collapse(FullTopic const& _fullTopic); +AbridgedTopic abridge(Topic const& _topic); +AbridgedTopics abridge(Topics const& _topics); class BuildTopic { @@ -80,10 +80,10 @@ public: BuildTopic& shiftRaw(h256 const& _part) { m_parts.push_back(_part); return *this; } - operator CollapsedTopic() const { return toTopic(); } - operator FullTopic() const { return toFullTopic(); } - CollapsedTopic toTopic() const; - FullTopic toFullTopic() const { return m_parts; } + operator AbridgedTopics() const { return toAbridgedTopics(); } + operator Topics() const { return toTopics(); } + AbridgedTopics toAbridgedTopics() const; + Topics toTopics() const { return m_parts; } protected: BuildTopic& shiftBytes(bytes const& _b); @@ -91,14 +91,14 @@ protected: h256s m_parts; }; -using TopicMask = std::vector>; +using TopicMask = std::vector>; using TopicMasks = std::vector; class TopicFilter { public: TopicFilter() {} - TopicFilter(FullTopic const& _m) { m_topicMasks.push_back(TopicMask()); for (auto const& h: _m) m_topicMasks.back().push_back(std::make_pair(collapse(h), h ? ~CollapsedTopicPart() : CollapsedTopicPart())); } + TopicFilter(Topics const& _m) { m_topicMasks.push_back(TopicMask()); for (auto const& h: _m) m_topicMasks.back().push_back(std::make_pair(abridge(h), h ? ~AbridgedTopic() : AbridgedTopic())); } TopicFilter(TopicMask const& _m): m_topicMasks(1, _m) {} TopicFilter(TopicMasks const& _m): m_topicMasks(_m) {} TopicFilter(RLP const& _r)//: m_topicMasks(_r.toVector>()) @@ -132,9 +132,9 @@ public: template BuildTopicMask& operator()(T const& _t) { shift(_t); return *this; } operator TopicMask() const { return toTopicMask(); } - operator FullTopic() const { return toFullTopic(); } + operator Topics() const { return toTopics(); } TopicMask toTopicMask() const; - FullTopic toFullTopic() const { return m_parts; } + Topics toTopics() const { return m_parts; } }; } diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 8b84193aa..8015957fc 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -38,19 +38,13 @@ namespace dev namespace shh { -/*struct TopicMask -{ - Topic data; - Topic mask; -};*/ - class Watch; struct InstalledFilter { - InstalledFilter(FullTopic const& _f): full(_f), filter(_f) {} + InstalledFilter(Topics const& _t): full(_t), filter(_t) {} - FullTopic full; + Topics full; TopicFilter filter; unsigned refCount = 1; }; @@ -71,8 +65,8 @@ public: virtual void inject(Envelope const& _m, WhisperPeer* _from = nullptr) = 0; - virtual FullTopic const& fullTopic(unsigned _id) const = 0; - virtual unsigned installWatch(FullTopic const& _mask) = 0; + virtual Topics const& fullTopics(unsigned _id) const = 0; + virtual unsigned installWatch(Topics const& _filter) = 0; virtual unsigned installWatchOnId(h256 _filterId) = 0; virtual void uninstallWatch(unsigned _watchId) = 0; virtual h256s peekWatch(unsigned _watchId) const = 0; @@ -81,10 +75,10 @@ public: virtual Envelope envelope(h256 _m) const = 0; - void post(bytes const& _payload, FullTopic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topic, _ttl, _workToProve)); } - void post(Public _to, bytes const& _payload, FullTopic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topic, _ttl, _workToProve)); } - void post(Secret _from, bytes const& _payload, FullTopic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topic, _ttl, _workToProve)); } - void post(Secret _from, Public _to, bytes const& _payload, FullTopic _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topic, _ttl, _workToProve)); } + void post(bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_topics, _ttl, _workToProve)); } + void post(Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_to, _topics, _ttl, _workToProve)); } + void post(Secret _from, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).seal(_from, _topics, _ttl, _workToProve)); } + void post(Secret _from, Public _to, bytes const& _payload, Topics _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { inject(Message(_payload).sealTo(_from, _to, _topics, _ttl, _workToProve)); } }; struct WatshhChannel: public dev::LogChannel { static const char* name() { return "shh"; } static const int verbosity = 1; }; @@ -106,7 +100,7 @@ class Watch: public boost::noncopyable public: Watch() {} - Watch(Interface& _c, FullTopic const& _f): m_c(&_c), m_id(_c.installWatch(_f)) {} + Watch(Interface& _c, Topics const& _t) : m_c(&_c), m_id(_c.installWatch(_t)) {} ~Watch() { if (m_c) m_c->uninstallWatch(m_id); } h256s check() { return m_c ? m_c->checkWatch(m_id) : h256s(); } diff --git a/libwhisper/Message.cpp b/libwhisper/Message.cpp index 9ba67ff9c..50020b783 100644 --- a/libwhisper/Message.cpp +++ b/libwhisper/Message.cpp @@ -26,7 +26,7 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -Message::Message(Envelope const& _e, FullTopic const& _fk, Secret const& _s) +Message::Message(Envelope const& _e, Topics const& _t, Secret const& _s) { try { @@ -35,7 +35,7 @@ Message::Message(Envelope const& _e, FullTopic const& _fk, Secret const& _s) if (!decrypt(_s, &(_e.data()), b)) return; else{} - else if (!openBroadcastEnvelope(_e, _fk, b)) + else if (!openBroadcastEnvelope(_e, _t, b)) return; if (populate(b)) @@ -47,14 +47,14 @@ Message::Message(Envelope const& _e, FullTopic const& _fk, Secret const& _s) } } -bool Message::openBroadcastEnvelope(Envelope const& _e, FullTopic const& _fk, bytes& o_b) +bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes& o_b) { // retrieve the key using the known topic and topicIndex. unsigned topicIndex = 0; Secret topicSecret; // determine topicSecret/topicIndex from knowledge of the collapsed topics (which give the order) and our full-size filter topic. - CollapsedTopic knownTopic = collapse(_fk); + AbridgedTopics knownTopic = abridge(_fk); for (unsigned ti = 0; ti < _fk.size() && !topicSecret; ++ti) for (unsigned i = 0; i < _e.topic().size(); ++i) if (_e.topic()[i] == knownTopic[ti]) @@ -96,10 +96,10 @@ bool Message::populate(bytes const& _data) return true; } -Envelope Message::seal(Secret _from, FullTopic const& _fullTopic, unsigned _ttl, unsigned _workToProve) const +Envelope Message::seal(Secret _from, Topics const& _fullTopics, unsigned _ttl, unsigned _workToProve) const { - CollapsedTopic topic = collapse(_fullTopic); - Envelope ret(time(0) + _ttl, _ttl, topic); + AbridgedTopics topics = abridge(_fullTopics); + Envelope ret(time(0) + _ttl, _ttl, topics); bytes input(1 + m_payload.size()); input[0] = 0; @@ -121,7 +121,7 @@ Envelope Message::seal(Secret _from, FullTopic const& _fullTopic, unsigned _ttl, // this message is for broadcast (could be read by anyone who knows at least one of the topics) // create the shared secret for encrypting the payload, then encrypt the shared secret with each topic Secret s = Secret::random(); - for (h256 const& t : _fullTopic) + for (h256 const& t : _fullTopics) { h256 salt = h256::random(); ret.m_data += (generateGamma(t, salt) ^ s).asBytes(); @@ -146,9 +146,9 @@ Envelope::Envelope(RLP const& _m) m_nonce = _m[4].toInt(); } -Message Envelope::open(FullTopic const& _ft, Secret const& _s) const +Message Envelope::open(Topics const& _t, Secret const& _s) const { - return Message(*this, _ft, _s); + return Message(*this, _t, _s); } unsigned Envelope::workProved() const diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 5b069f57b..3529054e0 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -72,22 +72,22 @@ public: unsigned sent() const { return m_expiry - m_ttl; } unsigned expiry() const { return m_expiry; } unsigned ttl() const { return m_ttl; } - CollapsedTopic const& topic() const { return m_topic; } + AbridgedTopics const& topic() const { return m_topic; } bytes const& data() const { return m_data; } - Message open(FullTopic const& _ft, Secret const& _s = Secret()) const; + Message open(Topics const& _t, Secret const& _s = Secret()) const; unsigned workProved() const; void proveWork(unsigned _ms); private: - Envelope(unsigned _exp, unsigned _ttl, CollapsedTopic const& _topic): m_expiry(_exp), m_ttl(_ttl), m_topic(_topic) {} + Envelope(unsigned _exp, unsigned _ttl, AbridgedTopics const& _topic): m_expiry(_exp), m_ttl(_ttl), m_topic(_topic) {} unsigned m_expiry = 0; unsigned m_ttl = 0; u256 m_nonce; - CollapsedTopic m_topic; + AbridgedTopics m_topic; bytes m_data; }; @@ -102,7 +102,7 @@ class Message { public: Message() {} - Message(Envelope const& _e, FullTopic const& _ft, Secret const& _s = Secret()); + Message(Envelope const& _e, Topics const& _t, Secret const& _s = Secret()); Message(bytes const& _payload): m_payload(_payload) {} Message(bytesConstRef _payload): m_payload(_payload.toBytes()) {} Message(bytes&& _payload) { std::swap(_payload, m_payload); } @@ -119,15 +119,15 @@ public: operator bool() const { return !!m_payload.size() || m_from || m_to; } /// Turn this message into a ditributable Envelope. - Envelope seal(Secret _from, FullTopic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) const; + Envelope seal(Secret _from, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const; // Overloads for skipping _from or specifying _to. - Envelope seal(FullTopic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topic, _ttl, _workToProve); } - Envelope sealTo(Public _to, FullTopic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(Secret(), _topic, _ttl, _workToProve); } - Envelope sealTo(Secret _from, Public _to, FullTopic const& _topic, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topic, _ttl, _workToProve); } + Envelope seal(Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) const { return seal(Secret(), _topics, _ttl, _workToProve); } + Envelope sealTo(Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(Secret(), _topics, _ttl, _workToProve); } + Envelope sealTo(Secret _from, Public _to, Topics const& _topics, unsigned _ttl = 50, unsigned _workToProve = 50) { m_to = _to; return seal(_from, _topics, _ttl, _workToProve); } private: bool populate(bytes const& _data); - bool openBroadcastEnvelope(Envelope const& _e, FullTopic const& _fk, bytes& o_b); + bool openBroadcastEnvelope(Envelope const& _e, Topics const& _t, bytes& o_b); h256 generateGamma(h256 const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); } Public m_from; diff --git a/libwhisper/WhisperHost.cpp b/libwhisper/WhisperHost.cpp index ab3576292..366bb92e4 100644 --- a/libwhisper/WhisperHost.cpp +++ b/libwhisper/WhisperHost.cpp @@ -103,11 +103,11 @@ unsigned WhisperHost::installWatchOnId(h256 _h) return ret; } -unsigned WhisperHost::installWatch(shh::FullTopic const& _ft) +unsigned WhisperHost::installWatch(shh::Topics const& _t) { Guard l(m_filterLock); - InstalledFilter f(_ft); + InstalledFilter f(_t); h256 h = f.filter.sha3(); if (!m_filters.count(h)) diff --git a/libwhisper/WhisperHost.h b/libwhisper/WhisperHost.h index cd427da35..c5ec5867b 100644 --- a/libwhisper/WhisperHost.h +++ b/libwhisper/WhisperHost.h @@ -40,7 +40,7 @@ namespace dev namespace shh { -static const FullTopic EmptyFullTopic; +static const Topics EmptyTopics; class WhisperHost: public HostCapability, public Interface, public Worker { @@ -54,8 +54,8 @@ public: virtual void inject(Envelope const& _e, WhisperPeer* _from = nullptr) override; - virtual FullTopic const& fullTopic(unsigned _id) const { try { return m_filters.at(m_watches.at(_id).id).full; } catch (...) { return EmptyFullTopic; } } - virtual unsigned installWatch(FullTopic const& _filter) override; + virtual Topics const& fullTopics(unsigned _id) const { try { return m_filters.at(m_watches.at(_id).id).full; } catch (...) { return EmptyTopics; } } + virtual unsigned installWatch(Topics const& _filter) override; virtual unsigned installWatchOnId(h256 _filterId) override; virtual void uninstallWatch(unsigned _watchId) override; virtual h256s peekWatch(unsigned _watchId) const override { dev::Guard l(m_filterLock); try { return m_watches.at(_watchId).changes; } catch (...) { return h256s(); } } diff --git a/test/libwhisper/whisperMessage.cpp b/test/libwhisper/whisperMessage.cpp index 5e4dff725..b3cda581b 100644 --- a/test/libwhisper/whisperMessage.cpp +++ b/test/libwhisper/whisperMessage.cpp @@ -34,9 +34,9 @@ struct VerbosityHolder int oldLogVerbosity; }; -FullTopic createRandomTopics(unsigned int i) +Topics createRandomTopics(unsigned int i) { - FullTopic ret; + Topics ret; h256 t(i); for (int j = 0; j < 8; ++j) @@ -72,14 +72,14 @@ void comparePayloads(Message const& m1, Message const& m2) void sealAndOpenSingleMessage(unsigned int i) { Secret zero; - FullTopic topics = createRandomTopics(i); + Topics topics = createRandomTopics(i); bytes const payload = createRandomPayload(i); Message m1(payload); Envelope e = m1.seal(zero, topics, 1, 1); for (auto const& t: topics) { - FullTopic singleTopic; + Topics singleTopic; singleTopic.push_back(t); Message m2(e, singleTopic, zero); comparePayloads(m1, m2); From f0ec754e46cbc9232a57853593ed40ddb782fac2 Mon Sep 17 00:00:00 2001 From: gluk256 Date: Wed, 3 Jun 2015 22:23:17 +0200 Subject: [PATCH 90/90] Update Interface.h --- libwhisper/Interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libwhisper/Interface.h b/libwhisper/Interface.h index 8015957fc..ff16c7e53 100644 --- a/libwhisper/Interface.h +++ b/libwhisper/Interface.h @@ -100,7 +100,7 @@ class Watch: public boost::noncopyable public: Watch() {} - Watch(Interface& _c, Topics const& _t) : m_c(&_c), m_id(_c.installWatch(_t)) {} + Watch(Interface& _c, Topics const& _t): m_c(&_c), m_id(_c.installWatch(_t)) {} ~Watch() { if (m_c) m_c->uninstallWatch(m_id); } h256s check() { return m_c ? m_c->checkWatch(m_id) : h256s(); }