@ -33,8 +33,10 @@ namespace dev { namespace test {
bytes createBlockRLPFromFields ( mObject & _tObj ) ;
bytes createBlockRLPFromFields ( mObject & _tObj ) ;
void overwriteBlockHeader ( BlockInfo & current_BlockHeader , mObject & blObj ) ;
void overwriteBlockHeader ( BlockInfo & current_BlockHeader , mObject & blObj ) ;
BlockInfo constructBlock ( mObject & _o ) ;
void updatePoW ( BlockInfo & _bi ) ;
void writeBlockHeaderToJson ( mObject & _o , const BlockInfo & _bi ) ;
RLPStream createFullBlockFromHeader ( const BlockInfo & _bi , const bytes & _txs = RLPEmptyList , const bytes & _uncles = RLPEmptyList ) ;
void doBlockchainTests ( json_spirit : : mValue & _v , bool _fillin )
void doBlockchainTests ( json_spirit : : mValue & _v , bool _fillin )
{
{
@ -44,86 +46,47 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
mObject & o = i . second . get_obj ( ) ;
mObject & o = i . second . get_obj ( ) ;
BOOST_REQUIRE ( o . count ( " genesisBlockHeader " ) ) ;
BOOST_REQUIRE ( o . count ( " genesisBlockHeader " ) ) ;
BlockInfo blockFromFields ;
BlockInfo biGenesisBlock = constructBlock ( o [ " genesisBlockHeader " ] . get_obj ( ) ) ;
try
{
// construct genesis block
const bytes c_blockRLP = createBlockRLPFromFields ( o [ " genesisBlockHeader " ] . get_obj ( ) ) ;
const RLP c_bRLP ( c_blockRLP ) ;
blockFromFields . populateFromHeader ( c_bRLP , false ) ;
}
catch ( Exception const & _e )
{
cnote < < " block population did throw an exception: " < < diagnostic_information ( _e ) ;
BOOST_ERROR ( " Failed block population with Exception: " < < _e . what ( ) ) ;
continue ;
}
catch ( std : : exception const & _e )
{
BOOST_ERROR ( " Failed block population with Exception: " < < _e . what ( ) ) ;
continue ;
}
catch ( . . . )
{
cnote < < " block population did throw an unknown exception \n " ;
continue ;
}
BOOST_REQUIRE ( o . count ( " pre " ) ) ;
BOOST_REQUIRE ( o . count ( " pre " ) ) ;
ImportTest importer ( o [ " pre " ] . get_obj ( ) ) ;
ImportTest importer ( o [ " pre " ] . get_obj ( ) ) ;
State state ( Address ( ) , OverlayDB ( ) , BaseState : : Empty ) ;
State state ( Address ( ) , OverlayDB ( ) , BaseState : : Empty ) ;
importer . importState ( o [ " pre " ] . get_obj ( ) , state ) ;
importer . importState ( o [ " pre " ] . get_obj ( ) , state ) ;
state . commit ( ) ;
state . commit ( ) ;
if ( _fillin )
if ( _fillin )
blockFromFields . stateRoot = state . rootHash ( ) ;
biGenesisBlock . stateRoot = state . rootHash ( ) ;
else
else
BOOST_CHECK_MESSAGE ( blockFromFields . stateRoot = = state . rootHash ( ) , " root hash does not match " ) ;
BOOST_CHECK_MESSAGE ( biGenesisBlock . stateRoot = = state . rootHash ( ) , " root hash does not match " ) ;
if ( _fillin )
if ( _fillin )
{
{
// find new valid nonce
// find new valid nonce
ProofOfWork pow ;
updatePoW ( biGenesisBlock ) ;
std : : pair < MineInfo , Ethash : : Proof > ret ;
while ( ! ProofOfWork : : verify ( blockFromFields ) )
{
ret = pow . mine ( blockFromFields , 1000 , true , true ) ; // tie(ret, blockFromFields.nonce)
Ethash : : assignResult ( ret . second , blockFromFields ) ;
}
//update genesis block in json file
//update genesis block in json file
o [ " genesisBlockHeader " ] . get_obj ( ) [ " stateRoot " ] = toString ( blockFromFields . stateRoot ) ;
writeBlockHeaderToJson ( o [ " genesisBlockHeader " ] . get_obj ( ) , biGenesisBlock ) ;
o [ " genesisBlockHeader " ] . get_obj ( ) [ " nonce " ] = toString ( blockFromFields . nonce ) ;
o [ " genesisBlockHeader " ] . get_obj ( ) [ " mixHash " ] = toString ( blockFromFields . mixHash ) ;
o [ " genesisBlockHeader " ] . get_obj ( ) [ " hash " ] = toString ( blockFromFields . headerHash ( WithNonce ) ) ;
}
}
// create new "genesis" block
// create new "genesis" block
RLPStream rlpStream ;
RLPStream rlpGenesisBlock = createFullBlockFromHeader ( biGenesisBlock ) ;
blockFromFields . streamRLP ( rlpStream , WithNonce ) ;
biGenesisBlock . verifyInternals ( & rlpGenesisBlock . out ( ) ) ;
RLPStream block ( 3 ) ;
block . appendRaw ( rlpStream . out ( ) ) ;
block . appendRaw ( RLPEmptyList ) ;
block . appendRaw ( RLPEmptyList ) ;
blockFromFields . verifyInternals ( & block . out ( ) ) ;
// construct blockchain
// construct blockchain
BlockChain bc ( b lock. out ( ) , string ( ) , true ) ;
BlockChain bc ( rlpGenesisBlock . out ( ) , string ( ) , true ) ;
if ( _fillin )
if ( _fillin )
{
{
BOOST_REQUIRE ( o . count ( " blocks " ) ) ;
BOOST_REQUIRE ( o . count ( " blocks " ) ) ;
mArray blArray ;
mArray blArray ;
vector < BlockInfo > vBiBlocks ;
for ( auto const & bl : o [ " blocks " ] . get_array ( ) )
for ( auto const & bl : o [ " blocks " ] . get_array ( ) )
{
{
mObject blObj = bl . get_obj ( ) ;
mObject blObj = bl . get_obj ( ) ;
BOOST_REQUIRE ( blObj . count ( " transactions " ) ) ;
// get txs
TransactionQueue txs ;
TransactionQueue txs ;
BOOST_REQUIRE ( blObj . count ( " transactions " ) ) ;
for ( auto const & txObj : blObj [ " transactions " ] . get_array ( ) )
for ( auto const & txObj : blObj [ " transactions " ] . get_array ( ) )
{
{
mObject tx = txObj . get_obj ( ) ;
mObject tx = txObj . get_obj ( ) ;
@ -132,6 +95,35 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
cnote < < " failed importing transaction \n " ;
cnote < < " failed importing transaction \n " ;
}
}
// write uncle list
BlockQueue uncleBlockQueue ;
mArray aUncleList ;
vector < BlockInfo > vBiUncles ;
for ( auto const & uHObj : blObj [ " uncleHeaders " ] . get_array ( ) )
{
mObject uncleHeaderObj = uHObj . get_obj ( ) ;
BlockInfo uncleBlockFromFields = constructBlock ( uncleHeaderObj ) ;
// make uncle header valid
uncleBlockFromFields . populateFromParent ( vBiBlocks [ vBiBlocks . size ( ) - 2 ] ) ;
uncleBlockFromFields . timestamp = ( u256 ) time ( 0 ) ;
updatePoW ( uncleBlockFromFields ) ;
writeBlockHeaderToJson ( uncleHeaderObj , uncleBlockFromFields ) ;
aUncleList . push_back ( uncleHeaderObj ) ;
vBiUncles . push_back ( uncleBlockFromFields ) ;
cnote < < " import uncle in blockQueue " ;
RLPStream uncle = createFullBlockFromHeader ( uncleBlockFromFields ) ;
uncleBlockQueue . import ( & uncle . out ( ) , bc ) ;
}
blObj [ " uncleHeaders " ] = aUncleList ;
bc . sync ( uncleBlockQueue , state . db ( ) , 4 ) ;
state . commitToMine ( bc ) ;
try
try
{
{
state . sync ( bc ) ;
state . sync ( bc ) ;
@ -152,6 +144,8 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
return ;
return ;
}
}
blObj [ " rlp " ] = " 0x " + toHex ( state . blockData ( ) ) ;
// write valid txs
// write valid txs
mArray txArray ;
mArray txArray ;
Transactions txList ;
Transactions txList ;
@ -174,46 +168,19 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
}
}
blObj [ " transactions " ] = txArray ;
blObj [ " transactions " ] = txArray ;
blObj [ " rlp " ] = " 0x " + toHex ( state . blockData ( ) ) ;
BlockInfo current_BlockHeader = state . info ( ) ;
BlockInfo current_BlockHeader = state . info ( ) ;
// overwrite blockheader with (possible wrong) data from "blockheader" in filler;
if ( blObj . count ( " blockHeader " ) )
if ( blObj . count ( " blockHeader " ) )
{
overwriteBlockHeader ( current_BlockHeader , blObj ) ;
overwriteBlockHeader ( current_BlockHeader , blObj ) ;
}
// write block header
// write block header
mObject oBlockHeader ;
mObject oBlockHeader ;
oBlockHeader [ " parentHash " ] = toString ( current_BlockHeader . parentHash ) ;
writeBlockHeaderToJson ( oBlockHeader , current_BlockHeader ) ;
oBlockHeader [ " uncleHash " ] = toString ( current_BlockHeader . sha3Uncles ) ;
oBlockHeader [ " coinbase " ] = toString ( current_BlockHeader . coinbaseAddress ) ;
oBlockHeader [ " stateRoot " ] = toString ( current_BlockHeader . stateRoot ) ;
oBlockHeader [ " transactionsTrie " ] = toString ( current_BlockHeader . transactionsRoot ) ;
oBlockHeader [ " receiptTrie " ] = toString ( current_BlockHeader . receiptsRoot ) ;
oBlockHeader [ " bloom " ] = toString ( current_BlockHeader . logBloom ) ;
oBlockHeader [ " difficulty " ] = toString ( current_BlockHeader . difficulty ) ;
oBlockHeader [ " number " ] = toString ( current_BlockHeader . number ) ;
oBlockHeader [ " gasLimit " ] = toString ( current_BlockHeader . gasLimit ) ;
oBlockHeader [ " gasUsed " ] = toString ( current_BlockHeader . gasUsed ) ;
oBlockHeader [ " timestamp " ] = toString ( current_BlockHeader . timestamp ) ;
oBlockHeader [ " extraData " ] = " 0x " + toHex ( current_BlockHeader . extraData ) ;
oBlockHeader [ " mixHash " ] = toString ( current_BlockHeader . mixHash ) ;
oBlockHeader [ " seedHash " ] = toString ( current_BlockHeader . seedHash ) ;
oBlockHeader [ " nonce " ] = toString ( current_BlockHeader . nonce ) ;
oBlockHeader [ " hash " ] = toString ( current_BlockHeader . hash ) ;
blObj [ " blockHeader " ] = oBlockHeader ;
blObj [ " blockHeader " ] = oBlockHeader ;
vBiBlocks . push_back ( current_BlockHeader ) ;
// write uncle list
// compare blocks from state and from rlp
mArray aUncleList ; // as of now, our parent is always the genesis block, so we can not have uncles.
blObj [ " uncleHeaders " ] = aUncleList ;
//txs:
RLPStream txStream ;
RLPStream txStream ;
txStream . appendList ( txList . size ( ) ) ;
txStream . appendList ( txList . size ( ) ) ;
for ( unsigned i = 0 ; i < txList . size ( ) ; + + i )
for ( unsigned i = 0 ; i < txList . size ( ) ; + + i )
@ -223,13 +190,16 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
txStream . appendRaw ( txrlp . out ( ) ) ;
txStream . appendRaw ( txrlp . out ( ) ) ;
}
}
RLPStream rlpStream2 ;
RLPStream uncleStream ;
current_BlockHeader . streamRLP ( rlpStream2 , WithNonce ) ;
uncleStream . appendList ( vBiUncles . size ( ) ) ;
for ( unsigned i = 0 ; i < vBiUncles . size ( ) ; + + i )
{
RLPStream uncleRlp ;
vBiUncles [ i ] . streamRLP ( uncleRlp , WithNonce ) ;
uncleStream . appendRaw ( uncleRlp . out ( ) ) ;
}
RLPStream block2 ( 3 ) ;
RLPStream block2 = createFullBlockFromHeader ( current_BlockHeader , txStream . out ( ) , uncleStream . out ( ) ) ;
block2 . appendRaw ( rlpStream2 . out ( ) ) ;
block2 . appendRaw ( txStream . out ( ) ) ;
block2 . appendRaw ( RLPEmptyList ) ;
blObj [ " rlp " ] = " 0x " + toHex ( block2 . out ( ) ) ;
blObj [ " rlp " ] = " 0x " + toHex ( block2 . out ( ) ) ;
@ -240,13 +210,14 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
cnote < < " txs mismatch \n " ;
cnote < < " txs mismatch \n " ;
if ( sha3 ( RLP ( state . blockData ( ) ) [ 2 ] . data ( ) ) ! = sha3 ( RLP ( block2 . out ( ) ) [ 2 ] . data ( ) ) )
if ( sha3 ( RLP ( state . blockData ( ) ) [ 2 ] . data ( ) ) ! = sha3 ( RLP ( block2 . out ( ) ) [ 2 ] . data ( ) ) )
cnote < < " uncle list mismatch \n " ;
cnote < < " uncle list mismatch \n " < < RLP ( state . blockData ( ) ) [ 2 ] . data ( ) < < " \n " < < RLP ( block2 . out ( ) ) [ 2 ] . data ( ) ;
try
try
{
{
state . sync ( bc ) ;
state . sync ( bc ) ;
bc . import ( block2 . out ( ) , state . db ( ) ) ;
bc . import ( block2 . out ( ) , state . db ( ) ) ;
state . sync ( bc ) ;
state . sync ( bc ) ;
state . commit ( ) ;
}
}
// 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 ( . . . )
@ -392,12 +363,51 @@ void doBlockchainTests(json_spirit::mValue& _v, bool _fillin)
}
}
// check uncle list
// check uncle list
BOOST_CHECK_MESSAGE ( ( blObj [ " uncleList " ] . type ( ) = = json_spirit : : null_type ? 0 : blObj [ " uncleList " ] . get_array ( ) . size ( ) ) = = 0 , " Uncle list is not empty, but the genesis block can not have uncles " ) ;
// uncles from uncle list field
vector < BlockInfo > uBlHsFromField ;
if ( blObj [ " uncleHeaders " ] . type ( ) ! = json_spirit : : null_type )
{
for ( auto const & uBlHeaderObj : blObj [ " uncleHeaders " ] . get_array ( ) )
{
mObject uBlH = uBlHeaderObj . get_obj ( ) ;
cout < < " uBlH.size(): " < < uBlH . size ( ) < < endl ;
BOOST_REQUIRE ( uBlH . size ( ) = = 17 ) ;
bytes uncleRLP = createBlockRLPFromFields ( uBlH ) ;
const RLP c_uRLP ( uncleRLP ) ;
BlockInfo uncleBlockHeader ;
try
{
uncleBlockHeader . populateFromHeader ( c_uRLP , true ) ;
}
catch ( . . . )
{
BOOST_ERROR ( " invalid uncle header " ) ;
}
uBlHsFromField . push_back ( uncleBlockHeader ) ;
}
}
// uncles from block RLP
vector < BlockInfo > uBlHsFromRlp ;
for ( auto const & uRLP : root [ 2 ] )
{
BlockInfo uBl ;
uBl . populateFromHeader ( uRLP , true ) ;
uBlHsFromRlp . push_back ( uBl ) ;
}
BOOST_REQUIRE_EQUAL ( uBlHsFromField . size ( ) , uBlHsFromRlp . size ( ) ) ;
for ( size_t i = 0 ; i < uBlHsFromField . size ( ) ; + + i )
BOOST_CHECK_MESSAGE ( uBlHsFromField [ i ] = = uBlHsFromRlp [ i ] , " block header in rlp and in field do not match " ) ;
}
}
}
}
}
}
}
}
// helping functions
bytes createBlockRLPFromFields ( mObject & _tObj )
bytes createBlockRLPFromFields ( mObject & _tObj )
{
{
RLPStream rlpStream ;
RLPStream rlpStream ;
@ -529,31 +539,103 @@ void overwriteBlockHeader(BlockInfo& current_BlockHeader, mObject& blObj)
current_BlockHeader . populateFromHeader ( c_bRLP , false ) ;
current_BlockHeader . populateFromHeader ( c_bRLP , false ) ;
}
}
}
}
} } // Namespace Close
BlockInfo constructBlock ( mObject & _o )
{
BOOST_AUTO_TEST_SUITE ( BlockChainTests )
BlockInfo ret ;
try
{
// construct genesis block
const bytes c_blockRLP = createBlockRLPFromFields ( _o ) ;
const RLP c_bRLP ( c_blockRLP ) ;
ret . populateFromHeader ( c_bRLP , false ) ;
}
catch ( Exception const & _e )
{
cnote < < " block population did throw an exception: " < < diagnostic_information ( _e ) ;
BOOST_ERROR ( " Failed block population with Exception: " < < _e . what ( ) ) ;
}
catch ( std : : exception const & _e )
{
BOOST_ERROR ( " Failed block population with Exception: " < < _e . what ( ) ) ;
}
catch ( . . . )
{
BOOST_ERROR ( " block population did throw an unknown exception \n " ) ;
}
return ret ;
}
BOOST_AUTO_TEST_CASE ( bcBlockChainTest )
void updatePoW ( BlockInfo & _bi )
{
{
dev : : test : : executeTests ( " bcBlockChainTest " , " /BlockTests " , dev : : test : : doBlockchainTests ) ;
ProofOfWork pow ;
std : : pair < MineInfo , Ethash : : Proof > ret ;
while ( ! ProofOfWork : : verify ( _bi ) )
{
ret = pow . mine ( _bi , 10000 , true , true ) ; // tie(ret, blockFromFields.nonce)
Ethash : : assignResult ( ret . second , _bi ) ;
}
}
}
BOOST_AUTO_TEST_CASE ( bcValidBlockTest )
void writeBlockHeaderToJson ( mObject & _o , const BlockInfo & _bi )
{
{
dev : : test : : executeTests ( " bcValidBlockTest " , " /BlockTests " , dev : : test : : doBlockchainTests ) ;
_o [ " parentHash " ] = toString ( _bi . parentHash ) ;
_o [ " uncleHash " ] = toString ( _bi . sha3Uncles ) ;
_o [ " coinbase " ] = toString ( _bi . coinbaseAddress ) ;
_o [ " stateRoot " ] = toString ( _bi . stateRoot ) ;
_o [ " transactionsTrie " ] = toString ( _bi . transactionsRoot ) ;
_o [ " receiptTrie " ] = toString ( _bi . receiptsRoot ) ;
_o [ " bloom " ] = toString ( _bi . logBloom ) ;
_o [ " difficulty " ] = toString ( _bi . difficulty ) ;
_o [ " number " ] = toString ( _bi . number ) ;
_o [ " gasLimit " ] = toString ( _bi . gasLimit ) ;
_o [ " gasUsed " ] = toString ( _bi . gasUsed ) ;
_o [ " timestamp " ] = toString ( _bi . timestamp ) ;
_o [ " extraData " ] = " 0x " + toHex ( _bi . extraData ) ;
_o [ " mixHash " ] = toString ( _bi . mixHash ) ;
_o [ " seedHash " ] = toString ( _bi . seedHash ) ;
_o [ " nonce " ] = toString ( _bi . nonce ) ;
_o [ " hash " ] = toString ( _bi . hash ) ;
}
}
BOOST_AUTO_TEST_CASE ( bcInvalidHeaderTest )
RLPStream createFullBlockFromHeader ( const BlockInfo & _bi , const bytes & _txs , const bytes & _uncles )
{
{
dev : : test : : executeTests ( " bcInvalidHeaderTest " , " /BlockTests " , dev : : test : : doBlockchainTests ) ;
RLPStream rlpStream ;
_bi . streamRLP ( rlpStream , WithNonce ) ;
RLPStream ret ( 3 ) ;
ret . appendRaw ( rlpStream . out ( ) ) ;
ret . appendRaw ( _txs ) ;
ret . appendRaw ( _uncles ) ;
return ret ;
}
}
} } // Namespace Close
//BOOST_AUTO_TEST_CASE(bcUncleTest)
BOOST_AUTO_TEST_SUITE ( BlockChainTests )
//BOOST_AUTO_TEST_CASE(bcBlockChainTest)
//{
// dev::test::executeTests("bcBlockChainTest", "/BlockTests", dev::test::doBlockchainTests);
//}
//BOOST_AUTO_TEST_CASE(bcValidBlockTest)
//{
// dev::test::executeTests("bcValidBlockTest", "/BlockTests", dev::test::doBlockchainTests);
//}
//BOOST_AUTO_TEST_CASE(bcInvalidHeaderTest)
//{
//{
// dev::test::executeTests("bcUncleTest", "/BlockTests", dev::test::doBlockchainTests);
// dev::test::executeTests("bcInvalidHeader Test", "/BlockTests", dev::test::doBlockchainTests);
//}
//}
BOOST_AUTO_TEST_CASE ( bcUncleTest )
{
dev : : test : : executeTests ( " bcUncleTest " , " /BlockTests " , dev : : test : : doBlockchainTests ) ;
}
BOOST_AUTO_TEST_CASE ( userDefinedFileBc )
BOOST_AUTO_TEST_CASE ( userDefinedFileBc )
{
{
dev : : test : : userDefinedTest ( " --bctest " , dev : : test : : doBlockchainTests ) ;
dev : : test : : userDefinedTest ( " --bctest " , dev : : test : : doBlockchainTests ) ;