void MixClient::executeTransaction(Transaction const& _t, Block& _block, bool _call, bool _gasAuto, Secret const& _secret) { Transaction t = _gasAuto ? replaceGas(_t, m_postMine.gasLimitRemaining()) : _t; // do debugging run first EnvInfo envInfo(bc().info(), bc().lastHashes()); ExecutionResult d = debugTransaction(t, _block.state(), envInfo, _call); // execute on a state if (!_call) { t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; eth::ExecutionResult const& er = _block.execute(envInfo.lastHashes(), t); if (t.isCreation() && _block.state().code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; LocalisedLogEntries logs; TransactionReceipt const& tr = _block.receipt(_block.pending().size() - 1); LogEntries le = tr.log(); if (le.size()) for (unsigned j = 0; j < le.size(); ++j) logs.insert(logs.begin(), LocalisedLogEntry(le[j])); d.logs = logs; } WriteGuard l(x_executions); m_executions.emplace_back(std::move(d)); }
LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { LocalisedLogEntries ret; unsigned begin = min(bc().number() + 1, (unsigned)numberFromHash(_f.latest())); unsigned end = min(bc().number(), min(begin, (unsigned)numberFromHash(_f.earliest()))); // Handle pending transactions differently as they're not on the block chain. if (begin > bc().number()) { State temp = postMine(); for (unsigned i = 0; i < temp.pending().size(); ++i) { // Might have a transaction that contains a matching log. TransactionReceipt const& tr = temp.receipt(i); LogEntries le = _f.matches(tr); if (le.size()) for (unsigned j = 0; j < le.size(); ++j) ret.insert(ret.begin(), LocalisedLogEntry(le[j])); } begin = bc().number(); } set<unsigned> matchingBlocks; for (auto const& i: _f.bloomPossibilities()) for (auto u: bc().withBlockBloom(i, end, begin)) matchingBlocks.insert(u); unsigned falsePos = 0; for (auto n: matchingBlocks) { int total = 0; auto h = bc().numberHash(n); auto info = bc().info(h); auto receipts = bc().receipts(h).receipts; unsigned logIndex = 0; for (size_t i = 0; i < receipts.size(); i++) { logIndex++; TransactionReceipt receipt = receipts[i]; if (_f.matches(receipt.bloom())) { auto th = transaction(info.hash(), i).sha3(); LogEntries le = _f.matches(receipt); if (le.size()) { total += le.size(); for (unsigned j = 0; j < le.size(); ++j) ret.insert(ret.begin(), LocalisedLogEntry(le[j], info, th, i, logIndex)); } } if (!total) falsePos++; } } cdebug << matchingBlocks.size() << "searched from" << (end - begin) << "skipped; " << falsePos << "false +ves"; return ret; }
void ClientBase::prependLogsFromBlock(LogFilter const& _f, h256 const& _blockHash, BlockPolarity _polarity, LocalisedLogEntries& io_logs) const { auto receipts = bc().receipts(_blockHash).receipts; for (size_t i = 0; i < receipts.size(); i++) { TransactionReceipt receipt = receipts[i]; auto th = transaction(_blockHash, i).sha3(); LogEntries le = _f.matches(receipt); for (unsigned j = 0; j < le.size(); ++j) io_logs.insert(io_logs.begin(), LocalisedLogEntry(le[j], _blockHash, (BlockNumber)bc().number(_blockHash), th, i, 0, _polarity)); } }
LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { LocalisedLogEntries ret; unsigned begin = min(bc().number() + 1, (unsigned)numberFromHash(_f.latest())); unsigned end = min(bc().number(), min(begin, (unsigned)numberFromHash(_f.earliest()))); // Handle pending transactions differently as they're not on the block chain. if (begin > bc().number()) { Block temp = postMine(); for (unsigned i = 0; i < temp.pending().size(); ++i) { // Might have a transaction that contains a matching log. TransactionReceipt const& tr = temp.receipt(i); LogEntries le = _f.matches(tr); for (unsigned j = 0; j < le.size(); ++j) ret.insert(ret.begin(), LocalisedLogEntry(le[j])); } begin = bc().number(); } // Handle reverted blocks // There are not so many, so let's iterate over them h256s blocks; h256 ancestor; unsigned ancestorIndex; tie(blocks, ancestor, ancestorIndex) = bc().treeRoute(_f.earliest(), _f.latest(), false); for (size_t i = 0; i < ancestorIndex; i++) prependLogsFromBlock(_f, blocks[i], BlockPolarity::Dead, ret); // cause end is our earliest block, let's compare it with our ancestor // if ancestor is smaller let's move our end to it // example: // // 3b -> 2b -> 1b // -> g // 3a -> 2a -> 1a // // if earliest is at 2a and latest is a 3b, coverting them to numbers // will give us pair (2, 3) // and we want to get all logs from 1 (ancestor + 1) to 3 // so we have to move 2a to g + 1 end = min(end, (unsigned)numberFromHash(ancestor) + 1); // Handle blocks from main chain set<unsigned> matchingBlocks; if (!_f.isRangeFilter()) for (auto const& i: _f.bloomPossibilities()) for (auto u: bc().withBlockBloom(i, end, begin)) matchingBlocks.insert(u); else // if it is a range filter, we want to get all logs from all blocks in given range for (unsigned i = end; i <= begin; i++) matchingBlocks.insert(i); for (auto n: matchingBlocks) prependLogsFromBlock(_f, bc().numberHash(n), BlockPolarity::Live, ret); reverse(ret.begin(), ret.end()); return ret; }