|
@ -56,18 +56,23 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
|
|
|
|
|
|
BOOST_REQUIRE(o.count("pre")); |
|
|
BOOST_REQUIRE(o.count("pre")); |
|
|
ImportTest importer(o["pre"].get_obj()); |
|
|
ImportTest importer(o["pre"].get_obj()); |
|
|
TransientDirectory td_stateDB; |
|
|
|
|
|
TransientDirectory td_stateDB_tmp; |
|
|
TransientDirectory td_stateDB_tmp; |
|
|
State state(State::openDB(td_stateDB.path()), BaseState::Empty, biGenesisBlock.coinbaseAddress); |
|
|
State trueState(OverlayDB(State::openDB(td_stateDB_tmp.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); |
|
|
State stateTemp(State::openDB(td_stateDB_tmp.path()), BaseState::Empty, biGenesisBlock.coinbaseAddress); |
|
|
|
|
|
importer.importState(o["pre"].get_obj(), state); |
|
|
//Imported blocks from the start
|
|
|
o["pre"] = fillJsonWithState(state); |
|
|
typedef std::vector<bytes> uncleList; |
|
|
state.commit(); |
|
|
typedef std::pair<bytes, uncleList> blockSet; |
|
|
|
|
|
std::vector<blockSet> blockRLPs; |
|
|
|
|
|
|
|
|
|
|
|
importer.importState(o["pre"].get_obj(), trueState); |
|
|
|
|
|
o["pre"] = fillJsonWithState(trueState); |
|
|
|
|
|
trueState.commit(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (_fillin) |
|
|
if (_fillin) |
|
|
biGenesisBlock.stateRoot = state.rootHash(); |
|
|
biGenesisBlock.stateRoot = trueState.rootHash(); |
|
|
else |
|
|
else |
|
|
BOOST_CHECK_MESSAGE(biGenesisBlock.stateRoot == state.rootHash(), "root hash does not match"); |
|
|
BOOST_CHECK_MESSAGE(biGenesisBlock.stateRoot == trueState.rootHash(), "root hash does not match"); |
|
|
|
|
|
|
|
|
if (_fillin) |
|
|
if (_fillin) |
|
|
{ |
|
|
{ |
|
@ -83,20 +88,55 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
biGenesisBlock.verifyInternals(&rlpGenesisBlock.out()); |
|
|
biGenesisBlock.verifyInternals(&rlpGenesisBlock.out()); |
|
|
o["genesisRLP"] = toHex(rlpGenesisBlock.out(), 2, HexPrefix::Add); |
|
|
o["genesisRLP"] = toHex(rlpGenesisBlock.out(), 2, HexPrefix::Add); |
|
|
|
|
|
|
|
|
// construct blockchain
|
|
|
// construct true blockchain
|
|
|
TransientDirectory td; |
|
|
TransientDirectory td; |
|
|
BlockChain bc(rlpGenesisBlock.out(), td.path(), WithExisting::Kill); |
|
|
BlockChain trueBc(rlpGenesisBlock.out(), td.path(), WithExisting::Kill); |
|
|
|
|
|
|
|
|
if (_fillin) |
|
|
if (_fillin) |
|
|
{ |
|
|
{ |
|
|
BOOST_REQUIRE(o.count("blocks")); |
|
|
BOOST_REQUIRE(o.count("blocks")); |
|
|
mArray blArray; |
|
|
mArray blArray; |
|
|
|
|
|
|
|
|
|
|
|
blockSet genesis; |
|
|
|
|
|
genesis.first = rlpGenesisBlock.out(); |
|
|
|
|
|
genesis.second = uncleList(); |
|
|
|
|
|
blockRLPs.push_back(genesis); |
|
|
vector<BlockInfo> vBiBlocks; |
|
|
vector<BlockInfo> vBiBlocks; |
|
|
vBiBlocks.push_back(biGenesisBlock); |
|
|
vBiBlocks.push_back(biGenesisBlock); |
|
|
|
|
|
|
|
|
|
|
|
size_t importBlockNumber; |
|
|
for (auto const& bl: o["blocks"].get_array()) |
|
|
for (auto const& bl: o["blocks"].get_array()) |
|
|
{ |
|
|
{ |
|
|
stateTemp = state; |
|
|
|
|
|
mObject blObj = bl.get_obj(); |
|
|
mObject blObj = bl.get_obj(); |
|
|
|
|
|
BOOST_REQUIRE(blObj.count("blocknumber")); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//each time construct a new blockchain up to importBlockNumber (to generate next block header)
|
|
|
|
|
|
vBiBlocks.clear(); |
|
|
|
|
|
vBiBlocks.push_back(biGenesisBlock); |
|
|
|
|
|
|
|
|
|
|
|
TransientDirectory td_stateDB, td_bc; |
|
|
|
|
|
BlockChain bc(rlpGenesisBlock.out(), td_bc.path(), WithExisting::Kill); |
|
|
|
|
|
State state(OverlayDB(State::openDB(td_stateDB.path())), BaseState::Empty, biGenesisBlock.coinbaseAddress); |
|
|
|
|
|
importer.importState(o["pre"].get_obj(), state); |
|
|
|
|
|
state.commit(); |
|
|
|
|
|
|
|
|
|
|
|
importBlockNumber = std::max((int)toInt(blObj["blocknumber"]), 1); |
|
|
|
|
|
for (size_t i = 1; i < importBlockNumber; i++) //0 block is genesis
|
|
|
|
|
|
{ |
|
|
|
|
|
BlockQueue uncleQueue; |
|
|
|
|
|
uncleList uncles = blockRLPs.at(i).second; |
|
|
|
|
|
for (size_t j = 0; j < uncles.size(); j++) |
|
|
|
|
|
uncleQueue.import(&uncles.at(j), bc); |
|
|
|
|
|
|
|
|
|
|
|
const bytes block = blockRLPs.at(i).first; |
|
|
|
|
|
bc.sync(uncleQueue, state.db(), 4); |
|
|
|
|
|
bc.attemptImport(block, state.db()); |
|
|
|
|
|
vBiBlocks.push_back(BlockInfo(block)); |
|
|
|
|
|
|
|
|
|
|
|
state.sync(bc); |
|
|
|
|
|
//vBiBlocks.push_back(state.info());
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// get txs
|
|
|
// get txs
|
|
|
TransactionQueue txs; |
|
|
TransactionQueue txs; |
|
@ -115,6 +155,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks); |
|
|
blObj["uncleHeaders"] = importUncles(blObj, vBiUncles, vBiBlocks); |
|
|
|
|
|
|
|
|
BlockQueue uncleBlockQueue; |
|
|
BlockQueue uncleBlockQueue; |
|
|
|
|
|
uncleList uncleBlockQueueList; |
|
|
cnote << "import uncle in blockQueue"; |
|
|
cnote << "import uncle in blockQueue"; |
|
|
for (size_t i = 0; i < vBiUncles.size(); i++) |
|
|
for (size_t i = 0; i < vBiUncles.size(); i++) |
|
|
{ |
|
|
{ |
|
@ -122,6 +163,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
uncleBlockQueue.import(&uncle.out(), bc); |
|
|
uncleBlockQueue.import(&uncle.out(), bc); |
|
|
|
|
|
uncleBlockQueueList.push_back(uncle.out()); |
|
|
} |
|
|
} |
|
|
catch(...) |
|
|
catch(...) |
|
|
{ |
|
|
{ |
|
@ -205,6 +247,24 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
bc.import(block2.out(), state.db()); |
|
|
bc.import(block2.out(), state.db()); |
|
|
state.sync(bc); |
|
|
state.sync(bc); |
|
|
state.commit(); |
|
|
state.commit(); |
|
|
|
|
|
|
|
|
|
|
|
//there we get new blockchain status in state which could have more difficulty than we have in trueState
|
|
|
|
|
|
//attempt to import new block to the true blockchain
|
|
|
|
|
|
trueBc.sync(uncleBlockQueue, trueState.db(), 4); |
|
|
|
|
|
trueBc.attemptImport(state.blockData(), trueState.db()); |
|
|
|
|
|
trueState.sync(trueBc); |
|
|
|
|
|
|
|
|
|
|
|
blockSet newBlock; |
|
|
|
|
|
newBlock.first = state.blockData(); |
|
|
|
|
|
newBlock.second = uncleBlockQueueList; |
|
|
|
|
|
if (importBlockNumber < blockRLPs.size()) |
|
|
|
|
|
{ |
|
|
|
|
|
//make new correct history of imported blocks
|
|
|
|
|
|
blockRLPs[importBlockNumber] = newBlock; |
|
|
|
|
|
for (size_t i = importBlockNumber+1; i < blockRLPs.size(); i++) |
|
|
|
|
|
blockRLPs.pop_back(); |
|
|
|
|
|
} |
|
|
|
|
|
else blockRLPs.push_back(newBlock); |
|
|
} |
|
|
} |
|
|
// if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given
|
|
|
// if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given
|
|
|
catch (...) |
|
|
catch (...) |
|
@ -213,7 +273,6 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
blObj.erase(blObj.find("blockHeader")); |
|
|
blObj.erase(blObj.find("blockHeader")); |
|
|
blObj.erase(blObj.find("uncleHeaders")); |
|
|
blObj.erase(blObj.find("uncleHeaders")); |
|
|
blObj.erase(blObj.find("transactions")); |
|
|
blObj.erase(blObj.find("transactions")); |
|
|
state = stateTemp; //revert state as if it was before executing this block
|
|
|
|
|
|
} |
|
|
} |
|
|
blArray.push_back(blObj); |
|
|
blArray.push_back(blObj); |
|
|
this_thread::sleep_for(chrono::seconds(1)); |
|
|
this_thread::sleep_for(chrono::seconds(1)); |
|
@ -224,14 +283,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
stateOptionsMap expectStateMap; |
|
|
stateOptionsMap expectStateMap; |
|
|
State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); |
|
|
State stateExpect(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); |
|
|
importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); |
|
|
importer.importState(o["expect"].get_obj(), stateExpect, expectStateMap); |
|
|
ImportTest::checkExpectedState(stateExpect, state, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); |
|
|
ImportTest::checkExpectedState(stateExpect, trueState, expectStateMap, Options::get().checkState ? WhenError::Throw : WhenError::DontThrow); |
|
|
o.erase(o.find("expect")); |
|
|
o.erase(o.find("expect")); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
o["blocks"] = blArray; |
|
|
o["blocks"] = blArray; |
|
|
o["postState"] = fillJsonWithState(state); |
|
|
o["postState"] = fillJsonWithState(trueState); |
|
|
|
|
|
|
|
|
//make all values hex
|
|
|
//make all values hex in pre section
|
|
|
State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); |
|
|
State prestate(OverlayDB(), BaseState::Empty, biGenesisBlock.coinbaseAddress); |
|
|
importer.importState(o["pre"].get_obj(), prestate); |
|
|
importer.importState(o["pre"].get_obj(), prestate); |
|
|
o["pre"] = fillJsonWithState(prestate); |
|
|
o["pre"] = fillJsonWithState(prestate); |
|
@ -241,14 +300,17 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
{ |
|
|
{ |
|
|
for (auto const& bl: o["blocks"].get_array()) |
|
|
for (auto const& bl: o["blocks"].get_array()) |
|
|
{ |
|
|
{ |
|
|
|
|
|
bool importedAndNotBest = false; |
|
|
mObject blObj = bl.get_obj(); |
|
|
mObject blObj = bl.get_obj(); |
|
|
bytes blockRLP; |
|
|
bytes blockRLP; |
|
|
try |
|
|
try |
|
|
{ |
|
|
{ |
|
|
state.sync(bc); |
|
|
trueState.sync(trueBc); |
|
|
blockRLP = importByteArray(blObj["rlp"].get_str()); |
|
|
blockRLP = importByteArray(blObj["rlp"].get_str()); |
|
|
bc.import(blockRLP, state.db()); |
|
|
trueBc.import(blockRLP, trueState.db()); |
|
|
state.sync(bc); |
|
|
if (trueBc.info() != BlockInfo(blockRLP)) |
|
|
|
|
|
importedAndNotBest = true; |
|
|
|
|
|
trueState.sync(trueBc); |
|
|
} |
|
|
} |
|
|
// if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given
|
|
|
// if exception is thrown, RLP is invalid and no blockHeader, Transaction list, or Uncle list should be given
|
|
|
catch (Exception const& _e) |
|
|
catch (Exception const& _e) |
|
@ -284,8 +346,10 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader); |
|
|
const RLP c_blockHeaderRLP(c_rlpBytesBlockHeader); |
|
|
blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreNonce); |
|
|
blockHeaderFromFields.populateFromHeader(c_blockHeaderRLP, IgnoreNonce); |
|
|
|
|
|
|
|
|
BlockInfo blockFromRlp = bc.info(); |
|
|
BlockInfo blockFromRlp = trueBc.info(); |
|
|
|
|
|
|
|
|
|
|
|
if (!importedAndNotBest) |
|
|
|
|
|
{ |
|
|
//Check the fields restored from RLP to original fields
|
|
|
//Check the fields restored from RLP to original fields
|
|
|
BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); |
|
|
BOOST_CHECK_MESSAGE(blockHeaderFromFields.headerHash(WithNonce) == blockFromRlp.headerHash(WithNonce), "hash in given RLP not matching the block hash!"); |
|
|
BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); |
|
|
BOOST_CHECK_MESSAGE(blockHeaderFromFields.parentHash == blockFromRlp.parentHash, "parentHash in given RLP not matching the block parentHash!"); |
|
@ -404,6 +468,7 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// helping functions
|
|
|
// helping functions
|
|
@ -635,11 +700,11 @@ mObject writeBlockHeaderToJson(mObject& _o, BlockInfo const& _bi) |
|
|
_o["transactionsTrie"] = toString(_bi.transactionsRoot); |
|
|
_o["transactionsTrie"] = toString(_bi.transactionsRoot); |
|
|
_o["receiptTrie"] = toString(_bi.receiptsRoot); |
|
|
_o["receiptTrie"] = toString(_bi.receiptsRoot); |
|
|
_o["bloom"] = toString(_bi.logBloom); |
|
|
_o["bloom"] = toString(_bi.logBloom); |
|
|
_o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add, 1); |
|
|
_o["difficulty"] = toCompactHex(_bi.difficulty, HexPrefix::Add); |
|
|
_o["number"] = toCompactHex(_bi.number, HexPrefix::Add, 1); |
|
|
_o["number"] = toCompactHex(_bi.number, HexPrefix::Add); |
|
|
_o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add, 1); |
|
|
_o["gasLimit"] = toCompactHex(_bi.gasLimit, HexPrefix::Add); |
|
|
_o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add, 1); |
|
|
_o["gasUsed"] = toCompactHex(_bi.gasUsed, HexPrefix::Add); |
|
|
_o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add, 1); |
|
|
_o["timestamp"] = toCompactHex(_bi.timestamp, HexPrefix::Add); |
|
|
_o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); |
|
|
_o["extraData"] = toHex(_bi.extraData, 2, HexPrefix::Add); |
|
|
_o["mixHash"] = toString(_bi.mixHash); |
|
|
_o["mixHash"] = toString(_bi.mixHash); |
|
|
_o["nonce"] = toString(_bi.nonce); |
|
|
_o["nonce"] = toString(_bi.nonce); |
|
@ -669,6 +734,11 @@ BOOST_AUTO_TEST_CASE(bcForkBlockTest) |
|
|
dev::test::executeTests("bcForkBlockTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); |
|
|
dev::test::executeTests("bcForkBlockTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(bcTotalDifficultyTest) |
|
|
|
|
|
{ |
|
|
|
|
|
dev::test::executeTests("bcTotalDifficultyTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(bcInvalidRLPTest) |
|
|
BOOST_AUTO_TEST_CASE(bcInvalidRLPTest) |
|
|
{ |
|
|
{ |
|
|
dev::test::executeTests("bcInvalidRLPTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); |
|
|
dev::test::executeTests("bcInvalidRLPTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); |
|
|