diff --git a/CMakeLists.txt b/CMakeLists.txt
index b49a94559..36d9b7695 100644
--- a/CMakeLists.txt
+++ b/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 ()
diff --git a/alethzero/Main.ui b/alethzero/Main.ui
index 0872aabe4..b1a93aaab 100644
--- a/alethzero/Main.ui
+++ b/alethzero/Main.ui
@@ -223,6 +223,7 @@
+
diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 214dbab1e..6a9db4a22 100644
--- a/alethzero/MainWin.cpp
+++ b/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 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 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())
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index f06048c02..307cc1533 100644
--- a/alethzero/MainWin.h
+++ b/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();
diff --git a/libethcore/BlockInfo.h b/libethcore/BlockInfo.h
index c6812a112..389d0a8ef 100644
--- a/libethcore/BlockInfo.h
+++ b/libethcore/BlockInfo.h
@@ -41,6 +41,7 @@ enum IncludeProof
enum Strictness
{
CheckEverything,
+ JustSeal,
QuickNonce,
IgnoreSeal,
CheckNothing
diff --git a/libethcore/Common.h b/libethcore/Common.h
index c59b28f15..072d78cc3 100644
--- a/libethcore/Common.h
+++ b/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
};
};
diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h
index 8715507ba..68992286c 100644
--- a/libethcore/Exceptions.h
+++ b/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);
diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp
index a32f41830..8db2e9356 100644
--- a/libethereum/BlockChain.cpp
+++ b/libethereum/BlockChain.cpp
@@ -427,11 +427,11 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB c
return make_tuple(ImportRoute{dead, fresh, goodTransactions}, _bq.doneDrain(badBlocks), count);
}
-pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept
+pair 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 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 (...)
{
diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h
index c08faaa22..54a3e6c0c 100644
--- a/libethereum/BlockChain.h
+++ b/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 attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Everything) noexcept;
+ std::pair 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 const& _onBad, ImportRequirements::value _ir) const = 0;
+ virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function 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 const& _onBad, ImportRequirements::value _ir) const override
+ virtual VerifiedBlockRef verifyBlock(bytesConstRef _block, std::function 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(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();
diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp
index b0ebf8547..83b1c0703 100644
--- a/libethereum/BlockQueue.cpp
+++ b/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 (...)
{
diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp
index 635b0bbd7..be4d8d081 100644
--- a/libethereum/CanonBlockChain.cpp
+++ b/libethereum/CanonBlockChain.cpp
@@ -111,7 +111,7 @@ unordered_map CanonBlockChain::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;