Browse Source

Merge pull request #2654 from ethereum/outofordercheckfix

Only do out-of-order compatible verifications at verifier-thread time.
cl-refactor
Gav Wood 10 years ago
parent
commit
965f5996ea
  1. 1
      CMakeLists.txt
  2. 6
      alethzero/Main.ui
  3. 40
      alethzero/MainWin.cpp
  4. 1
      alethzero/MainWin.h
  5. 1
      libethcore/BlockInfo.h
  6. 12
      libethcore/Common.h
  7. 1
      libethcore/Exceptions.h
  8. 19
      libethereum/BlockChain.cpp
  9. 37
      libethereum/BlockChain.h
  10. 2
      libethereum/BlockQueue.cpp
  11. 2
      libethereum/CanonBlockChain.cpp

1
CMakeLists.txt

@ -139,7 +139,6 @@ elseif (BUNDLE STREQUAL "release") # release builds
set(D_EVMJIT ON)
set(D_JSCONSOLE ON)
set(D_JSONRPC ON)
set(D_FRONTIER ON)
set(D_CMAKE_BUILD_TYPE "Release")
endif ()

6
alethzero/Main.ui

@ -223,6 +223,7 @@
<addaction name="debugCurrent"/>
<addaction name="debugDumpState"/>
<addaction name="debugDumpStatePre"/>
<addaction name="dumpBlockState"/>
</widget>
<widget class="QMenu" name="menu_Config">
<property name="title">
@ -1819,6 +1820,11 @@ font-size: 14pt</string>
<string>&amp;Hermit Mode</string>
</property>
</action>
<action name="dumpBlockState">
<property name="text">
<string>Dump &amp;Block State as JSON...</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

40
alethzero/MainWin.cpp

@ -1851,6 +1851,46 @@ void Main::on_debugCurrent_triggered()
}
}
std::string minHex(h256 const& _h)
{
unsigned i = 0;
for (; i < 31 && !_h[i]; ++i) {}
return toHex(_h.ref().cropped(i));
}
void Main::on_dumpBlockState_triggered()
{
#if ETH_FATDB || !ETH_TRUE
if (auto item = ui->blocks->currentItem())
{
auto hba = item->data(Qt::UserRole).toByteArray();
assert(hba.size() == 32);
auto h = h256((byte const*)hba.data(), h256::ConstructFromPointer);
QString fn = QFileDialog::getSaveFileName(this, "Select file to output state dump");
ofstream f(fn.toStdString());
if (f.is_open())
{
js::mObject s;
State state = ethereum()->state(h);
for (pair<Address, u256> const& i: state.addresses())
{
js::mObject a;
a["balance"] = toString(i.second);
a["nonce"] = toString(state.transactionsFrom(i.first));
a["codeHash"] = state.codeHash(i.first).hex();
js::mObject st;
for (pair<u256, u256> const& j: state.storage(i.first))
st[minHex(j.first)] = st[minHex(j.second)];
a["storage"] = st;
s[i.first.hex()] = a;
}
js::mValue v(s);
js::write_stream(v, f, true);
}
}
#endif
}
void Main::debugDumpState(int _add)
{
if (auto item = ui->blocks->currentItem())

1
alethzero/MainWin.h

@ -193,6 +193,7 @@ private slots:
void on_debugCurrent_triggered();
void on_debugDumpState_triggered() { debugDumpState(1); }
void on_debugDumpStatePre_triggered() { debugDumpState(0); }
void on_dumpBlockState_triggered();
// Whisper
void on_newIdentity_triggered();

1
libethcore/BlockInfo.h

@ -41,6 +41,7 @@ enum IncludeProof
enum Strictness
{
CheckEverything,
JustSeal,
QuickNonce,
IgnoreSeal,
CheckNothing

12
libethcore/Common.h

@ -127,15 +127,17 @@ struct ImportRequirements
enum
{
ValidSeal = 1, ///< Validate seal
DontHave = 2, ///< Avoid old blocks
UncleBasic = 4, ///< Check the basic structure of the uncles.
TransactionBasic = 8, ///< Check the basic structure of the transactions.
UncleSeals = 16, ///< Check the basic structure of the uncles.
TransactionSignatures = 32, ///< Check the basic structure of the transactions.
Parent = 64, ///< Check parent block header
CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals
CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures
Everything = ValidSeal | DontHave | CheckUncles | CheckTransactions | Parent,
Parent = 64, ///< Check parent block header.
UncleParent = 128, ///< Check uncle parent block header.
CheckUncles = UncleBasic | UncleSeals, ///< Check uncle seals.
CheckTransactions = TransactionBasic | TransactionSignatures, ///< Check transaction signatures.
OutOfOrderChecks = ValidSeal | CheckUncles | CheckTransactions, ///< Do all checks that can be done independently of prior blocks having been imported.
InOrderChecks = Parent | UncleParent, ///< Do all checks that cannot be done independently of prior blocks having been imported.
Everything = ValidSeal | CheckUncles | CheckTransactions | Parent | UncleParent,
None = 0
};
};

1
libethcore/Exceptions.h

@ -70,6 +70,7 @@ DEV_SIMPLE_EXCEPTION(InvalidNonce);
DEV_SIMPLE_EXCEPTION(InvalidBlockHeaderItemCount);
DEV_SIMPLE_EXCEPTION(InvalidBlockNonce);
DEV_SIMPLE_EXCEPTION(InvalidParentHash);
DEV_SIMPLE_EXCEPTION(InvalidUncleParentHash);
DEV_SIMPLE_EXCEPTION(InvalidNumber);
DEV_SIMPLE_EXCEPTION(BlockNotFound);

19
libethereum/BlockChain.cpp

@ -427,11 +427,11 @@ tuple<ImportRoute, bool, unsigned> BlockChain::sync(BlockQueue& _bq, OverlayDB c
return make_tuple(ImportRoute{dead, fresh, goodTransactions}, _bq.doneDrain(badBlocks), count);
}
pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept
pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _mustBeNew) noexcept
{
try
{
return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, _ir), _stateDB, _ir | ImportRequirements::TransactionBasic));
return make_pair(ImportResult::Success, import(verifyBlock(&_block, m_onBad, ImportRequirements::OutOfOrderChecks), _stateDB, _mustBeNew));
}
catch (UnknownParent&)
{
@ -453,7 +453,7 @@ pair<ImportResult, ImportRoute> BlockChain::attemptImport(bytes const& _block, O
}
}
ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir)
ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, bool _mustBeNew)
{
// VERIFY: populates from the block and checks the block is internally coherent.
VerifiedBlockRef block;
@ -462,7 +462,7 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
try
#endif
{
block = verifyBlock(&_block, m_onBad, _ir | ImportRequirements::TransactionBasic);
block = verifyBlock(&_block, m_onBad, ImportRequirements::OutOfOrderChecks);
}
#if ETH_CATCH
catch (Exception& ex)
@ -474,10 +474,10 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import
}
#endif
return import(block, _db, _ir);
return import(block, _db, _mustBeNew);
}
ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir)
ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _db, bool _mustBeNew)
{
//@tidy This is a behemoth of a method - could do to be split into a few smaller ones.
@ -492,7 +492,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
#endif
// Check block doesn't already exist first!
if (isKnown(_block.info.hash()) && (_ir & ImportRequirements::DontHave))
if (isKnown(_block.info.hash()) && _mustBeNew)
{
clog(BlockChainNote) << _block.info.hash() << ": Not new.";
BOOST_THROW_EXCEPTION(AlreadyHaveBlock());
@ -528,6 +528,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
BOOST_THROW_EXCEPTION(FutureTime());
}
// Verify parent-critical parts
verifyBlock(_block.block, m_onBad, ImportRequirements::InOrderChecks);
clog(BlockChainChat) << "Attempting import of " << _block.info.hash() << "...";
#if ETH_TIMED_IMPORTS
@ -758,7 +761,7 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const&
try
{
State canary(_db, BaseState::Empty);
canary.populateFromChain(*this, _block.info.hash(), ImportRequirements::DontHave);
canary.populateFromChain(*this, _block.info.hash());
}
catch (...)
{

37
libethereum/BlockChain.h

@ -122,12 +122,12 @@ public:
/// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB.
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
std::pair<ImportResult, ImportRoute> attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept;
std::pair<ImportResult, ImportRoute> attemptImport(bytes const& _block, OverlayDB const& _stateDB, bool _mutBeNew = true) noexcept;
/// Import block into disk-backed DB
/// @returns the block hashes of any blocks that came into/went out of the canonical block chain.
ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything);
ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Everything);
ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, bool _mustBeNew = true);
ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, bool _mustBeNew = true);
/// Returns true if the given block is known (though not necessarily a part of the canon chain).
bool isKnown(h256 const& _hash) const;
@ -289,7 +289,7 @@ public:
State genesisState(OverlayDB const& _db);
/// Verify block and prepare it for enactment
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir) const = 0;
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir = ImportRequirements::OutOfOrderChecks) const = 0;
protected:
static h256 chunkId(unsigned _level, unsigned _index) { return h256(_index * 0xff + _level); }
@ -410,7 +410,7 @@ public:
typename Sealer::BlockHeader header(h256 const& _hash) const { return typename Sealer::BlockHeader(headerData(_hash), IgnoreSeal, _hash, HeaderData); }
typename Sealer::BlockHeader header() const { return header(currentHash()); }
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir) const override
virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function<void(Exception&)> const& _onBad, ImportRequirements::value _ir = ImportRequirements::OutOfOrderChecks) const override
{
VerifiedBlockRef res;
BlockHeader h;
@ -418,11 +418,11 @@ public:
{
h = BlockHeader(_block, (_ir & ImportRequirements::ValidSeal) ? Strictness::CheckEverything : Strictness::QuickNonce);
h.verifyInternals(_block);
if ((_ir & ImportRequirements::Parent) != 0)
if (!!(_ir & ImportRequirements::Parent))
{
bytes parentHeader(headerData(h.parentHash()));
if (parentHeader.empty())
BOOST_THROW_EXCEPTION(InvalidParentHash());
BOOST_THROW_EXCEPTION(InvalidParentHash() << errinfo_required_h256(h.parentHash()) << errinfo_currentNumber(h.number()));
h.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, h.parentHash(), HeaderData));
}
res.info = static_cast<BlockInfo&>(h);
@ -443,17 +443,20 @@ public:
RLP r(_block);
unsigned i = 0;
if (_ir && ImportRequirements::UncleBasic)
if (_ir && (ImportRequirements::UncleBasic | ImportRequirements::UncleParent | ImportRequirements::UncleSeals))
for (auto const& uncle: r[2])
{
BlockHeader h;
BlockHeader uh;
try
{
h.populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal);
bytes parentHeader(headerData(h.parentHash()));
if (parentHeader.empty())
BOOST_THROW_EXCEPTION(InvalidParentHash());
h.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, h.parentHash(), HeaderData));
uh.populateFromHeader(RLP(uncle.data()), (_ir & ImportRequirements::UncleSeals) ? Strictness::CheckEverything : Strictness::IgnoreSeal);
if (!!(_ir & ImportRequirements::UncleParent))
{
bytes parentHeader(headerData(uh.parentHash()));
if (parentHeader.empty())
BOOST_THROW_EXCEPTION(InvalidUncleParentHash() << errinfo_required_h256(uh.parentHash()) << errinfo_currentNumber(h.number()) << errinfo_uncleNumber(uh.number()));
uh.verifyParent(typename Sealer::BlockHeader(parentHeader, IgnoreSeal, uh.parentHash(), HeaderData));
}
}
catch (Exception& ex)
{
@ -463,8 +466,8 @@ public:
ex << errinfo_block(_block.toBytes());
// only populate extraData if we actually managed to extract it. otherwise,
// we might be clobbering the existing one.
if (!h.extraData().empty())
ex << errinfo_extraData(h.extraData());
if (!uh.extraData().empty())
ex << errinfo_extraData(uh.extraData());
if (_onBad)
_onBad(ex);
throw;
@ -472,7 +475,7 @@ public:
++i;
}
i = 0;
if (_ir && ImportRequirements::TransactionBasic)
if (_ir && (ImportRequirements::TransactionBasic | ImportRequirements::TransactionSignatures))
for (RLP const& tr: r[1])
{
bytesConstRef d = tr.data();

2
libethereum/BlockQueue.cpp

@ -111,7 +111,7 @@ void BlockQueue::verifierBody()
swap(work.block, res.blockData);
try
{
res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::Everything & ~ImportRequirements::Parent);
res.verified = m_bc->verifyBlock(&res.blockData, m_onBad, ImportRequirements::OutOfOrderChecks);
}
catch (...)
{

2
libethereum/CanonBlockChain.cpp

@ -111,7 +111,7 @@ unordered_map<Address, Account> CanonBlockChain<Ethash>::createGenesisState()
if (s_ret.empty())
{
js::mValue val;
json_spirit::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val);
js::read_string(s_genesisStateJSON.empty() ? c_genesisInfo : s_genesisStateJSON, val);
for (auto account: val.get_obj()["alloc"].get_obj())
{
u256 balance;

Loading…
Cancel
Save