diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 6a11736a4..3a67fc3ae 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1899,7 +1899,7 @@ void Main::on_net_triggered() { web3()->setIdealPeerCount(ui->idealPeers->value()); web3()->setNetworkPreferences(netPrefs(), ui->dropPeers->isChecked()); - ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256()); + ethereum()->setNetworkId(m_privateChain.size() ? sha3(m_privateChain.toStdString()) : h256(u256(42))); web3()->startNetwork(); ui->downloadView->setDownloadMan(ethereum()->downloadMan()); ui->enode->setText(QString::fromStdString(web3()->enode())); diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index df2ba5a5a..639e1d4f4 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -97,6 +97,7 @@ public: ExportBare, RecodeBare, KillBare, + InspectBare, CreateWallet, List, New, @@ -137,6 +138,8 @@ public: m_mode = OperationMode::ListBare; else if (arg == "--export-bare") m_mode = OperationMode::ExportBare; + else if (arg == "--inspect-bare") + m_mode = OperationMode::InspectBare; else if (arg == "--recode-bare") m_mode = OperationMode::RecodeBare; else if (arg == "--kill-bare") @@ -162,7 +165,7 @@ public: m_mode = OperationMode::Recode; else if (arg == "--no-icap") m_icap = false; - else if (m_mode == OperationMode::ImportBare || m_mode == OperationMode::KillBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare) + else if (m_mode == OperationMode::ImportBare || m_mode == OperationMode::InspectBare || m_mode == OperationMode::KillBare || m_mode == OperationMode::Recode || m_mode == OperationMode::Export || m_mode == OperationMode::RecodeBare || m_mode == OperationMode::ExportBare) m_inputs.push_back(arg); else return false; @@ -224,7 +227,7 @@ public: } if (!u && b.size() == 32) u = store.importSecret(b, lockPassword(toAddress(Secret(b)).abridged())); - else + if (!u) { cerr << "Cannot import " << i << " not a file or secret." << endl; continue; @@ -232,28 +235,43 @@ public: cout << "Successfully imported " << i << " as " << toUUID(u); } break; + case OperationMode::InspectBare: + for (auto const& i: m_inputs) + if (!contents(i).empty()) + { + h128 u = store.readKey(i, false); + bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); }); + cout << "Key " << i << ":" << endl; + cout << " UUID: " << toUUID(u) << ":" << endl; + cout << " Address: " << toAddress(Secret(s)).hex() << endl; + cout << " Secret: " << Secret(s).abridged() << endl; + } + else if (h128 u = fromUUID(i)) + { + bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }); + cout << "Key " << i << ":" << endl; + cout << " Address: " << toAddress(Secret(s)).hex() << endl; + cout << " Secret: " << Secret(s).abridged() << endl; + } + else + cerr << "Couldn't inspect " << i << "; not found." << endl; + break; case OperationMode::ExportBare: break; case OperationMode::RecodeBare: for (auto const& i: m_inputs) - { - h128 u = fromUUID(i); - if (u) + if (h128 u = fromUUID(i)) if (store.recode(u, lockPassword(toUUID(u)), [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); }, kdf())) cerr << "Re-encoded " << toUUID(u) << endl; else cerr << "Couldn't re-encode " << toUUID(u) << "; key corrupt or incorrect password supplied." << endl; else - cerr << "Couldn't re-encode " << toUUID(u) << "; not found." << endl; - } + cerr << "Couldn't re-encode " << i << "; not found." << endl; case OperationMode::KillBare: for (auto const& i: m_inputs) - { - h128 u = fromUUID(i); - if (u) + if (h128 u = fromUUID(i)) store.kill(u); else - cerr << "Couldn't kill " << toUUID(u) << "; not found." << endl; - } + cerr << "Couldn't kill " << i << "; not found." << endl; break; default: break; } diff --git a/libdevcore/TrieHash.cpp b/libdevcore/TrieHash.cpp index cff3464b5..ec31c3679 100644 --- a/libdevcore/TrieHash.cpp +++ b/libdevcore/TrieHash.cpp @@ -23,10 +23,8 @@ #include #include // @TODO replace ASAP! #include -#include using namespace std; using namespace dev; -using namespace dev::eth; namespace dev { diff --git a/libethcore/Common.cpp b/libethcore/Common.cpp index 56db647f3..11034b0ae 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -104,5 +104,28 @@ std::string formatBalance(bigint const& _b) return ret.str(); } +static void badBlockInfo(BlockInfo const& _bi, string const& _err) +{ + cwarn << EthRedBold << "========================================================================"; + cwarn << EthRedBold << "== Software Failure " + _err + string(max(0, 44 - _err.size()), ' ') + " =="; + string bin = toString(_bi.number); + cwarn << EthRedBold << ("== Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " =="); + cwarn << EthRedBold << "========================================================================"; +} + +void badBlock(bytesConstRef _block, string const& _err) +{ + badBlockInfo(BlockInfo(_block, CheckNothing), _err); + cwarn << " Block:" << toHex(_block); + cwarn << " Block RLP:" << RLP(_block); +} + +void badBlockHeader(bytesConstRef _header, string const& _err) +{ + badBlockInfo(BlockInfo::fromHeader(_header, CheckNothing), _err); + cwarn << " Header:" << toHex(_header); + cwarn << " Header RLP:" << RLP(_header);; +} + } } diff --git a/libethcore/Common.h b/libethcore/Common.h index 2cb505905..1d48803cb 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -148,5 +148,10 @@ struct TransactionSkeleton u256 gasPrice = UndefinedU256; }; +void badBlockHeader(bytesConstRef _header, std::string const& _err); +inline void badBlockHeader(bytes const& _header, std::string const& _err) { badBlockHeader(&_header, _err); } +void badBlock(bytesConstRef _header, std::string const& _err); +inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } + } } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 60585a162..f62c1f9cd 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -94,11 +94,13 @@ bool Ethash::preVerify(BlockInfo const& _header) h256 boundary = u256((bigint(1) << 256) / _header.difficulty); - return !!ethash_quick_check_difficulty( - (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), - (uint64_t)(u64)_header.nonce, - (ethash_h256_t const*)_header.mixHash.data(), - (ethash_h256_t const*)boundary.data()); + bool ret = !!ethash_quick_check_difficulty( + (ethash_h256_t const*)_header.headerHash(WithoutNonce).data(), + (uint64_t)(u64)_header.nonce, + (ethash_h256_t const*)_header.mixHash.data(), + (ethash_h256_t const*)boundary.data()); + + return ret; } bool Ethash::verify(BlockInfo const& _header) @@ -112,6 +114,10 @@ bool Ethash::verify(BlockInfo const& _header) auto result = EthashAux::eval(_header); bool slow = result.value <= _header.boundary() && result.mixHash == _header.mixHash; +// cdebug << (slow ? "VERIFY" : "VERYBAD"); +// cdebug << result.value.hex() << _header.boundary().hex(); +// cdebug << result.mixHash.hex() << _header.mixHash.hex(); + #if ETH_DEBUG || !ETH_TRUE if (!pre && slow) { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 2af95d00c..4a7a61a31 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -22,6 +22,7 @@ #include "BlockQueue.h" #include #include +#include #include #include #include "BlockChain.h" @@ -76,11 +77,54 @@ void BlockQueue::verifierBody() std::pair res; swap(work.second, res.second); try { - res.first.populate(res.second, CheckEverything, work.first); - res.first.verifyInternals(&res.second); + try { + res.first.populate(res.second, CheckEverything, work.first); + res.first.verifyInternals(&res.second); + } + catch (InvalidNonce&) + { + badBlock(res.second, "Invalid block nonce"); + cwarn << " Nonce:" << res.first.nonce.hex(); + cwarn << " PoWHash:" << res.first.headerHash(WithoutNonce).hex(); + cwarn << " SeedHash:" << res.first.seedHash().hex(); + cwarn << " Target:" << res.first.boundary().hex(); + cwarn << " MixHash:" << res.first.mixHash.hex(); + Ethash::Result er = EthashAux::eval(res.first.seedHash(), res.first.headerHash(WithoutNonce), res.first.nonce); + cwarn << " Ethash v:" << er.value.hex(); + cwarn << " Ethash mH:" << er.mixHash.hex(); + throw; + } + catch (Exception& _e) + { + badBlock(res.second, _e.what()); + throw; + } + RLP r(&res.second); for (auto const& uncle: r[2]) - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); + try + { + BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); + } + catch (InvalidNonce&) + { + badBlockHeader(uncle.data(), "Invalid uncle nonce"); + BlockInfo bi = BlockInfo::fromHeader(uncle.data(), CheckNothing); + cwarn << " Nonce:" << bi.nonce.hex(); + cwarn << " PoWHash:" << bi.headerHash(WithoutNonce).hex(); + cwarn << " SeedHash:" << bi.seedHash().hex(); + cwarn << " Target:" << bi.boundary().hex(); + cwarn << " MixHash:" << bi.mixHash.hex(); + Ethash::Result er = EthashAux::eval(bi.seedHash(), bi.headerHash(WithoutNonce), bi.nonce); + cwarn << " Ethash v:" << er.value.hex(); + cwarn << " Ethash mH:" << er.mixHash.hex(); + throw; + } + catch (Exception& _e) + { + badBlockHeader(uncle.data(), _e.what()); + throw; + } } catch (...) { diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 4fbf51244..09cdc6b04 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -242,6 +242,24 @@ OnOpFunc Executive::simpleTrace() }; } +OnOpFunc Executive::standardTrace(ostream& o_output) +{ + return [&](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, VM* voidVM, ExtVMFace const* voidExt) + { + ExtVM const& ext = *static_cast(voidExt); + VM& vm = *voidVM; + + o_output << endl << " STACK" << endl; + for (auto i: vm.stack()) + o_output << (h256)i << endl; + o_output << " MEMORY" << endl << ((vm.memory().size() > 1000) ? " mem size greater than 1000 bytes " : memDump(vm.memory())); + o_output << " STORAGE" << endl; + for (auto const& i: ext.state().storage(ext.myAddress)) + o_output << showbase << hex << i.first << ": " << i.second << endl; + o_output << " < " << dec << ext.depth << " : " << ext.myAddress << " : #" << steps << " : " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " : " << dec << vm.gas() << " : -" << dec << gasCost << " : " << newMemSize << "x32" << " >"; + }; +} + bool Executive::go(OnOpFunc const& _onOp) { if (m_vm) diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 8bb0ab771..949e2dc34 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -106,6 +106,9 @@ public: /// Operation function for providing a simple trace of the VM execution. static OnOpFunc simpleTrace(); + /// Operation function for providing a simple trace of the VM execution. + static OnOpFunc standardTrace(std::ostream& o_output); + /// @returns gas remaining after the transaction/operation. u256 endGas() const { return m_endGas; } /// @returns output data of the transaction/operation. diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c753f57ea..23405912c 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -564,6 +564,34 @@ pair State::sync(BlockChain const& _bc, TransactionQu return ret; } +string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) +{ + RLP rlp(_block); + + cleanup(false); + BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + m_currentBlock = bi; + m_currentBlock.verifyInternals(_block); + m_currentBlock.noteDirty(); + + LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); + vector receipts; + + ostringstream ss; + unsigned i = 0; + for (auto const& tr: rlp[1]) + { + ss << " VM Execution of transaction" << i << ":" << endl; + execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, Executive::standardTrace(ss)); + RLPStream receiptRLP; + m_receipts.back().streamRLP(receiptRLP); + receipts.push_back(receiptRLP.out()); + ++i; + ss << endl; + } + return ss.str(); +} + u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) { // m_currentBlock is assumed to be prepopulated and reset. @@ -587,14 +615,6 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement // cnote << "playback begins:" << m_state.root(); // cnote << m_state; - MemoryDB tm; - GenericTrieDB transactionsTrie(&tm); - transactionsTrie.init(); - - MemoryDB rm; - GenericTrieDB receiptsTrie(&rm); - receiptsTrie.init(); - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); RLP rlp(_block); @@ -612,40 +632,33 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement } auto receiptsRoot = orderedTrieRoot(receipts); - if (receiptsRoot != m_currentBlock.receiptsRoot) { - cwarn << "Bad receipts state root."; - cwarn << "Expected: " << toString(receiptsRoot) << " received: " << toString(m_currentBlock.receiptsRoot); - cwarn << "Block:" << toHex(_block); - cwarn << "Block RLP:" << rlp; - cwarn << "Calculated: " << receiptsRoot; + badBlock(_block, "Bad receipts state root"); + cwarn << " Received: " << toString(m_currentBlock.receiptsRoot); + cwarn << " Expected: " << toString(receiptsRoot) << " which is:"; for (unsigned j = 0; j < i; ++j) { - RLPStream k; - k << j; auto b = receipts[j]; cwarn << j << ": "; - cwarn << "RLP: " << RLP(b); - cwarn << "Hex: " << toHex(b); - cwarn << TransactionReceipt(&b); - } - cwarn << "Recorded: " << m_currentBlock.receiptsRoot; - auto rs = _bc.receipts(m_currentBlock.hash()); - for (unsigned j = 0; j < rs.receipts.size(); ++j) - { - auto b = rs.receipts[j].rlp(); - cwarn << j << ": "; - cwarn << "RLP: " << RLP(b); - cwarn << "Hex: " << toHex(b); - cwarn << rs.receipts[j]; + cwarn << " RLP: " << RLP(b); + cwarn << " Hex: " << toHex(b); + cwarn << " " << TransactionReceipt(&b); } + cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir); BOOST_THROW_EXCEPTION(InvalidReceiptsStateRoot()); } if (m_currentBlock.logBloom != logBloom()) { - cwarn << "Bad log bloom!"; + badBlock(_block, "Bad log bloom"); + cwarn << " Receipt blooms:"; + for (unsigned j = 0; j < i; ++j) + { + auto b = receipts[j]; + cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex(); + } + cwarn << " Final bloom:" << m_currentBlock.logBloom.hex(); BOOST_THROW_EXCEPTION(InvalidLogBloom()); } @@ -654,7 +667,10 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) + { + badBlock(_block, "Too many uncles"); BOOST_THROW_EXCEPTION(TooManyUncles()); + } vector rewarded; h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); @@ -664,13 +680,22 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement { auto h = sha3(i.data()); if (excluded.count(h)) + { + badBlock(_block, "Invalid uncle included"); BOOST_THROW_EXCEPTION(UncleInChain() << errinfo_comment("Uncle in block already mentioned") << errinfo_data(toString(excluded)) << errinfo_hash256(sha3(i.data()))); + } excluded.insert(h); BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); BlockInfo uncleParent(_bc.block(uncle.parentHash)); if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + { + badBlock(_block, "Uncle too old"); + cwarn << " Uncle number: " << uncle.number; + cwarn << " Uncle parent number: " << uncleParent.number; + cwarn << " Block number: " << m_currentBlock.number; BOOST_THROW_EXCEPTION(UncleTooOld()); + } uncle.verifyParent(uncleParent); // tdIncrease += uncle.difficulty; @@ -685,13 +710,13 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement // Hash the state trie and check against the state_root hash in m_currentBlock. if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) { - cwarn << "Bad state root!"; - cnote << "Given to be:" << m_currentBlock.stateRoot; + badBlock(_block, "Bad state root"); + cnote << " Given to be:" << m_currentBlock.stateRoot; // TODO: Fix // cnote << SecureTrieDB(&m_db, m_currentBlock.stateRoot); - cnote << "Calculated to be:" << rootHash(); + cnote << " Calculated to be:" << rootHash(); + cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir); // cnote << m_state; - cnote << *this; // Rollback the trie. m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidStateRoot()); @@ -700,6 +725,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement if (m_currentBlock.gasUsed != gasUsed()) { // Rollback the trie. + badBlock(_block, "Invalid gas used"); m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); } @@ -1114,7 +1140,7 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const return true; } -ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p) +ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) { #if ETH_PARANOIA paranoia("start of execution.", true); @@ -1141,7 +1167,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per #if ETH_VMTRACE e.go(e.simpleTrace()); #else - e.go(); + e.go(_onOp); #endif e.finalize(); diff --git a/libethereum/State.h b/libethereum/State.h index f46d0e222..afdf41735 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -190,7 +190,7 @@ public: /// Execute a given transaction. /// This will append @a _t to the transaction list and change the state accordingly. - ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed); + ExecutionResult execute(LastHashes const& _lh, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc()); /// Get the remaining gas limit in this block. u256 gasLimitRemaining() const { return m_currentBlock.gasLimit - gasUsed(); } @@ -351,6 +351,9 @@ private: /// Debugging only. Good for checking the Trie is in shape. void paranoia(std::string const& _when, bool _enforceRefs = false) const; + /// Provide a standard VM trace for debugging purposes. + std::string vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir); + OverlayDB m_db; ///< Our overlay for the state tree. SecureTrieDB m_state; ///< Our state tree, as an OverlayDB DB. Transactions m_transactions; ///< The current list of transactions that we've included in the state.