message: add a more complicated forking test case to chain_tester
  This is the test case that should have caused corruption in the old chain_controller/fork_db code.
diff: @@ -127,7 +127,46 @@ int main( int argc, char** argv ) {
  FC_ASSERT( b->producer == expected_producer,
  "expected block ${n} to be produced by ${expected_producer} but was instead produced by ${actual_producer}",
  ("n", b->block_num())("expected_producer", expected_producer.to_string())("actual_producer", b->producer.to_string()) );
  + c.produce_blocks(10);
  +
  + wlog( "push c1 blocks to c2" );
  + while( c2.control->head_block_num() < c.control->head_block_num() ) {
  + auto fb = c.control->fetch_block_by_number( c2.control->head_block_num()+1 );
  + c2.control->push_block( fb );
  + }
  + wlog( "end push c1 blocks to c2" );
  + // Now with four block producers active and two identical chains (for now),
  + // we can test out the case that would trigger the bug in the old fork db code:
  + fork_block_num = c.control->head_block_num();
  + wlog( "cam and dan go off on their own fork on c1 while sam and pam go off on their own fork on c2" );
  + wlog( "c1 blocks:" );
  + c.produce_blocks(12); // dan produces 12 blocks
  + c.produce_block( fc::milliseconds(config::block_interval_ms * 25) ); // cam skips over sam and pam's blocks
  + c.produce_blocks(23); // cam finishes the remaining 11 blocks then dan produces his 12 blocks
  + wlog( "c2 blocks:" );
  + c2.produce_block( fc::milliseconds(config::block_interval_ms * 25) ); // pam skips over dan and sam's blocks
  + c2.produce_blocks(11); // pam finishes the remaining 11 blocks
  + c2.produce_block( fc::milliseconds(config::block_interval_ms * 25) ); // sam skips over cam and dan's blocks
  + c2.produce_blocks(11); // sam finishes the remaining 11 blocks
  +
  + wlog( "now cam and dan rejoin sam and pam on c2" );
  + c2.produce_block( fc::milliseconds(config::block_interval_ms * 13) ); // cam skips over pam's blocks (this block triggers a block on this branch to become irreversible)
  + c2.produce_blocks(11); // cam produces the remaining 11 blocks
  + b = c2.produce_block(); // dan produces a block
  +
  + // a node on chain 1 now gets all but the last block from chain 2 which should cause a fork switch
  + wlog( "push c2 blocks (except for the last block by dan) to c1" );
  + for( uint32_t start = fork_block_num + 1, end = c2.control->head_block_num() - 1; start <= end; ++start ) {
  + auto fb = c2.control->fetch_block_by_number( start );
  + c.control->push_block( fb );
  + }
  + wlog( "end push c2 blocks to c1" );
  + wlog( "now push dan's block to c1 but first corrupt it so it is a bad block" );
  + auto bad_block = *b;
  + bad_block.producer = N(sam);
  + // bad_block.transaction_mroot = bad_block.action_mroot; // TODO/BUG: why did this not cause block rejection?
  + c.control->push_block( std::make_shared<signed_block>(bad_block) );
  } FC_CAPTURE_AND_RETHROW()
  } catch ( const fc::exception& e ) {
  