chain_controller.cpp 52.2 KB
Newer Older
N
Nathan Hourt 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright (c) 2017, Respective Authors.
 *
 * The MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
N
Nathan Hourt 已提交
24

25
#include <eos/chain/chain_controller.hpp>
N
Nathan Hourt 已提交
26 27 28 29
#include <eos/chain/exceptions.hpp>

#include <eos/chain/block_summary_object.hpp>
#include <eos/chain/global_property_object.hpp>
N
Nathan Hourt 已提交
30 31
#include <eos/chain/key_value_object.hpp>
#include <eos/chain/action_objects.hpp>
32
#include <eos/chain/generated_transaction_object.hpp>
N
Nathan Hourt 已提交
33 34
#include <eos/chain/transaction_object.hpp>
#include <eos/chain/producer_object.hpp>
35
#include <eos/chain/permission_link_object.hpp>
N
Nathan Hourt 已提交
36
#include <eos/chain/authority_checker.hpp>
N
Nathan Hourt 已提交
37

38 39
#include <eos/chain/wasm_interface.hpp>

40 41
#include <eos/types/native.hpp>
#include <eos/types/generated.hpp>
42
#include <eos/types/AbiSerializer.hpp>
43

44
#include <eos/utilities/rand.hpp>
45

N
Nathan Hourt 已提交
46
#include <fc/smart_ref_impl.hpp>
N
Nathan Hourt 已提交
47 48 49
#include <fc/uint128.hpp>
#include <fc/crypto/digest.hpp>

50
#include <boost/range/algorithm/copy.hpp>
N
Nathan Hourt 已提交
51
#include <boost/range/algorithm_ext/is_sorted.hpp>
52
#include <boost/range/adaptor/transformed.hpp>
N
Nathan Hourt 已提交
53
#include <boost/range/adaptor/map.hpp>
N
Nathan Hourt 已提交
54 55 56 57 58

#include <fstream>
#include <functional>
#include <iostream>

D
Daniel Larimer 已提交
59
//#include <Wren++.h>
60

N
Nathan Hourt 已提交
61 62
namespace eos { namespace chain {

63

64
bool chain_controller::is_known_block(const block_id_type& id)const
N
Nathan Hourt 已提交
65
{
66
   return _fork_db.is_known_block(id) || _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
67 68 69 70 71 72
}
/**
 * Only return true *if* the transaction has not expired or been invalidated. If this
 * method is called with a VERY old transaction we will return false, they should
 * query things by blocks if they are that old.
 */
73
bool chain_controller::is_known_transaction(const transaction_id_type& id)const
N
Nathan Hourt 已提交
74
{
75
   const auto& trx_idx = _db.get_index<transaction_multi_index, by_trx_id>();
N
Nathan Hourt 已提交
76 77 78
   return trx_idx.find( id ) != trx_idx.end();
}

79
block_id_type chain_controller::get_block_id_for_num(uint32_t block_num)const
N
Nathan Hourt 已提交
80
{ try {
81 82
   if (const auto& block = fetch_block_by_number(block_num))
      return block->id();
N
Nathan Hourt 已提交
83

84 85 86
   FC_THROW_EXCEPTION(unknown_block_exception, "Could not find block");
} FC_CAPTURE_AND_RETHROW((block_num)) }

87
optional<signed_block> chain_controller::fetch_block_by_id(const block_id_type& id)const
N
Nathan Hourt 已提交
88
{
89 90
   auto b = _fork_db.fetch_block(id);
   if(b) return b->data;
91
   return _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
92 93
}

94
optional<signed_block> chain_controller::fetch_block_by_number(uint32_t num)const
N
Nathan Hourt 已提交
95
{
96
   if (const auto& block = _block_log.read_block_by_num(num))
97 98
      return *block;

N
Nathan Hourt 已提交
99
   // Not in _block_log, so it must be since the last irreversible block. Grab it from _fork_db instead
100 101 102 103 104 105 106 107
   if (num <= head_block_num()) {
      auto block = _fork_db.head();
      while (block && block->num > num)
         block = block->prev.lock();
      if (block && block->num == num)
         return block->data;
   }

N
Nathan Hourt 已提交
108 109 110
   return optional<signed_block>();
}

111
const SignedTransaction& chain_controller::get_recent_transaction(const transaction_id_type& trx_id) const
N
Nathan Hourt 已提交
112
{
113
   auto& index = _db.get_index<transaction_multi_index, by_trx_id>();
N
Nathan Hourt 已提交
114 115 116 117 118
   auto itr = index.find(trx_id);
   FC_ASSERT(itr != index.end());
   return itr->trx;
}

119
std::vector<block_id_type> chain_controller::get_block_ids_on_fork(block_id_type head_of_fork) const
N
Nathan Hourt 已提交
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
{
  pair<fork_database::branch_type, fork_database::branch_type> branches = _fork_db.fetch_branch_from(head_block_id(), head_of_fork);
  if( !((branches.first.back()->previous_id() == branches.second.back()->previous_id())) )
  {
     edump( (head_of_fork)
            (head_block_id())
            (branches.first.size())
            (branches.second.size()) );
     assert(branches.first.back()->previous_id() == branches.second.back()->previous_id());
  }
  std::vector<block_id_type> result;
  for (const item_ptr& fork_block : branches.second)
    result.emplace_back(fork_block->id);
  result.emplace_back(branches.first.back()->previous_id());
  return result;
}

/**
 * Push block "may fail" in which case every partial change is unwound.  After
 * push block is successful the block is appended to the chain database on disk.
 *
 * @return true if we switched forks as a result of this push.
 */
143
bool chain_controller::push_block(const signed_block& new_block, uint32_t skip)
D
Daniel Larimer 已提交
144 145 146
{ try {
   return with_skip_flags( skip, [&](){ 
      return without_pending_transactions( [&]() {
147
         return _db.with_write_lock( [&]() {
148 149
            return _push_block(new_block);
         } );
N
Nathan Hourt 已提交
150 151
      });
   });
152
} FC_CAPTURE_AND_RETHROW((new_block)) }
N
Nathan Hourt 已提交
153

154
bool chain_controller::_push_block(const signed_block& new_block)
N
Nathan Hourt 已提交
155
{ try {
N
Nathan Hourt 已提交
156
   uint32_t skip = _skip_flags;
157
   if (!(skip&skip_fork_db)) {
N
Nathan Hourt 已提交
158
      /// TODO: if the block is greater than the head block and before the next maintenance interval
N
Nathan Hourt 已提交
159 160 161 162
      // verify that the block signer is in the current set of active producers.

      shared_ptr<fork_item> new_head = _fork_db.push_block(new_block);
      //If the head block from the longest chain does not build off of the current head, we need to switch forks.
163
      if (new_head->data.previous != head_block_id()) {
N
Nathan Hourt 已提交
164 165
         //If the newly pushed block is the same height as head, we get head back in new_head
         //Only switch forks if new_head is actually higher than head
166 167
         if (new_head->data.block_num() > head_block_num()) {
            wlog("Switching to fork: ${id}", ("id",new_head->data.id()));
N
Nathan Hourt 已提交
168 169 170
            auto branches = _fork_db.fetch_branch_from(new_head->data.id(), head_block_id());

            // pop blocks until we hit the forked block
171
            while (head_block_id() != branches.second.back()->data.previous)
N
Nathan Hourt 已提交
172 173 174
               pop_block();

            // push all blocks on the new fork
175 176
            for (auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
                ilog("pushing blocks from fork ${n} ${id}", ("n",(*ritr)->data.block_num())("id",(*ritr)->data.id()));
N
Nathan Hourt 已提交
177 178
                optional<fc::exception> except;
                try {
179
                   auto session = _db.start_undo_session(true);
180
                   apply_block((*ritr)->data, skip);
N
Nathan Hourt 已提交
181 182
                   session.push();
                }
183 184 185
                catch (const fc::exception& e) { except = e; }
                if (except) {
                   wlog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));
N
Nathan Hourt 已提交
186
                   // remove the rest of branches.first from the fork_db, those blocks are invalid
187 188
                   while (ritr != branches.first.rend()) {
                      _fork_db.remove((*ritr)->data.id());
N
Nathan Hourt 已提交
189 190
                      ++ritr;
                   }
191
                   _fork_db.set_head(branches.second.front());
N
Nathan Hourt 已提交
192 193

                   // pop all blocks from the bad fork
194
                   while (head_block_id() != branches.second.back()->data.previous)
N
Nathan Hourt 已提交
195 196 197
                      pop_block();

                   // restore all blocks from the good fork
198
                   for (auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr) {
199
                      auto session = _db.start_undo_session(true);
200
                      apply_block((*ritr)->data, skip);
N
Nathan Hourt 已提交
201 202 203 204 205 206 207 208 209 210 211 212
                      session.push();
                   }
                   throw *except;
                }
            }
            return true;
         }
         else return false;
      }
   }

   try {
213
      auto session = _db.start_undo_session(true);
N
Nathan Hourt 已提交
214 215 216 217 218 219 220 221 222
      apply_block(new_block, skip);
      session.push();
   } catch ( const fc::exception& e ) {
      elog("Failed to push new block:\n${e}", ("e", e.to_detail_string()));
      _fork_db.remove(new_block.id());
      throw;
   }

   return false;
223
} FC_CAPTURE_AND_RETHROW((new_block)) }
N
Nathan Hourt 已提交
224 225 226 227 228 229 230 231 232 233

/**
 * Attempts to push the transaction into the pending queue
 *
 * When called to push a locally generated transaction, set the skip_block_size_check bit on the skip argument. This
 * will allow the transaction to be pushed even if it causes the pending block size to exceed the maximum block size.
 * Although the transaction will probably not propagate further now, as the peers are likely to have their pending
 * queues full as well, it will be kept in the queue to be propagated later when a new block flushes out the pending
 * queues.
 */
234
ProcessedTransaction chain_controller::push_transaction(const SignedTransaction& trx, uint32_t skip)
N
Nathan Hourt 已提交
235
{ try {
236 237 238
   return with_skip_flags(skip, [&]() {
      return _db.with_write_lock([&]() {
         return _push_transaction(trx);
D
Daniel Larimer 已提交
239
      });
N
Nathan Hourt 已提交
240 241
   });
} FC_CAPTURE_AND_RETHROW((trx)) }
N
Nathan Hourt 已提交
242

243
ProcessedTransaction chain_controller::_push_transaction(const SignedTransaction& trx) {
244 245
   // If this is the first transaction pushed after applying a block, start a new undo session.
   // This allows us to quickly rewind to the clean state of the head block, in case a new block arrives.
246
   if (!_pending_tx_session.valid())
247
      _pending_tx_session = _db.start_undo_session(true);
248

249
   auto temp_session = _db.start_undo_session(true);
250
   validate_referenced_accounts(trx);
N
Nathan Hourt 已提交
251
   check_transaction_authorization(trx);
252
   auto pt = _apply_transaction(trx);
D
Daniel Larimer 已提交
253
   _pending_transactions.push_back(trx);
N
Nathan Hourt 已提交
254 255 256 257 258 259

   // notify_changed_objects();
   // The transaction applied successfully. Merge its changes into the pending block session.
   temp_session.squash();

   // notify anyone listening to pending transactions
260 261 262
   on_pending_transaction(trx); /// TODO move this to apply...

   return pt;
N
Nathan Hourt 已提交
263 264
}

265
signed_block chain_controller::generate_block(
N
Nathan Hourt 已提交
266
   fc::time_point_sec when,
N
Nathan Hourt 已提交
267
   const AccountName& producer,
N
Nathan Hourt 已提交
268
   const fc::ecc::private_key& block_signing_private_key,
269
   block_schedule::factory scheduler, /* = block_schedule::by_threading_conflits */
N
Nathan Hourt 已提交
270 271 272
   uint32_t skip /* = 0 */
   )
{ try {
N
Nathan Hourt 已提交
273 274
   return with_skip_flags( skip, [&](){
      auto b = _db.with_write_lock( [&](){
275
         return _generate_block( when, producer, block_signing_private_key, scheduler );
D
Daniel Larimer 已提交
276
      });
N
Nathan Hourt 已提交
277 278 279
      push_block(b, skip);
      return b;
   });
D
Daniel Larimer 已提交
280
} FC_CAPTURE_AND_RETHROW( (when) ) }
N
Nathan Hourt 已提交
281

282
signed_block chain_controller::_generate_block(
N
Nathan Hourt 已提交
283
   fc::time_point_sec when,
N
Nathan Hourt 已提交
284
   const AccountName& producer,
285 286
   const fc::ecc::private_key& block_signing_private_key,
   block_schedule::factory scheduler
N
Nathan Hourt 已提交
287 288 289
   )
{
   try {
N
Nathan Hourt 已提交
290
   uint32_t skip = _skip_flags;
N
Nathan Hourt 已提交
291 292
   uint32_t slot_num = get_slot_at_time( when );
   FC_ASSERT( slot_num > 0 );
N
Nathan Hourt 已提交
293 294
   AccountName scheduled_producer = get_scheduled_producer( slot_num );
   FC_ASSERT( scheduled_producer == producer );
N
Nathan Hourt 已提交
295

N
Nathan Hourt 已提交
296
   const auto& producer_obj = get_producer(scheduled_producer);
N
Nathan Hourt 已提交
297 298 299 300

   if( !(skip & skip_producer_signature) )
      FC_ASSERT( producer_obj.signing_key == block_signing_private_key.get_public_key() );

301 302 303 304
  
   auto& generated = _db.get_index<generated_transaction_multi_index, generated_transaction_object::by_trx_id>();

   vector<pending_transaction> pending;
B
Bart Wyatt 已提交
305
   std::set<transaction_id_type> invalid_pending;
306
   pending.reserve(generated.size() + _pending_transactions.size());
B
Bart Wyatt 已提交
307 308
   for (const auto& gt: generated) {
      pending.emplace_back(std::reference_wrapper<const GeneratedTransaction> {gt.trx});
309 310
   }
   
B
Bart Wyatt 已提交
311 312
   for(const auto& st: _pending_transactions) {
      pending.emplace_back(std::reference_wrapper<const SignedTransaction> {st});
313 314
   }

315
   auto schedule = scheduler(pending, get_global_properties());
N
Nathan Hourt 已提交
316 317 318 319 320 321 322 323 324 325 326 327 328

   //
   // The following code throws away existing pending_tx_session and
   // rebuilds it by re-applying pending transactions.
   //
   // This rebuild is necessary because pending transactions' validity
   // and semantics may have changed since they were received, because
   // time-based semantics are evaluated based on the current block
   // time.  These changes can only be reflected in the database when
   // the value of the "when" variable is known, which means we need to
   // re-apply pending transactions in this method.
   //
   _pending_tx_session.reset();
329
   _pending_tx_session = _db.start_undo_session(true);
N
Nathan Hourt 已提交
330

331 332 333 334 335 336 337 338 339 340 341 342
   signed_block pending_block;
   pending_block.cycles.reserve(schedule.cycles.size());

   size_t invalid_transaction_count = 0;
   size_t valid_transaction_count = 0;

   for (const auto &c : schedule.cycles) {
     cycle block_cycle;
     block_cycle.reserve(c.size());

     for (const auto &t : c) {
       thread block_thread;
343 344 345 346 347 348
       block_thread.user_input.reserve(t.transactions.size());
       block_thread.generated_input.reserve(t.transactions.size());
       for (const auto &trx : t.transactions) {
          try
          {
             auto temp_session = _db.start_undo_session(true);
B
Bart Wyatt 已提交
349 350
             if (trx.contains<std::reference_wrapper<const SignedTransaction>>()) {
                const auto& t = trx.get<std::reference_wrapper<const SignedTransaction>>().get();
B
Bart Wyatt 已提交
351
                validate_referenced_accounts(t);
352 353
                check_transaction_authorization(t);
                auto processed = _apply_transaction(t);
354
                block_thread.user_input.emplace_back(processed);
B
Bart Wyatt 已提交
355 356
             } else if (trx.contains<std::reference_wrapper<const GeneratedTransaction>>()) {
                // auto processed = _apply_transaction(trx.get<std::reference_wrapper<const GeneratedTransaction>>().get());
357 358 359 360 361 362 363 364 365 366 367
                // block_thread.generated_input.emplace_back(processed);
             } else {
                FC_THROW_EXCEPTION(tx_scheduling_exception, "Unknown transaction type in block_schedule");
             }
             
             temp_session.squash();
             valid_transaction_count++;
          }
          catch ( const fc::exception& e )
          {
             // Do nothing, transaction will not be re-applied
B
Bart Wyatt 已提交
368
             elog( "Transaction was not processed while generating block due to ${e}", ("e", e) );
B
Bart Wyatt 已提交
369
             if (trx.contains<std::reference_wrapper<const SignedTransaction>>()) {
B
Bart Wyatt 已提交
370 371 372
                const auto& t = trx.get<std::reference_wrapper<const SignedTransaction>>().get();
                wlog( "The transaction was ${t}", ("t", t );
                invalid_pending.emplace(t.id());
B
Bart Wyatt 已提交
373 374
             } else if (trx.contains<std::reference_wrapper<const GeneratedTransaction>>()) {
                wlog( "The transaction was ${t}", ("t", trx.get<std::reference_wrapper<const GeneratedTransaction>>().get()) );
375 376 377
             } 
             invalid_transaction_count++;
          }
378 379 380
       }

       if (!(block_thread.generated_input.empty() && block_thread.user_input.empty())) {
381 382
          block_thread.generated_input.shrink_to_fit();
          block_thread.user_input.shrink_to_fit();
383 384 385 386 387 388 389
          block_cycle.emplace_back(std::move(block_thread));
       }
     }

     if (!block_cycle.empty()) {
        pending_block.cycles.emplace_back(std::move(block_cycle));
     }
N
Nathan Hourt 已提交
390
   }
391 392
   
   size_t postponed_tx_count = _pending_transactions.size() - valid_transaction_count - invalid_transaction_count;
N
Nathan Hourt 已提交
393 394 395 396 397
   if( postponed_tx_count > 0 )
   {
      wlog( "Postponed ${n} transactions due to block size limit", ("n", postponed_tx_count) );
   }

398 399 400
   if( invalid_transaction_count > 0 )
   {
      wlog( "Postponed ${n} transactions errors when processing", ("n", invalid_transaction_count) );
B
Bart Wyatt 已提交
401 402 403 404 405 406 407 408 409 410 411 412

      // remove pending transactions determined to be bad during scheduling
      if (invalid_pending.size() > 0) {
         for (auto itr = _pending_transactions.begin(); itr != _pending_transactions.end(); ) {
            auto& tx = *itr;
            if (invalid_pending.find(tx.id()) != invalid_pending.end()) {
               itr = _pending_transactions.erase(itr);
            } else {
               ++itr;
            }
         }
      }
413 414
   }

N
Nathan Hourt 已提交
415 416 417 418
   _pending_tx_session.reset();

   // We have temporarily broken the invariant that
   // _pending_tx_session is the result of applying _pending_tx, as
D
Daniel Larimer 已提交
419
   // _pending_transactions now consists of the set of postponed transactions.
N
Nathan Hourt 已提交
420 421 422 423 424 425
   // However, the push_block() call below will re-create the
   // _pending_tx_session.

   pending_block.previous = head_block_id();
   pending_block.timestamp = when;
   pending_block.transaction_merkle_root = pending_block.calculate_merkle_root();
D
Daniel Larimer 已提交
426

427
   pending_block.producer = producer_obj.owner;
N
Nathan Hourt 已提交
428

429 430 431 432 433 434
   // If this block is last in a round, calculate the schedule for the new round
   if (pending_block.block_num() % config::BlocksPerRound == 0) {
      auto new_schedule = _admin->get_next_round(_db);
      pending_block.producer_changes = get_global_properties().active_producers - new_schedule;
   }

N
Nathan Hourt 已提交
435 436 437 438
   if( !(skip & skip_producer_signature) )
      pending_block.sign( block_signing_private_key );

   // TODO:  Move this to _push_block() so session is restored.
439
   /*
N
Nathan Hourt 已提交
440 441 442 443
   if( !(skip & skip_block_size_check) )
   {
      FC_ASSERT( fc::raw::pack_size(pending_block) <= get_global_properties().parameters.maximum_block_size );
   }
444
   */
N
Nathan Hourt 已提交
445

446
   // push_block( pending_block, skip );
N
Nathan Hourt 已提交
447 448

   return pending_block;
N
Nathan Hourt 已提交
449
} FC_CAPTURE_AND_RETHROW( (producer) ) }
N
Nathan Hourt 已提交
450 451

/**
N
Nathan Hourt 已提交
452
 * Removes the most recent block from the database and undoes any changes it made.
N
Nathan Hourt 已提交
453
 */
454
void chain_controller::pop_block()
N
Nathan Hourt 已提交
455 456 457 458 459 460 461
{ try {
   _pending_tx_session.reset();
   auto head_id = head_block_id();
   optional<signed_block> head_block = fetch_block_by_id( head_id );
   EOS_ASSERT( head_block.valid(), pop_empty_chain, "there are no blocks to pop" );

   _fork_db.pop_block();
462
   _db.undo();
N
Nathan Hourt 已提交
463 464
} FC_CAPTURE_AND_RETHROW() }

465
void chain_controller::clear_pending()
N
Nathan Hourt 已提交
466
{ try {
D
Daniel Larimer 已提交
467
   _pending_transactions.clear();
N
Nathan Hourt 已提交
468 469 470 471 472
   _pending_tx_session.reset();
} FC_CAPTURE_AND_RETHROW() }

//////////////////// private methods ////////////////////

473
void chain_controller::apply_block(const signed_block& next_block, uint32_t skip)
N
Nathan Hourt 已提交
474 475
{
   auto block_num = next_block.block_num();
476 477 478 479 480
   if (_checkpoints.size() && _checkpoints.rbegin()->second != block_id_type()) {
      auto itr = _checkpoints.find(block_num);
      if (itr != _checkpoints.end())
         FC_ASSERT(next_block.id() == itr->second,
                   "Block did not match checkpoint", ("checkpoint",*itr)("block_id",next_block.id()));
N
Nathan Hourt 已提交
481

482
      if (_checkpoints.rbegin()->first >= block_num)
N
Nathan Hourt 已提交
483 484
         skip = ~0;// WE CAN SKIP ALMOST EVERYTHING
   }
N
Nathan Hourt 已提交
485 486 487 488 489 490

   with_applying_block([&] {
      with_skip_flags(skip, [&] {
         _apply_block(next_block);
      });
   });
N
Nathan Hourt 已提交
491 492
}

493
void chain_controller::_apply_block(const signed_block& next_block)
N
Nathan Hourt 已提交
494 495
{ try {
   uint32_t next_block_num = next_block.block_num();
N
Nathan Hourt 已提交
496
   uint32_t skip = _skip_flags;
N
Nathan Hourt 已提交
497

498 499 500
   FC_ASSERT((skip & skip_merkle_check) || next_block.transaction_merkle_root == next_block.calculate_merkle_root(),
             "", ("next_block.transaction_merkle_root", next_block.transaction_merkle_root)
             ("calc",next_block.calculate_merkle_root())("next_block",next_block)("id",next_block.id()));
N
Nathan Hourt 已提交
501 502

   const producer_object& signing_producer = validate_block_header(skip, next_block);
N
Nathan Hourt 已提交
503 504 505
   
   for (const auto& cycle : next_block.cycles)
      for (const auto& thread : cycle)
506 507
         for (const auto& trx : thread.user_input) {
            validate_referenced_accounts(trx);
508 509 510
            // Check authorization, and allow irrelevant signatures.
            // If the block producer let it slide, we'll roll with it.
            check_transaction_authorization(trx, true);
511
         }
N
Nathan Hourt 已提交
512

N
Nathan Hourt 已提交
513 514 515 516 517 518
   /* We do not need to push the undo state for each transaction
    * because they either all apply and are valid or the
    * entire block fails to apply.  We only need an "undo" state
    * for transactions when validating broadcast transactions or
    * when building a block.
    */
519 520 521
   for (const auto& cycle : next_block.cycles) {
      for (const auto& thread : cycle) {
         for(const auto& trx : thread.generated_input ) {
N
Nathan Hourt 已提交
522
         }
523
         for(const auto& trx : thread.user_input ) {
524
            _apply_transaction(trx);
525 526 527
         }
      }
   }
N
Nathan Hourt 已提交
528

529
   update_global_properties(next_block);
N
Nathan Hourt 已提交
530 531 532 533 534 535 536 537
   update_global_dynamic_data(next_block);
   update_signing_producer(signing_producer, next_block);
   update_last_irreversible_block();

   create_block_summary(next_block);
   clear_expired_transactions();

   // notify observers that the block has been applied
538
   // TODO: do this outside the write lock...? 
N
Nathan Hourt 已提交
539 540 541 542
   applied_block( next_block ); //emit

} FC_CAPTURE_AND_RETHROW( (next_block.block_num()) )  }

543
void chain_controller::check_transaction_authorization(const SignedTransaction& trx, bool allow_unused_signatures)const {
N
Nathan Hourt 已提交
544 545 546 547 548
   if ((_skip_flags & skip_transaction_signatures) && (_skip_flags & skip_authority_check)) {
      ilog("Skipping auth and sigs checks");
      return;
   }

549

N
Nathan Hourt 已提交
550 551 552 553 554 555 556
   auto getPermission = [&db=_db](const types::AccountPermission& permission) {
      auto key = boost::make_tuple(permission.account, permission.permission);
      return db.get<permission_object, by_owner>(key);
   };
   auto getAuthority = [&getPermission](const types::AccountPermission& permission) {
      return getPermission(permission).auth;
   };
557
   auto depthLimit = get_global_properties().configuration.authDepthLimit;
N
Nathan Hourt 已提交
558
#warning TODO: Use a real chain_id here (where is this stored? Do we still need it?)
559
   auto checker = MakeAuthorityChecker(std::move(getAuthority), depthLimit, trx.get_signature_keys(chain_id_type{}));
N
Nathan Hourt 已提交
560 561 562 563 564 565 566 567

   for (const auto& message : trx.messages)
      for (const auto& declaredAuthority : message.authorization) {
         const auto& minimumPermission = lookup_minimum_permission(declaredAuthority.account,
                                                                   message.code, message.type);
         if ((_skip_flags & skip_authority_check) == false) {
            const auto& index = _db.get_index<permission_index>().indices();
            EOS_ASSERT(getPermission(declaredAuthority).satisfies(minimumPermission, index), tx_irrelevant_auth,
N
Nathan Hourt 已提交
568 569
                       "Message declares irrelevant authority '${auth}'; minimum authority is ${min}",
                       ("auth", declaredAuthority)("min", minimumPermission.name));
N
Nathan Hourt 已提交
570 571 572 573 574 575 576
         }
         if ((_skip_flags & skip_transaction_signatures) == false) {
            EOS_ASSERT(checker.satisfied(declaredAuthority), tx_missing_sigs,
                       "Transaction declares authority '${auth}', but does not have signatures for it.",
                       ("auth", declaredAuthority));
         }
      }
N
Nathan Hourt 已提交
577

578
   if (!allow_unused_signatures && (_skip_flags & skip_transaction_signatures) == false)
579 580
      EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
                 "Transaction bears irrelevant signatures from these keys: ${keys}", ("keys", checker.unused_keys()));
N
Nathan Hourt 已提交
581 582
}

583
ProcessedTransaction chain_controller::apply_transaction(const SignedTransaction& trx, uint32_t skip)
N
Nathan Hourt 已提交
584
{
585
   return with_skip_flags( skip, [&]() { return _apply_transaction(trx); });
N
Nathan Hourt 已提交
586 587
}

588
void chain_controller::validate_transaction(const SignedTransaction& trx)const {
589
try {
590
   EOS_ASSERT(trx.messages.size() > 0, transaction_exception, "A transaction must have at least one message");
N
Nathan Hourt 已提交
591

592 593
   validate_scope(trx);
   validate_expiration(trx);
594 595
   validate_uniqueness(trx);
   validate_tapos(trx);
596

597
} FC_CAPTURE_AND_RETHROW( (trx) ) }
598

599 600 601 602 603 604
void chain_controller::validate_scope( const SignedTransaction& trx )const {
   EOS_ASSERT(trx.scope.size() > 0, transaction_exception, "No scope specified by transaction" );
   for( uint32_t i = 1; i < trx.scope.size(); ++i )
      EOS_ASSERT( trx.scope[i-1] < trx.scope[i], transaction_exception, "Scopes must be sorted and unique" );
}

N
Nathan Hourt 已提交
605 606 607 608
const permission_object& chain_controller::lookup_minimum_permission(types::AccountName authorizer_account,
                                                                    types::AccountName code_account,
                                                                    types::FuncName type) const {
   try {
609 610 611 612 613 614 615 616 617 618 619 620 621 622
      // First look up a specific link for this message type
      auto key = boost::make_tuple(authorizer_account, code_account, type);
      auto link = _db.find<permission_link_object, by_message_type>(key);
      // If no specific link found, check for a contract-wide default
      if (link == nullptr) {
         get<2>(key) = "";
         link = _db.find<permission_link_object, by_message_type>(key);
      }

      // If no specific or default link found, use active permission
      auto permissionKey = boost::make_tuple<AccountName, PermissionName>(authorizer_account, "active");
      if (link != nullptr)
         get<1>(permissionKey) = link->required_permission;
      return _db.get<permission_object, by_owner>(permissionKey);
N
Nathan Hourt 已提交
623 624 625
   } FC_CAPTURE_AND_RETHROW((authorizer_account)(code_account)(type))
}

626
void chain_controller::validate_uniqueness( const SignedTransaction& trx )const {
N
Nathan Hourt 已提交
627
   if( !should_check_for_duplicate_transactions() ) return;
N
Nathan Hourt 已提交
628

N
Nathan Hourt 已提交
629
   auto transaction = _db.find<transaction_object, by_trx_id>(trx.id());
630
   EOS_ASSERT(transaction == nullptr, tx_duplicate, "Transaction is not unique");
631
}
632

633
void chain_controller::validate_tapos(const SignedTransaction& trx)const {
N
Nathan Hourt 已提交
634
   if (!should_check_tapos()) return;
635

636
   const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.refBlockNum);
637 638

   //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
N
Nathan Hourt 已提交
639 640 641 642
   EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), transaction_exception,
              "Transaction's reference block did not match. Is this transaction from a different fork?",
              ("tapos_summary", tapos_block_summary));
}
643

644
void chain_controller::validate_referenced_accounts(const SignedTransaction& trx)const {
N
Nathan Hourt 已提交
645 646 647
   for (const auto& scope : trx.scope)
      require_account(scope);
   for (const auto& msg : trx.messages) {
648
      require_account(msg.code);
N
Nathan Hourt 已提交
649 650
      for (const auto& auth : msg.authorization)
         require_account(auth.account);
651 652
   }
}
D
Daniel Larimer 已提交
653

654
void chain_controller::validate_expiration(const SignedTransaction& trx) const
655 656
{ try {
   fc::time_point_sec now = head_block_time();
657
   const BlockchainConfiguration& chain_configuration = get_global_properties().configuration;
658

659
   EOS_ASSERT(trx.expiration <= now + int32_t(chain_configuration.maxTrxLifetime),
660 661
              transaction_exception, "Transaction expiration is too far in the future",
              ("trx.expiration",trx.expiration)("now",now)
662
              ("max_til_exp",chain_configuration.maxTrxLifetime));
663 664 665
   EOS_ASSERT(now <= trx.expiration, transaction_exception, "Transaction is expired",
              ("now",now)("trx.exp",trx.expiration));
} FC_CAPTURE_AND_RETHROW((trx)) }
666

667

N
Nathan Hourt 已提交
668
void chain_controller::process_message(const ProcessedTransaction& trx, AccountName code,
669
                                       const Message& message, MessageOutput& output, apply_context* parent_context) {
670
   apply_context apply_ctx(*this, _db, trx, message, code);
N
Nathan Hourt 已提交
671 672
   apply_message(apply_ctx);

673 674 675
   output.notify.reserve( apply_ctx.notified.size() );

   for( uint32_t i = 0; i < apply_ctx.notified.size(); ++i ) {
N
Nathan Hourt 已提交
676
      try {
677 678
         auto notify_code = apply_ctx.notified[i];
         output.notify.push_back( {notify_code} );
679
         process_message(trx, notify_code, message, output.notify.back().output, &apply_ctx);
680 681 682 683 684 685 686 687 688 689
      } FC_CAPTURE_AND_RETHROW((apply_ctx.notified[i]))
   }

   for( const auto& generated : apply_ctx.sync_transactions ) {
      try {
         output.sync_transactions.emplace_back( process_transaction( generated ) );
      } FC_CAPTURE_AND_RETHROW((generated))
   }

   for( auto& asynctrx : apply_ctx.async_transactions ) {
690
     output.async_transactions.emplace_back( std::move( asynctrx ) );
N
Nathan Hourt 已提交
691
   }
692 693 694 695 696 697 698 699 700 701 702 703

   // propagate used_authorizations up the context chain
   if (parent_context != nullptr)
      for (int i = 0; i < apply_ctx.used_authorizations.size(); ++i)
         if (apply_ctx.used_authorizations[i])
            parent_context->used_authorizations[i] = true;

   // process_message recurses for each notified account, but we only want to run this check at the top level
   if (parent_context == nullptr && (_skip_flags & skip_authority_check) == false)
      EOS_ASSERT(apply_ctx.all_authorizations_used(), tx_irrelevant_auth,
                 "Message declared authorities it did not need: ${unused}",
                 ("unused", apply_ctx.unused_authorizations())("message", message));
N
Nathan Hourt 已提交
704
}
705

706
void chain_controller::apply_message(apply_context& context)
707
{ try {
D
Daniel Larimer 已提交
708 709
    /// context.code => the execution namespace
    /// message.code / message.type => Event
710
    const auto& m = context.msg;
D
Daniel Larimer 已提交
711
    auto contract_handlers_itr = apply_handlers.find(context.code);
712 713 714
    if (contract_handlers_itr != apply_handlers.end()) {
       auto message_handler_itr = contract_handlers_itr->second.find({m.code, m.type});
       if (message_handler_itr != contract_handlers_itr->second.end()) {
N
Nathan Hourt 已提交
715
          message_handler_itr->second(context);
716 717 718
          return;
       }
    }
D
Daniel Larimer 已提交
719
    const auto& recipient = _db.get<account_object,by_name>(context.code);
720
    if (recipient.code.size()) {
721
       //idump((context.code)(context.msg.type));
722
       wasm_interface::get().apply(context);
723
    }
724

N
Nathan Hourt 已提交
725
} FC_CAPTURE_AND_RETHROW((context.msg)) }
N
Nathan Hourt 已提交
726

727
ProcessedTransaction chain_controller::_apply_transaction(const SignedTransaction& trx)
728
{ try {
729
   validate_transaction(trx);
730

N
Nathan Hourt 已提交
731
   //Insert transaction into unique transactions database.
N
Nathan Hourt 已提交
732
   if (should_check_for_duplicate_transactions())
N
Nathan Hourt 已提交
733
   {
734
      _db.create<transaction_object>([&](transaction_object& transaction) {
735
         transaction.trx_id = trx.id(); /// TODO: consider caching ID
N
Nathan Hourt 已提交
736 737 738
         transaction.trx = trx;
      });
   }
739 740 741

   return process_transaction( trx );

N
Nathan Hourt 已提交
742
} FC_CAPTURE_AND_RETHROW((trx)) }
N
Nathan Hourt 已提交
743

744 745 746 747 748 749 750 751 752 753

/**
 *  @pre the transaction is assumed valid and all signatures / duplicate checks have bee performed
 */
ProcessedTransaction chain_controller::process_transaction( const SignedTransaction& trx ) 
{ try {
   ProcessedTransaction ptrx( trx );
   ptrx.output.resize( trx.messages.size() );

   for( uint32_t i = 0; i < ptrx.messages.size(); ++i ) {
754
      process_message(ptrx, ptrx.messages[i].code, ptrx.messages[i], ptrx.output[i] );
755 756 757 758 759 760
   }

   return ptrx;
} FC_CAPTURE_AND_RETHROW( (trx) ) }


N
Nathan Hourt 已提交
761 762 763 764
void chain_controller::require_account(const types::AccountName& name) const {
   auto account = _db.find<account_object, by_name>(name);
   FC_ASSERT(account != nullptr, "Account not found: ${name}", ("name", name));
}
N
Nathan Hourt 已提交
765

766
const producer_object& chain_controller::validate_block_header(uint32_t skip, const signed_block& next_block)const {
767 768 769 770
   EOS_ASSERT(head_block_id() == next_block.previous, block_validate_exception, "",
              ("head_block_id",head_block_id())("next.prev",next_block.previous));
   EOS_ASSERT(head_block_time() < next_block.timestamp, block_validate_exception, "",
              ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()));
N
Nathan Hourt 已提交
771
   if (next_block.block_num() % config::BlocksPerRound != 0) {
772 773
      EOS_ASSERT(next_block.producer_changes.empty(), block_validate_exception,
                 "Producer changes may only occur at the end of a round.");
N
Nathan Hourt 已提交
774 775 776 777 778 779 780
   } else {
      using boost::is_sorted;
      using namespace boost::adaptors;
      EOS_ASSERT(is_sorted(keys(next_block.producer_changes)) && is_sorted(values(next_block.producer_changes)),
                 block_validate_exception, "Producer changes are not sorted correctly",
                 ("changes", next_block.producer_changes));
   }
N
Nathan Hourt 已提交
781
   const producer_object& producer = get_producer(get_scheduled_producer(get_slot_at_time(next_block.timestamp)));
N
Nathan Hourt 已提交
782

N
Nathan Hourt 已提交
783
   if(!(skip&skip_producer_signature))
784 785 786
      EOS_ASSERT(next_block.validate_signee(producer.signing_key), block_validate_exception,
                 "Incorrect block producer key: expected ${e} but got ${a}",
                 ("e", producer.signing_key)("a", public_key_type(next_block.signee())));
N
Nathan Hourt 已提交
787

788
   if(!(skip&skip_producer_schedule_check)) {
789 790 791
      EOS_ASSERT(next_block.producer == producer.owner, block_validate_exception,
                 "Producer produced block at wrong time",
                 ("block producer",next_block.producer)("scheduled producer",producer.owner));
N
Nathan Hourt 已提交
792 793 794 795 796
   }

   return producer;
}

797
void chain_controller::create_block_summary(const signed_block& next_block) {
798
   auto sid = next_block.block_num() & 0xffff;
799
   _db.modify( _db.get<block_summary_object,by_id>(sid), [&](block_summary_object& p) {
800 801
         p.block_id = next_block.id();
   });
N
Nathan Hourt 已提交
802 803
}

804
void chain_controller::update_global_properties(const signed_block& b) {
805 806
   // If we're at the end of a round, update the BlockchainConfiguration, producer schedule
   // and "producers" special account authority
N
Nathan Hourt 已提交
807
   if (b.block_num() % config::BlocksPerRound == 0) {
808
      auto schedule = calculate_next_round(b);
809 810
      auto config = _admin->get_blockchain_configuration(_db, schedule);

811 812
      const auto& gpo = get_global_properties();
      _db.modify(gpo, [schedule = std::move(schedule), config = std::move(config)] (global_property_object& gpo) {
813 814 815
         gpo.active_producers = std::move(schedule);
         gpo.configuration = std::move(config);
      });
816

817
      auto active_producers_authority = types::Authority(config::ProducersAuthorityThreshold, {}, {});
818
      for(auto& name : gpo.active_producers) {
819
         active_producers_authority.accounts.push_back({{name, config::ActiveName}, 1});
820 821
      }

822
      auto& po = _db.get<permission_object, by_owner>( boost::make_tuple(config::ProducersAccountName, config::ActiveName) );
823 824 825
      _db.modify(po,[active_producers_authority] (permission_object& po) {
         po.auth = active_producers_authority;
      });
826 827 828
   }
}

829
void chain_controller::add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts ) {
830
   for (const auto& i : checkpts)
N
Nathan Hourt 已提交
831 832 833
      _checkpoints[i.first] = i.second;
}

834
bool chain_controller::before_last_checkpoint()const {
N
Nathan Hourt 已提交
835 836 837
   return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
}

838
const global_property_object& chain_controller::get_global_properties()const {
839
   return _db.get<global_property_object>();
N
Nathan Hourt 已提交
840 841
}

842
const dynamic_global_property_object&chain_controller::get_dynamic_global_properties() const {
843
   return _db.get<dynamic_global_property_object>();
N
Nathan Hourt 已提交
844 845
}

846
time_point_sec chain_controller::head_block_time()const {
N
Nathan Hourt 已提交
847 848 849
   return get_dynamic_global_properties().time;
}

850
uint32_t chain_controller::head_block_num()const {
N
Nathan Hourt 已提交
851 852 853
   return get_dynamic_global_properties().head_block_number;
}

854
block_id_type chain_controller::head_block_id()const {
N
Nathan Hourt 已提交
855 856 857
   return get_dynamic_global_properties().head_block_id;
}

N
Nathan Hourt 已提交
858
types::AccountName chain_controller::head_block_producer() const {
N
Nathan Hourt 已提交
859
   if (auto head_block = fetch_block_by_id(head_block_id()))
860
      return head_block->producer;
N
Nathan Hourt 已提交
861 862 863
   return {};
}

N
Nathan Hourt 已提交
864 865 866 867
const producer_object& chain_controller::get_producer(const types::AccountName& ownerName) const {
   return _db.get<producer_object, by_owner>(ownerName);
}

868
uint32_t chain_controller::last_irreversible_block_num() const {
N
Nathan Hourt 已提交
869
   return get_dynamic_global_properties().last_irreversible_block_num;
N
Nathan Hourt 已提交
870 871
}

872
void chain_controller::initialize_indexes() {
873 874
   _db.add_index<account_index>();
   _db.add_index<permission_index>();
875
   _db.add_index<permission_link_index>();
876 877
   _db.add_index<action_permission_index>();
   _db.add_index<key_value_index>();
878
   _db.add_index<key128x128_value_index>();
879
   _db.add_index<key64x64x64_value_index>();
880 881 882 883 884

   _db.add_index<global_property_multi_index>();
   _db.add_index<dynamic_global_property_multi_index>();
   _db.add_index<block_summary_multi_index>();
   _db.add_index<transaction_multi_index>();
885
   _db.add_index<generated_transaction_multi_index>();
886
   _db.add_index<producer_multi_index>();
N
Nathan Hourt 已提交
887 888
}

889
void chain_controller::initialize_chain(chain_initializer_interface& starter)
N
Nathan Hourt 已提交
890
{ try {
891
   if (!_db.find<global_property_object>()) {
N
Nathan Hourt 已提交
892 893 894 895 896
      _db.with_write_lock([this, &starter] {
         auto initial_timestamp = starter.get_chain_start_time();
         FC_ASSERT(initial_timestamp != time_point_sec(), "Must initialize genesis timestamp." );
         FC_ASSERT(initial_timestamp.sec_since_epoch() % config::BlockIntervalSeconds == 0,
                    "Genesis timestamp must be divisible by config::BlockIntervalSeconds." );
N
Nathan Hourt 已提交
897

898
         // Create global properties
N
Nathan Hourt 已提交
899 900 901
         _db.create<global_property_object>([&starter](global_property_object& p) {
            p.configuration = starter.get_chain_start_configuration();
            p.active_producers = starter.get_chain_start_producers();
902 903
         });
         _db.create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
N
Nathan Hourt 已提交
904
            p.time = initial_timestamp;
905 906
            p.recent_slots_filled = uint64_t(-1);
         });
N
Nathan Hourt 已提交
907

N
Nathan Hourt 已提交
908
         // Initialize block summary index
909 910
         for (int i = 0; i < 0x10000; i++)
            _db.create<block_summary_object>([&](block_summary_object&) {});
N
Nathan Hourt 已提交
911

912
         auto messages = starter.prepare_database(*this, _db);
913 914
         std::for_each(messages.begin(), messages.end(), [&](const Message& m) { 
            MessageOutput output;
915
            ProcessedTransaction trx; /// dummy tranaction required for scope validation
916
            std::sort(trx.scope.begin(), trx.scope.end() );
917
            with_skip_flags(skip_scope_check | skip_transaction_signatures | skip_authority_check, [&](){
918
               process_message(trx,m.code,m,output); 
919
            });
920
         });
921 922
      });
   }
N
Nathan Hourt 已提交
923 924
} FC_CAPTURE_AND_RETHROW() }

925 926 927
chain_controller::chain_controller(database& database, fork_database& fork_db, block_log& blocklog,
                                   chain_initializer_interface& starter, unique_ptr<chain_administration_interface> admin)
   : _db(database), _fork_db(fork_db), _block_log(blocklog), _admin(std::move(admin)) {
N
Nathan Hourt 已提交
928

929
   initialize_indexes();
930
   starter.register_types(*this, _db);
N
Nathan Hourt 已提交
931 932 933 934 935 936

   // Behave as though we are applying a block during chain initialization (it's the genesis block!)
   with_applying_block([&] {
      initialize_chain(starter);
   });

937 938
   spinup_db();
   spinup_fork_db();
939 940 941

   if (_block_log.read_head() && head_block_num() < _block_log.read_head()->block_num())
      replay();
N
Nathan Hourt 已提交
942 943
}

944 945 946 947 948
chain_controller::~chain_controller() {
   clear_pending();
   _db.flush();
   _fork_db.reset();
}
N
Nathan Hourt 已提交
949

950
void chain_controller::replay() {
951
   ilog("Replaying blockchain");
N
Nathan Hourt 已提交
952
   auto start = fc::time_point::now();
953 954 955
   auto last_block = _block_log.read_head();
   if (!last_block) {
      elog("No blocks in block log; skipping replay");
N
Nathan Hourt 已提交
956 957 958 959 960
      return;
   }

   const auto last_block_num = last_block->block_num();

961 962 963 964 965 966
   ilog("Replaying blocks...");
   for (uint32_t i = 1; i <= last_block_num; ++i) {
      if (i % 5000 == 0)
         std::cerr << "   " << double(i*100)/last_block_num << "%   "<<i << " of " <<last_block_num<<"   \n";
      fc::optional<signed_block> block = _block_log.read_block_by_num(i);
      FC_ASSERT(block, "Could not find block #${n} in block_log!", ("n", i));
N
Nathan Hourt 已提交
967 968 969 970 971 972 973 974
      apply_block(*block, skip_producer_signature |
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_producer_schedule_check |
                          skip_authority_check);
   }
   auto end = fc::time_point::now();
975 976
   ilog("Done replaying ${n} blocks, elapsed time: ${t} sec",
        ("n", head_block_num())("t",double((end-start).count())/1000000.0));
N
Nathan Hourt 已提交
977

978
   _db.set_revision(head_block_num());
979
}
N
Nathan Hourt 已提交
980

981 982 983 984
void chain_controller::spinup_db() {
   // Rewind the database to the last irreversible block
   _db.with_write_lock([&] {
      _db.undo_all();
D
Daniel Larimer 已提交
985

986 987 988 989
      FC_ASSERT(_db.revision() == head_block_num(), "Chainbase revision does not match head block num",
                ("rev", _db.revision())("head_block", head_block_num()));
   });
}
N
Nathan Hourt 已提交
990

991
void chain_controller::spinup_fork_db()
N
Nathan Hourt 已提交
992
{
993 994 995 996 997 998 999 1000
   fc::optional<signed_block> last_block = _block_log.read_head();
   if(last_block.valid()) {
      _fork_db.start_block(*last_block);
      if (last_block->id() != head_block_id()) {
           FC_ASSERT(head_block_num() == 0, "last block ID does not match current chain state",
                     ("last_block->id", last_block->id())("head_block_num",head_block_num()));
      }
   }
N
Nathan Hourt 已提交
1001 1002
}

1003 1004
ProducerRound chain_controller::calculate_next_round(const signed_block& next_block) {
   auto schedule = _admin->get_next_round(_db);
N
Nathan Hourt 已提交
1005 1006 1007 1008
   auto changes = get_global_properties().active_producers - schedule;
   EOS_ASSERT(boost::range::equal(next_block.producer_changes, changes), block_validate_exception,
              "Unexpected round changes in new block header",
              ("expected changes", changes)("block changes", next_block.producer_changes));
1009

1010
   utilities::rand::random rng(next_block.timestamp.sec_since_epoch());
1011 1012 1013 1014
   rng.shuffle(schedule);
   return schedule;
}

1015
void chain_controller::update_global_dynamic_data(const signed_block& b) {
1016
   const dynamic_global_property_object& _dgp = _db.get<dynamic_global_property_object>();
N
Nathan Hourt 已提交
1017

1018 1019
   uint32_t missed_blocks = head_block_num() == 0? 1 : get_slot_at_time(b.timestamp);
   assert(missed_blocks != 0);
N
Nathan Hourt 已提交
1020
   missed_blocks--;
N
Nathan Hourt 已提交
1021

1022 1023
//   if (missed_blocks)
//      wlog("Blockchain continuing after gap of ${b} missed blocks", ("b", missed_blocks));
N
Nathan Hourt 已提交
1024

N
Nathan Hourt 已提交
1025
   for(uint32_t i = 0; i < missed_blocks; ++i) {
N
Nathan Hourt 已提交
1026
      const auto& producer_missed = get_producer(get_scheduled_producer(i+1));
1027
      if(producer_missed.owner != b.producer) {
N
Nathan Hourt 已提交
1028 1029 1030 1031 1032 1033
         /*
         const auto& producer_account = producer_missed.producer_account(*this);
         if( (fc::time_point::now() - b.timestamp) < fc::seconds(30) )
            wlog( "Producer ${name} missed block ${n} around ${t}", ("name",producer_account.name)("n",b.block_num())("t",b.timestamp) );
            */

1034
         _db.modify( producer_missed, [&]( producer_object& w ) {
N
Nathan Hourt 已提交
1035 1036 1037 1038 1039 1040
           w.total_missed++;
         });
      }
   }

   // dynamic global properties updating
1041
   _db.modify( _dgp, [&]( dynamic_global_property_object& dgp ){
N
Nathan Hourt 已提交
1042 1043 1044
      dgp.head_block_number = b.block_num();
      dgp.head_block_id = b.id();
      dgp.time = b.timestamp;
1045
      dgp.current_producer = b.producer;
N
Nathan Hourt 已提交
1046 1047 1048 1049 1050 1051 1052 1053 1054
      dgp.current_absolute_slot += missed_blocks+1;

      // If we've missed more blocks than the bitmap stores, skip calculations and simply reset the bitmap
      if (missed_blocks < sizeof(dgp.recent_slots_filled) * 8) {
         dgp.recent_slots_filled <<= 1;
         dgp.recent_slots_filled += 1;
         dgp.recent_slots_filled <<= missed_blocks;
      } else
         dgp.recent_slots_filled = 0;
N
Nathan Hourt 已提交
1055 1056 1057 1058 1059
   });

   _fork_db.set_max_size( _dgp.head_block_number - _dgp.last_irreversible_block_num + 1 );
}

1060
void chain_controller::update_signing_producer(const producer_object& signing_producer, const signed_block& new_block)
N
Nathan Hourt 已提交
1061 1062
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
N
Nathan Hourt 已提交
1063
   uint64_t new_block_aslot = dpo.current_absolute_slot + get_slot_at_time( new_block.timestamp );
N
Nathan Hourt 已提交
1064

1065
   _db.modify( signing_producer, [&]( producer_object& _wit )
N
Nathan Hourt 已提交
1066 1067 1068 1069 1070 1071
   {
      _wit.last_aslot = new_block_aslot;
      _wit.last_confirmed_block_num = new_block.block_num();
   } );
}

1072
void chain_controller::update_last_irreversible_block()
N
Nathan Hourt 已提交
1073 1074 1075 1076
{
   const global_property_object& gpo = get_global_properties();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();

N
Nathan Hourt 已提交
1077 1078 1079
   vector<const producer_object*> producer_objs;
   producer_objs.reserve(gpo.active_producers.size());
   std::transform(gpo.active_producers.begin(), gpo.active_producers.end(), std::back_inserter(producer_objs),
N
Nathan Hourt 已提交
1080
                  [this](const AccountName& owner) { return &get_producer(owner); });
N
Nathan Hourt 已提交
1081

N
Nathan Hourt 已提交
1082
   static_assert(config::IrreversibleThresholdPercent > 0, "irreversible threshold must be nonzero");
N
Nathan Hourt 已提交
1083

N
Nathan Hourt 已提交
1084
   size_t offset = EOS_PERCENT(producer_objs.size(), config::Percent100 - config::IrreversibleThresholdPercent);
1085 1086
   std::nth_element(producer_objs.begin(), producer_objs.begin() + offset, producer_objs.end(),
      [](const producer_object* a, const producer_object* b) {
N
Nathan Hourt 已提交
1087
         return a->last_confirmed_block_num < b->last_confirmed_block_num;
1088
      });
N
Nathan Hourt 已提交
1089

N
Nathan Hourt 已提交
1090
   uint32_t new_last_irreversible_block_num = producer_objs[offset]->last_confirmed_block_num;
N
Nathan Hourt 已提交
1091

1092
   if (new_last_irreversible_block_num > dpo.last_irreversible_block_num) {
1093
      _db.modify(dpo, [&](dynamic_global_property_object& _dpo) {
N
Nathan Hourt 已提交
1094
         _dpo.last_irreversible_block_num = new_last_irreversible_block_num;
1095
      });
N
Nathan Hourt 已提交
1096
   }
1097 1098

   // Write newly irreversible blocks to disk. First, get the number of the last block on disk...
1099
   auto old_last_irreversible_block = _block_log.head();
1100 1101 1102 1103
   int last_block_on_disk = 0;
   // If this is null, there are no blocks on disk, so the zero is correct
   if (old_last_irreversible_block)
      last_block_on_disk = old_last_irreversible_block->block_num();
1104

1105 1106 1107 1108 1109 1110
   if (last_block_on_disk < new_last_irreversible_block_num)
      for (auto block_to_write = last_block_on_disk + 1;
           block_to_write <= new_last_irreversible_block_num;
           ++block_to_write) {
         auto block = fetch_block_by_number(block_to_write);
         assert(block);
1111
         _block_log.append(*block);
1112
      }
N
Nathan Hourt 已提交
1113 1114 1115

   // Trim fork_database and undo histories
   _fork_db.set_max_size(head_block_num() - new_last_irreversible_block_num + 1);
1116
   _db.commit(new_last_irreversible_block_num);
N
Nathan Hourt 已提交
1117 1118
}

1119
void chain_controller::clear_expired_transactions()
N
Nathan Hourt 已提交
1120 1121 1122
{ try {
   //Look for expired transactions in the deduplication list, and remove them.
   //Transactions must have expired by at least two forking windows in order to be removed.
1123
   auto& transaction_idx = _db.get_mutable_index<transaction_multi_index>();
N
Nathan Hourt 已提交
1124 1125 1126
   const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
   while( (!dedupe_index.empty()) && (head_block_time() > dedupe_index.rbegin()->trx.expiration) )
      transaction_idx.remove(*dedupe_index.rbegin());
1127 1128 1129 1130 1131 1132 1133

   //Look for expired transactions in the pending generated list, and remove them.
   //Transactions must have expired by at least two forking windows in order to be removed.
   auto& generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
   const auto& generated_index = generated_transaction_idx.indices().get<generated_transaction_object::by_expiration>();
   while( (!generated_index.empty()) && (head_block_time() > generated_index.rbegin()->trx.expiration) )
      generated_transaction_idx.remove(*generated_index.rbegin());
N
Nathan Hourt 已提交
1134 1135 1136 1137
} FC_CAPTURE_AND_RETHROW() }

using boost::container::flat_set;

N
Nathan Hourt 已提交
1138
types::AccountName chain_controller::get_scheduled_producer(uint32_t slot_num)const
N
Nathan Hourt 已提交
1139 1140
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
N
Nathan Hourt 已提交
1141
   uint64_t current_aslot = dpo.current_absolute_slot + slot_num;
1142
   const auto& gpo = _db.get<global_property_object>();
N
Nathan Hourt 已提交
1143
   return gpo.active_producers[current_aslot % gpo.active_producers.size()];
N
Nathan Hourt 已提交
1144 1145
}

1146
fc::time_point_sec chain_controller::get_slot_time(uint32_t slot_num)const
N
Nathan Hourt 已提交
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
{
   if( slot_num == 0 )
      return fc::time_point_sec();

   auto interval = block_interval();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();

   if( head_block_num() == 0 )
   {
      // n.b. first block is at genesis_time plus one block interval
      fc::time_point_sec genesis_time = dpo.time;
      return genesis_time + slot_num * interval;
   }

   int64_t head_block_abs_slot = head_block_time().sec_since_epoch() / interval;
   fc::time_point_sec head_slot_time(head_block_abs_slot * interval);

   return head_slot_time + (slot_num * interval);
}

1167
uint32_t chain_controller::get_slot_at_time(fc::time_point_sec when)const
N
Nathan Hourt 已提交
1168 1169 1170 1171 1172 1173 1174
{
   fc::time_point_sec first_slot_time = get_slot_time( 1 );
   if( when < first_slot_time )
      return 0;
   return (when - first_slot_time).to_seconds() / block_interval() + 1;
}

1175
uint32_t chain_controller::producer_participation_rate()const
N
Nathan Hourt 已提交
1176 1177
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
N
Nathan Hourt 已提交
1178
   return uint64_t(config::Percent100) * __builtin_popcountll(dpo.recent_slots_filled) / 64;
N
Nathan Hourt 已提交
1179 1180
}

1181
void chain_controller::set_apply_handler( const AccountName& contract, const AccountName& scope, const ActionName& action, apply_handler v ) {
D
Daniel Larimer 已提交
1182
   apply_handlers[contract][std::make_pair(scope,action)] = v;
1183
}
N
Nathan Hourt 已提交
1184

1185
chain_initializer_interface::~chain_initializer_interface() {}
N
Nathan Hourt 已提交
1186

1187

D
Daniel Larimer 已提交
1188
ProcessedTransaction chain_controller::transaction_from_variant( const fc::variant& v )const {
1189 1190 1191 1192
   const variant_object& vo = v.get_object();
#define GET_FIELD( VO, FIELD, RESULT ) \
   if( VO.contains(#FIELD) ) fc::from_variant( VO[#FIELD], RESULT.FIELD )

D
Daniel Larimer 已提交
1193
   ProcessedTransaction result;
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
   GET_FIELD( vo, refBlockNum, result );
   GET_FIELD( vo, refBlockPrefix, result );
   GET_FIELD( vo, expiration, result );
   GET_FIELD( vo, scope, result );
   GET_FIELD( vo, signatures, result );

   if( vo.contains( "messages" ) ) {
      const vector<variant>& msgs = vo["messages"].get_array();
      result.messages.resize( msgs.size() );
      for( uint32_t i = 0; i <  msgs.size(); ++i ) {
         const auto& vo = msgs[i].get_object();
         GET_FIELD( vo, code, result.messages[i] );
         GET_FIELD( vo, type, result.messages[i] );
1207
         GET_FIELD( vo, authorization, result.messages[i] );
1208 1209 1210 1211 1212 1213

         if( vo.contains( "data" ) ) {
            const auto& data = vo["data"];
            if( data.is_string() ) {
               GET_FIELD( vo, data, result.messages[i] );
            } else if ( data.is_object() ) {
1214 1215
               result.messages[i].data = message_to_binary( result.messages[i].code, result.messages[i].type, data ); 
               /*
1216 1217 1218 1219 1220 1221 1222 1223
               const auto& code_account = _db.get<account_object,by_name>( result.messages[i].code );
               if( code_account.abi.size() > 4 ) { /// 4 == packsize of empty Abi
                  fc::datastream<const char*> ds( code_account.abi.data(), code_account.abi.size() );
                  eos::types::Abi abi;
                  fc::raw::unpack( ds, abi );
                  types::AbiSerializer abis( abi );
                  result.messages[i].data = abis.variantToBinary( abis.getActionType( result.messages[i].type ), data );
               }
1224
               */
1225 1226 1227 1228
            }
         }
      }
   }
D
Daniel Larimer 已提交
1229 1230 1231
   if( vo.contains( "output" ) ) {
      const vector<variant>& outputs = vo["output"].get_array();
   }
1232 1233 1234 1235
   return result;
#undef GET_FIELD
}

1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
vector<char> chain_controller::message_to_binary( Name code, Name type, const fc::variant& obj )const {
   const auto& code_account = _db.get<account_object,by_name>( code );
   if( code_account.abi.size() > 4 ) { /// 4 == packsize of empty Abi
      fc::datastream<const char*> ds( code_account.abi.data(), code_account.abi.size() );
      eos::types::Abi abi;
      fc::raw::unpack( ds, abi );
      types::AbiSerializer abis( abi );
      return abis.variantToBinary( abis.getActionType( type ), obj );
   }
   return vector<char>();
}
D
Daniel Larimer 已提交
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
fc::variant chain_controller::message_from_binary( Name code, Name type, const vector<char>& data )const {
   const auto& code_account = _db.get<account_object,by_name>( code );
   if( code_account.abi.size() > 4 ) { /// 4 == packsize of empty Abi
      fc::datastream<const char*> ds( code_account.abi.data(), code_account.abi.size() );
      eos::types::Abi abi;
      fc::raw::unpack( ds, abi );
      types::AbiSerializer abis( abi );
      return abis.binaryToVariant( abis.getActionType( type ), data );
   }
   return fc::variant();
}
1258

D
Daniel Larimer 已提交
1259
fc::variant  chain_controller::transaction_to_variant( const ProcessedTransaction& trx )const {
1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
#define SET_FIELD( MVO, OBJ, FIELD ) MVO(#FIELD, OBJ.FIELD)

    fc::mutable_variant_object trx_mvo;
    SET_FIELD( trx_mvo, trx, refBlockNum );
    SET_FIELD( trx_mvo, trx, refBlockPrefix );
    SET_FIELD( trx_mvo, trx, expiration );
    SET_FIELD( trx_mvo, trx, scope );
    SET_FIELD( trx_mvo, trx, signatures );

    vector<fc::mutable_variant_object> msgs( trx.messages.size() );
    vector<fc::variant> msgsv(msgs.size());

    for( uint32_t i = 0; i < trx.messages.size(); ++i ) {
       auto& msg_mvo = msgs[i];
       auto& msg     = trx.messages[i];
       SET_FIELD( msg_mvo, msg, code );
       SET_FIELD( msg_mvo, msg, type );
1277
       SET_FIELD( msg_mvo, msg, authorization );
1278 1279 1280

       const auto& code_account = _db.get<account_object,by_name>( msg.code );
       if( code_account.abi.size() > 4 ) { /// 4 == packsize of empty Abi
D
Daniel Larimer 已提交
1281
          try {
D
Daniel Larimer 已提交
1282
             msg_mvo( "data", message_from_binary( msg.code, msg.type, msg.data ) ); 
D
Daniel Larimer 已提交
1283 1284 1285 1286
             msg_mvo( "hex_data", msg.data );
          } catch ( ... ) {
            SET_FIELD( msg_mvo, msg, data );
          }
1287 1288 1289 1290 1291 1292 1293 1294
       }
       else {
         SET_FIELD( msg_mvo, msg, data );
       }
       msgsv[i] = std::move( msgs[i] );
    }
    trx_mvo( "messages", std::move(msgsv) );

D
Daniel Larimer 已提交
1295 1296 1297 1298 1299 1300 1301 1302 1303
    /* TODO: recursively process generated transactions 
    vector<fc::mutable_variant_object> outs( trx.messages.size() );
    for( uint32_t i = 0; i < trx.output.size(); ++i ) {
       auto& out_mvo = outs[i];
       auto& out = trx.outputs[i];
    }
    */
    trx_mvo( "output", fc::variant( trx.output ) );

1304 1305 1306 1307
    return fc::variant( std::move( trx_mvo ) );
#undef SET_FIELD
}

1308

N
Nathan Hourt 已提交
1309
} }