chain_controller.cpp 62.5 KB
Newer Older
A
Andrianto Lie 已提交
1 2 3
/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
N
Nathan Hourt 已提交
4
 */
N
Nathan Hourt 已提交
5

B
Bart Wyatt 已提交
6
#include <eosio/chain/chain_controller.hpp>
7
#include <eosio/chain/contracts/staked_balance_objects.hpp>
N
Nathan Hourt 已提交
8

B
Bart Wyatt 已提交
9 10
#include <eosio/chain/block_summary_object.hpp>
#include <eosio/chain/global_property_object.hpp>
11
#include <eosio/chain/contracts/contract_table_objects.hpp>
B
Bart Wyatt 已提交
12 13 14 15 16 17
#include <eosio/chain/action_objects.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
#include <eosio/chain/transaction_object.hpp>
#include <eosio/chain/producer_object.hpp>
#include <eosio/chain/permission_link_object.hpp>
#include <eosio/chain/authority_checker.hpp>
D
Daniel Larimer 已提交
18
#include <eosio/chain/contracts/chain_initializer.hpp>
19
#include <eosio/chain/contracts/producer_objects.hpp>
20
#include <eosio/chain/scope_sequence_object.hpp>
21
#include <eosio/chain/merkle.hpp>
N
Nathan Hourt 已提交
22

B
Bart Wyatt 已提交
23
#include <eosio/chain/wasm_interface.hpp>
24

25
#include <eos/utilities/rand.hpp>
26

N
Nathan Hourt 已提交
27
#include <fc/smart_ref_impl.hpp>
N
Nathan Hourt 已提交
28 29 30
#include <fc/uint128.hpp>
#include <fc/crypto/digest.hpp>

31
#include <boost/range/algorithm/copy.hpp>
N
Nathan Hourt 已提交
32
#include <boost/range/algorithm_ext/is_sorted.hpp>
33
#include <boost/range/adaptor/transformed.hpp>
N
Nathan Hourt 已提交
34
#include <boost/range/adaptor/map.hpp>
N
Nathan Hourt 已提交
35 36 37 38

#include <fstream>
#include <functional>
#include <iostream>
39
#include <chrono>
N
Nathan Hourt 已提交
40

P
Pravin 已提交
41
namespace eosio { namespace chain {
D
Daniel Larimer 已提交
42

43 44 45 46
bool is_start_of_round( block_num_type block_num ) {
  return (block_num % config::blocks_per_round) == 0; 
}

D
Daniel Larimer 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
chain_controller::chain_controller( const chain_controller::controller_config& cfg )
:_db( cfg.shared_memory_dir, 
      (cfg.read_only ? database::read_only : database::read_write), 
      cfg.shared_memory_size), 
 _block_log(cfg.block_log_dir) 
{
   _initialize_indexes();

   contracts::chain_initializer starter(cfg.genesis);
   starter.register_types(*this, _db);

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

   _spinup_db();
   _spinup_fork_db();

   if (_block_log.read_head() && head_block_num() < _block_log.read_head()->block_num())
      replay();
} /// chain_controller::chain_controller


chain_controller::~chain_controller() {
   clear_pending();
   _db.flush();
}

76
bool chain_controller::is_known_block(const block_id_type& id)const
N
Nathan Hourt 已提交
77
{
78
   return _fork_db.is_known_block(id) || _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
79 80 81 82 83 84
}
/**
 * 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.
 */
85
bool chain_controller::is_known_transaction(const transaction_id_type& id)const
N
Nathan Hourt 已提交
86
{
87
   const auto& trx_idx = _db.get_index<transaction_multi_index, by_trx_id>();
N
Nathan Hourt 已提交
88 89 90
   return trx_idx.find( id ) != trx_idx.end();
}

91
block_id_type chain_controller::get_block_id_for_num(uint32_t block_num)const
N
Nathan Hourt 已提交
92
{ try {
93 94
   if (const auto& block = fetch_block_by_number(block_num))
      return block->id();
N
Nathan Hourt 已提交
95

96 97 98
   FC_THROW_EXCEPTION(unknown_block_exception, "Could not find block");
} FC_CAPTURE_AND_RETHROW((block_num)) }

99
optional<signed_block> chain_controller::fetch_block_by_id(const block_id_type& id)const
N
Nathan Hourt 已提交
100
{
101 102
   auto b = _fork_db.fetch_block(id);
   if(b) return b->data;
103
   return _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
104 105
}

106
optional<signed_block> chain_controller::fetch_block_by_number(uint32_t num)const
N
Nathan Hourt 已提交
107
{
108
   if (const auto& block = _block_log.read_block_by_num(num))
109 110
      return *block;

N
Nathan Hourt 已提交
111
   // Not in _block_log, so it must be since the last irreversible block. Grab it from _fork_db instead
112 113 114 115 116 117 118 119
   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 已提交
120 121 122
   return optional<signed_block>();
}

D
Daniel Larimer 已提交
123
/*
D
Daniel Larimer 已提交
124
const signed_transaction& chain_controller::get_recent_transaction(const transaction_id_type& trx_id) const
N
Nathan Hourt 已提交
125
{
126
   auto& index = _db.get_index<transaction_multi_index, by_trx_id>();
N
Nathan Hourt 已提交
127 128 129 130
   auto itr = index.find(trx_id);
   FC_ASSERT(itr != index.end());
   return itr->trx;
}
D
Daniel Larimer 已提交
131
*/
N
Nathan Hourt 已提交
132

133
std::vector<block_id_type> chain_controller::get_block_ids_on_fork(block_id_type head_of_fork) const
N
Nathan Hourt 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
{
  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;
}

151

N
Nathan Hourt 已提交
152 153 154 155 156 157
/**
 * 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.
 */
D
Daniel Larimer 已提交
158
void chain_controller::push_block(const signed_block& new_block, uint32_t skip)
D
Daniel Larimer 已提交
159
{ try {
D
Daniel Larimer 已提交
160
   with_skip_flags( skip, [&](){ 
D
Daniel Larimer 已提交
161
      return without_pending_transactions( [&]() {
162
         return _db.with_write_lock( [&]() {
163
            return _push_block(new_block);
164
         } );
N
Nathan Hourt 已提交
165 166
      });
   });
167
} FC_CAPTURE_AND_RETHROW((new_block)) }
N
Nathan Hourt 已提交
168

169
bool chain_controller::_push_block(const signed_block& new_block)
N
Nathan Hourt 已提交
170
{ try {
N
Nathan Hourt 已提交
171
   uint32_t skip = _skip_flags;
172
   if (!(skip&skip_fork_db)) {
N
Nathan Hourt 已提交
173
      /// TODO: if the block is greater than the head block and before the next maintenance interval
N
Nathan Hourt 已提交
174 175 176 177
      // 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.
178
      if (new_head->data.previous != head_block_id()) {
N
Nathan Hourt 已提交
179 180
         //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
181 182
         if (new_head->data.block_num() > head_block_num()) {
            wlog("Switching to fork: ${id}", ("id",new_head->data.id()));
N
Nathan Hourt 已提交
183 184 185
            auto branches = _fork_db.fetch_branch_from(new_head->data.id(), head_block_id());

            // pop blocks until we hit the forked block
186
            while (head_block_id() != branches.second.back()->data.previous)
N
Nathan Hourt 已提交
187 188 189
               pop_block();

            // push all blocks on the new fork
190 191
            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 已提交
192 193
                optional<fc::exception> except;
                try {
194
                   auto session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
195
                   _apply_block((*ritr)->data, skip);
N
Nathan Hourt 已提交
196 197
                   session.push();
                }
198 199 200
                catch (const fc::exception& e) { except = e; }
                if (except) {
                   wlog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));
N
Nathan Hourt 已提交
201
                   // remove the rest of branches.first from the fork_db, those blocks are invalid
202 203
                   while (ritr != branches.first.rend()) {
                      _fork_db.remove((*ritr)->data.id());
N
Nathan Hourt 已提交
204 205
                      ++ritr;
                   }
206
                   _fork_db.set_head(branches.second.front());
N
Nathan Hourt 已提交
207 208

                   // pop all blocks from the bad fork
209
                   while (head_block_id() != branches.second.back()->data.previous)
N
Nathan Hourt 已提交
210 211 212
                      pop_block();

                   // restore all blocks from the good fork
213
                   for (auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr) {
214
                      auto session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
215
                      _apply_block((*ritr)->data, skip);
N
Nathan Hourt 已提交
216 217 218 219 220
                      session.push();
                   }
                   throw *except;
                }
            }
D
Daniel Larimer 已提交
221
            return true; //swithced fork
N
Nathan Hourt 已提交
222
         }
D
Daniel Larimer 已提交
223
         else return false; // didn't switch fork
N
Nathan Hourt 已提交
224 225 226 227
      }
   }

   try {
228
      auto session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
229
      _apply_block(new_block, skip);
N
Nathan Hourt 已提交
230 231 232 233 234 235 236 237
      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;
238
} FC_CAPTURE_AND_RETHROW((new_block)) }
N
Nathan Hourt 已提交
239 240 241 242 243 244 245 246 247 248

/**
 * 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.
 */
249
transaction_trace chain_controller::push_transaction(const signed_transaction& trx, uint32_t skip)
N
Nathan Hourt 已提交
250
{ try {
251 252
   return with_skip_flags(skip, [&]() {
      return _db.with_write_lock([&]() {
253
         return _push_transaction(trx);
D
Daniel Larimer 已提交
254
      });
N
Nathan Hourt 已提交
255 256
   });
} FC_CAPTURE_AND_RETHROW((trx)) }
N
Nathan Hourt 已提交
257

258
transaction_trace chain_controller::_push_transaction(const signed_transaction& trx) {
B
Bart Wyatt 已提交
259
   check_transaction_authorization(trx);
260
   transaction_metadata   mtrx( trx, get_chain_id(), head_block_time());
B
Bart Wyatt 已提交
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

   auto result = _push_transaction(mtrx);

   _pending_block->input_transactions.push_back(trx);

   // notify anyone listening to pending transactions
   on_pending_transaction(trx);

   return result;

}

transaction_trace chain_controller::_push_transaction( transaction_metadata& data )
{
   const transaction& trx = data.trx;
276 277
   // 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.
D
Daniel Larimer 已提交
278
   if( !_pending_block ) {
D
Daniel Larimer 已提交
279
      _start_pending_block();
D
Daniel Larimer 已提交
280
   }
281

282
   auto temp_session = _db.start_undo_session(true);
D
Daniel Larimer 已提交
283

B
Bart Wyatt 已提交
284
   // for now apply the transaction serially but schedule it according to those invariants
285
   validate_referenced_accounts(trx);
N
Nathan Hourt 已提交
286

287 288
   auto cyclenum = _pending_block->regions.back().cycles_summary.size() - 1;

289 290 291
   /// TODO: move _pending_cycle into db so that it can be undone if transation fails, for now we will apply
   /// the transaction first so that there is nothing to undo... this only works because things are currently
   /// single threaded
B
Bart Wyatt 已提交
292 293 294
   // set cycle, shard, region etc
   data.region_id = 0;
   data.cycle_index = cyclenum;
B
Bart Wyatt 已提交
295
   data.shard_index = 0;
B
Bart Wyatt 已提交
296
   auto result = _apply_transaction( data );
297

298
   auto& bcycle = _pending_block->regions.back().cycles_summary.back();
B
Bart Wyatt 已提交
299
   auto& bshard = bcycle.front();
300

B
Bart Wyatt 已提交
301 302 303
   copy_append_names(bshard.read_scopes, result.read_scopes);
   copy_append_names(bshard.write_scopes, result.write_scopes);
   bshard.transactions.emplace_back( result );
304

B
Bart Wyatt 已提交
305
   _pending_cycle_trace->shard_traces.at(0).append(result);
B
Bart Wyatt 已提交
306

N
Nathan Hourt 已提交
307 308 309
   // The transaction applied successfully. Merge its changes into the pending block session.
   temp_session.squash();

B
Bart Wyatt 已提交
310
   return result;
N
Nathan Hourt 已提交
311 312
}

313 314 315 316 317 318
void chain_controller::_start_pending_block()
{
   FC_ASSERT( !_pending_block );
   _pending_block         = signed_block();
   _pending_block_trace   = block_trace(*_pending_block);
   _pending_block_session = _db.start_undo_session(true);
319 320
   _pending_block->regions.resize(1);
   _pending_block_trace->region_traces.resize(1);
321 322 323
   _start_pending_cycle();
}

324 325
/**
 *  Wraps up all work for current shards, starts a new cycle, and
326
 *  executes any pending transactions
327
 */
328
void chain_controller::_start_pending_cycle() {
329
   _pending_block->regions.back().cycles_summary.resize( _pending_block->regions[0].cycles_summary.size() + 1 );
330 331
   _pending_cycle_trace = cycle_trace();
   _start_pending_shard();
332 333

   /// TODO: check for deferred transactions and schedule them
334
} // _start_pending_cycle
335

336
void chain_controller::_start_pending_shard()
B
Bart Wyatt 已提交
337
{
338
   auto& bcycle = _pending_block->regions.back().cycles_summary.back();
339 340 341
   bcycle.resize( bcycle.size()+1 );

   _pending_cycle_trace->shard_traces.resize(_pending_cycle_trace->shard_traces.size() + 1 );
B
Bart Wyatt 已提交
342 343
}

344 345
void chain_controller::_finalize_pending_cycle()
{
346 347 348 349
   for( auto& shard : _pending_cycle_trace->shard_traces ) {
      shard.calculate_root();
   }

350
   _apply_cycle_trace(*_pending_cycle_trace);
351
   _pending_block_trace->region_traces.back().cycle_traces.emplace_back(std::move(*_pending_cycle_trace));
352 353
   _pending_cycle_trace.reset();
}
B
Bart Wyatt 已提交
354

355 356 357 358 359
void chain_controller::_apply_cycle_trace( const cycle_trace& res )
{
   for (const auto&st: res.shard_traces) {
      for (const auto &tr: st.transaction_traces) {
         for (const auto &dt: tr.deferred_transactions) {
360
            _db.create<generated_transaction_object>([&](generated_transaction_object &obj) {
361 362 363 364 365
               obj.trx_id = dt.id();
               obj.sender = dt.sender;
               obj.sender_id = dt.sender_id;
               obj.expiration = dt.expiration;
               obj.delay_until = dt.execute_after;
366
               obj.published = head_block_time();
367 368 369 370 371 372
               obj.packed_trx.resize(fc::raw::pack_size(dt));
               fc::datastream<char *> ds(obj.packed_trx.data(), obj.packed_trx.size());
               fc::raw::pack(ds, dt);
            });
         }

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
         if (tr.canceled_deferred.size() > 0 ) {
            auto &generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
            const auto &generated_index = generated_transaction_idx.indices().get<by_sender_id>();
            for (const auto &dr: tr.canceled_deferred) {
               while(!generated_index.empty()) {
                  const auto& itr = generated_index.lower_bound(boost::make_tuple(dr.sender, dr.sender_id));
                  if (itr == generated_index.end() || itr->sender != dr.sender || itr->sender_id != dr.sender_id ) {
                     break;
                  }

                  generated_transaction_idx.remove(*itr);
               }
            }
         }

388 389 390 391
         ///TODO: hook this up as a signal handler in a de-coupled "logger" that may just silently drop them
         for (const auto &ar : tr.action_traces) {
            if (!ar.console.empty()) {
               auto prefix = fc::format_string(
B
Bart Wyatt 已提交
392
                  "[(${a},${n})->${r}]",
393
                  fc::mutable_variant_object()
B
Bart Wyatt 已提交
394 395
                     ("a", ar.act.account)
                     ("n", ar.act.name)
396 397 398 399 400
                     ("r", ar.receiver));
               std::cerr << prefix << ": CONSOLE OUTPUT BEGIN =====================" << std::endl;
               std::cerr << ar.console;
               std::cerr << prefix << ": CONSOLE OUTPUT END   =====================" << std::endl;
            }
401
         }
B
Bart Wyatt 已提交
402 403 404 405
      }
   }
}

406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
/**
 *  After applying all transactions successfully we can update
 *  the current block time, block number, producer stats, etc
 */
void chain_controller::_finalize_block( const block_trace& trace ) { try {
   const auto& b = trace.block;
   const producer_object& signing_producer = validate_block_header(_skip_flags, b);

   update_global_properties( b );
   update_global_dynamic_data( b );
   update_signing_producer(signing_producer, b);
   update_last_irreversible_block();

   create_block_summary(b);
   clear_expired_transactions();

422
   applied_block( trace ); //emit
423 424 425 426 427
   if (_currently_replaying_blocks)
     applied_irreversible_block(b);

} FC_CAPTURE_AND_RETHROW( (trace.block) ) }

428
signed_block chain_controller::generate_block(
D
Daniel Larimer 已提交
429 430 431
   block_timestamp_type when,
   account_name producer,
   const private_key_type& block_signing_private_key,
N
Nathan Hourt 已提交
432 433 434
   uint32_t skip /* = 0 */
   )
{ try {
N
Nathan Hourt 已提交
435
   return with_skip_flags( skip, [&](){
D
Daniel Larimer 已提交
436
      return _db.with_write_lock( [&](){
D
Daniel Larimer 已提交
437
         return _generate_block( when, producer, block_signing_private_key );
D
Daniel Larimer 已提交
438
      });
N
Nathan Hourt 已提交
439
   });
D
Daniel Larimer 已提交
440
} FC_CAPTURE_AND_RETHROW( (when) ) }
N
Nathan Hourt 已提交
441

D
Daniel Larimer 已提交
442 443 444 445 446
signed_block chain_controller::_generate_block( block_timestamp_type when, 
                                              account_name producer, 
                                              const private_key_type& block_signing_key )
{ try {
   uint32_t skip     = _skip_flags;
N
Nathan Hourt 已提交
447 448
   uint32_t slot_num = get_slot_at_time( when );
   FC_ASSERT( slot_num > 0 );
D
Daniel Larimer 已提交
449
   account_name scheduled_producer = get_scheduled_producer( slot_num );
N
Nathan Hourt 已提交
450
   FC_ASSERT( scheduled_producer == producer );
N
Nathan Hourt 已提交
451

N
Nathan Hourt 已提交
452
   const auto& producer_obj = get_producer(scheduled_producer);
N
Nathan Hourt 已提交
453

D
Daniel Larimer 已提交
454
   if( !_pending_block ) {
D
Daniel Larimer 已提交
455
      _start_pending_block();
456 457
   }

458
   _finalize_pending_cycle();
459

D
Daniel Larimer 已提交
460 461
   if( !(skip & skip_producer_signature) )
      FC_ASSERT( producer_obj.signing_key == block_signing_key.get_public_key() );
N
Nathan Hourt 已提交
462

463 464 465 466 467 468 469
      _pending_block->timestamp   = when;
      _pending_block->producer    = producer_obj.owner;
      _pending_block->previous    = head_block_id();
      _pending_block->block_mroot = get_dynamic_global_properties().block_merkle_root.get_root();
      _pending_block->transaction_mroot = _pending_block->calculate_transaction_merkle_root();
      _pending_block->action_mroot = _pending_block_trace->calculate_action_merkle_root();

470

471
      if( is_start_of_round( _pending_block->block_num() ) ) {
472 473 474
      auto latest_producer_schedule = _calculate_producer_schedule();
      if( latest_producer_schedule != _head_producer_schedule() )
         _pending_block->new_producers = latest_producer_schedule;
475 476
   }

N
Nathan Hourt 已提交
477
   if( !(skip & skip_producer_signature) )
D
Daniel Larimer 已提交
478
      _pending_block->sign( block_signing_key );
N
Nathan Hourt 已提交
479

480
   _finalize_block( *_pending_block_trace );
D
Daniel Larimer 已提交
481

482 483
   _pending_block_session->push();

D
Daniel Larimer 已提交
484 485
   auto result = move( *_pending_block );

486
   _pending_block_trace.reset();
487 488 489
   _pending_block.reset();
   _pending_block_session.reset();

D
Daniel Larimer 已提交
490
   if (!(skip&skip_fork_db)) {
D
Daniel Larimer 已提交
491
      _fork_db.push_block(result);
N
Nathan Hourt 已提交
492
   }
D
Daniel Larimer 已提交
493
   return result;
N
Nathan Hourt 已提交
494

N
Nathan Hourt 已提交
495
} FC_CAPTURE_AND_RETHROW( (producer) ) }
N
Nathan Hourt 已提交
496 497

/**
N
Nathan Hourt 已提交
498
 * Removes the most recent block from the database and undoes any changes it made.
N
Nathan Hourt 已提交
499
 */
500
void chain_controller::pop_block()
N
Nathan Hourt 已提交
501
{ try {
D
Daniel Larimer 已提交
502
   _pending_block_session.reset();
N
Nathan Hourt 已提交
503 504 505 506 507
   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();
508
   _db.undo();
N
Nathan Hourt 已提交
509 510
} FC_CAPTURE_AND_RETHROW() }

511
void chain_controller::clear_pending()
N
Nathan Hourt 已提交
512
{ try {
513
   _pending_block_trace.reset();
D
Daniel Larimer 已提交
514
   _pending_block.reset();
D
Daniel Larimer 已提交
515
   _pending_block_session.reset();
N
Nathan Hourt 已提交
516 517 518 519
} FC_CAPTURE_AND_RETHROW() }

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

D
Daniel Larimer 已提交
520
void chain_controller::_apply_block(const signed_block& next_block, uint32_t skip)
N
Nathan Hourt 已提交
521 522
{
   auto block_num = next_block.block_num();
523 524 525 526 527
   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 已提交
528

529
      if (_checkpoints.rbegin()->first >= block_num)
N
Nathan Hourt 已提交
530 531
         skip = ~0;// WE CAN SKIP ALMOST EVERYTHING
   }
N
Nathan Hourt 已提交
532 533 534

   with_applying_block([&] {
      with_skip_flags(skip, [&] {
D
Daniel Larimer 已提交
535
         __apply_block(next_block);
N
Nathan Hourt 已提交
536 537
      });
   });
N
Nathan Hourt 已提交
538 539
}

540 541 542 543 544 545 546 547 548 549 550
static void validate_shard_scopes(const vector<scope_name>& scopes, string tag) {
   if (scopes.size() < 2) {
      return;
   }

   for (auto cur = scopes.begin() + 1; cur < scopes.end(); cur++) {
      auto prev = cur - 1;
      FC_ASSERT(*prev != *cur, "${tag} scope \"${scope}\" is not unique", ("tag",tag)("scope",*cur));
      FC_ASSERT(*prev < *cur,  "${tag} scopes are not sorted", ("tag",tag));
   }
}
551

D
Daniel Larimer 已提交
552
void chain_controller::__apply_block(const signed_block& next_block)
N
Nathan Hourt 已提交
553
{ try {
N
Nathan Hourt 已提交
554
   uint32_t skip = _skip_flags;
N
Nathan Hourt 已提交
555

D
Daniel Larimer 已提交
556 557 558
   /*
   FC_ASSERT((skip & skip_merkle_check) 
             || next_block.transaction_merkle_root == next_block.calculate_merkle_root(),
559 560
             "", ("next_block.transaction_merkle_root", next_block.transaction_merkle_root)
             ("calc",next_block.calculate_merkle_root())("next_block",next_block)("id",next_block.id()));
D
Daniel Larimer 已提交
561
             */
N
Nathan Hourt 已提交
562 563

   const producer_object& signing_producer = validate_block_header(skip, next_block);
564

565 566 567 568
   /// regions must be listed in order
   for( uint32_t i = 1; i < next_block.regions.size(); ++i )
      FC_ASSERT( next_block.regions[i-1].region < next_block.regions[i].region );

569 570 571 572 573 574 575

   /// cache the input tranasction ids so that they can be looked up when executing the
   /// summary
   map<transaction_id_type,const signed_transaction*> trx_index;
   for( const auto& t : next_block.input_transactions ) {
      trx_index[t.id()] = &t;
   }
576 577

   block_trace next_block_trace(next_block);
578 579
   next_block_trace.region_traces.reserve(next_block.regions.size());

580
   for( const auto& r : next_block.regions ) {
581 582 583
      region_trace r_trace;
      r_trace.cycle_traces.reserve(r.cycles_summary.size());

584
      for (uint32_t cycle_index = 0; cycle_index < r.cycles_summary.size(); cycle_index++) {
585
         const auto& cycle = r.cycles_summary.at(cycle_index);
586 587 588
         cycle_trace c_trace;
         c_trace.shard_traces.reserve(cycle.size());

589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
         // validate that no read_scope is used as a write scope in this cycle and that no two shards
         // share write scopes
         set<scope_name> read_scopes;
         map<scope_name, uint32_t> write_scopes;

         for (uint32_t shard_index = 0; shard_index < cycle.size(); shard_index++) {
            const auto& shard = cycle.at(shard_index);

            // Validate that the shards scopes are correct and available
            validate_shard_scopes(shard.read_scopes,  "read");
            validate_shard_scopes(shard.write_scopes, "write");

            for (const auto& s: shard.read_scopes) {
               FC_ASSERT(write_scopes.count(s) == 0,
                  "shard ${i} requires read scope \"${s}\" which is locked for write by shard ${j}",
                  ("i", shard_index)("s", s)("j", write_scopes[s]));
               read_scopes.emplace(s);
            }

            for (const auto& s: shard.write_scopes) {
               FC_ASSERT(write_scopes.count(s) == 0,
                  "shard ${i} requires write scope \"${s}\" which is locked for write by shard ${j}",
                  ("i", shard_index)("s", s)("j", write_scopes[s]));
               write_scopes[s] = shard_index;
            }

615
            shard_trace s_trace;
B
Bart Wyatt 已提交
616
            for (const auto& receipt : shard.transactions) {
617
                auto make_metadata = [&](){
618 619
                  auto itr = trx_index.find(receipt.id);
                  if( itr != trx_index.end() ) {
620
                     return transaction_metadata( *itr->second, get_chain_id(), next_block.timestamp );
B
Bart Wyatt 已提交
621
                  } else {
622
                     const auto& gtrx = _db.get<generated_transaction_object,by_trx_id>(receipt.id);
B
Bart Wyatt 已提交
623
                     auto trx = fc::raw::unpack<deferred_transaction>(gtrx.packed_trx.data(), gtrx.packed_trx.size());
624
                     return transaction_metadata(trx, gtrx.published, trx.sender, trx.sender_id, gtrx.packed_trx.data(), gtrx.packed_trx.size() );
625
                  }
626
               };
B
Bart Wyatt 已提交
627

628 629 630 631
               auto mtrx = make_metadata();
               mtrx.region_id = r.region;
               mtrx.cycle_index = cycle_index;
               mtrx.shard_index = shard_index;
B
Bart Wyatt 已提交
632 633
               mtrx.allowed_read_scopes = &shard.read_scopes;
               mtrx.allowed_write_scopes = &shard.write_scopes;
B
Bart Wyatt 已提交
634

635 636 637
               s_trace.transaction_traces.emplace_back(_apply_transaction(mtrx));

               FC_ASSERT(receipt.status == s_trace.transaction_traces.back().status);
B
Bart Wyatt 已提交
638

639 640 641 642 643
               // validate_referenced_accounts(trx);
               // Check authorization, and allow irrelevant signatures.
               // If the block producer let it slide, we'll roll with it.
               // check_transaction_authorization(trx, true);
            } /// for each transaction id
N
Nathan Hourt 已提交
644

645 646 647
            s_trace.calculate_root();
            c_trace.shard_traces.emplace_back(move(s_trace));
         } /// for each shard
D
Daniel Larimer 已提交
648

649 650 651
         _apply_cycle_trace(c_trace);
         r_trace.cycle_traces.emplace_back(move(c_trace));
      } /// for each cycle
D
Daniel Larimer 已提交
652

653 654
      next_block_trace.region_traces.emplace_back(move(r_trace));
   } /// for each region
N
Nathan Hourt 已提交
655

656
   FC_ASSERT(next_block.action_mroot == next_block_trace.calculate_action_merkle_root());
N
Nathan Hourt 已提交
657

658 659
   _finalize_block( next_block_trace );
} FC_CAPTURE_AND_RETHROW( (next_block.block_num()) )  }
D
Daniel Larimer 已提交
660

661
flat_set<public_key_type> chain_controller::get_required_keys(const signed_transaction& trx,
B
Bart Wyatt 已提交
662
                                                              const flat_set<public_key_type>& candidate_keys)const 
D
Daniel Larimer 已提交
663
{
664
   auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
665 666
                                     get_global_properties().configuration.max_authority_depth,
                                     candidate_keys);
667

D
Daniel Larimer 已提交
668 669 670 671
   for (const auto& act : trx.actions ) {
      for (const auto& declared_auth : act.authorization) {
         if (!checker.satisfied(declared_auth)) {
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
672
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
673
                       ("auth", declared_auth));
674 675 676 677 678 679 680
         }
      }
   }

   return checker.used_keys();
}

681
void chain_controller::check_authorization( const vector<action>& actions,
682 683 684
                                            flat_set<public_key_type> provided_keys,
                                            bool allow_unused_signatures,
                                            flat_set<account_name>    provided_accounts  )const
D
Daniel Larimer 已提交
685
{
686
   auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
687
                                     get_global_properties().configuration.max_authority_depth,
688 689
                                     provided_keys, provided_accounts );

N
Nathan Hourt 已提交
690

691
   for( const auto& act : actions ) {
692
      for( const auto& declared_auth : act.authorization ) {
D
Daniel Larimer 已提交
693

694
         // check a minimum permission if one is set, otherwise assume the contract code will validate
B
Bart Wyatt 已提交
695
         auto min_permission_name = lookup_minimum_permission(declared_auth.actor, act.account, act.name);
696 697 698 699 700 701 702 703 704 705 706
         if (min_permission_name) {
            const auto& min_permission = _db.get<permission_object, by_owner>(boost::make_tuple(declared_auth.actor, *min_permission_name));


            if ((_skip_flags & skip_authority_check) == false) {
               const auto &index = _db.get_index<permission_index>().indices();
               EOS_ASSERT(get_permission(declared_auth).satisfies(min_permission, index),
                          tx_irrelevant_auth,
                          "action declares irrelevant authority '${auth}'; minimum authority is ${min}",
                          ("auth", declared_auth)("min", min_permission.name));
            }
N
Nathan Hourt 已提交
707 708
         }
         if ((_skip_flags & skip_transaction_signatures) == false) {
D
Daniel Larimer 已提交
709
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
710
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
711
                       ("auth", declared_auth));
N
Nathan Hourt 已提交
712 713
         }
      }
714
   }
N
Nathan Hourt 已提交
715

716
   if (!allow_unused_signatures && (_skip_flags & skip_transaction_signatures) == false)
717
      EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
718 719
                 "transaction bears irrelevant signatures from these keys: ${keys}", 
                 ("keys", checker.unused_keys()));
N
Nathan Hourt 已提交
720 721
}

722 723 724
void chain_controller::check_transaction_authorization(const signed_transaction& trx, 
                                                       bool allow_unused_signatures)const 
{
725
   check_authorization( trx.actions, trx.get_signature_keys( chain_id_type{} ), allow_unused_signatures );
726 727
}

728
optional<permission_name> chain_controller::lookup_minimum_permission(account_name authorizer_account,
D
Daniel Larimer 已提交
729 730
                                                                    account_name scope,
                                                                    action_name act_name) const {
731 732 733 734 735 736
   // updateauth is a special case where any permission _may_ be suitable depending
   // on the contents of the action
   if (scope == config::system_account_name && act_name == N(updateauth)) {
      return optional<permission_name>();
   }

N
Nathan Hourt 已提交
737
   try {
D
Daniel Larimer 已提交
738 739 740
      // First look up a specific link for this message act_name
      auto key = boost::make_tuple(authorizer_account, scope, act_name);
      auto link = _db.find<permission_link_object, by_action_name>(key);
741 742 743
      // If no specific link found, check for a contract-wide default
      if (link == nullptr) {
         get<2>(key) = "";
D
Daniel Larimer 已提交
744
         link = _db.find<permission_link_object, by_action_name>(key);
745 746 747 748
      }

      // If no specific or default link found, use active permission
      if (link != nullptr)
749 750 751
         return link->required_permission;
      else
         return N(active);
D
Daniel Larimer 已提交
752
   } FC_CAPTURE_AND_RETHROW((authorizer_account)(scope)(act_name))
N
Nathan Hourt 已提交
753 754
}

D
Daniel Larimer 已提交
755
void chain_controller::validate_uniqueness( const signed_transaction& trx )const {
N
Nathan Hourt 已提交
756
   if( !should_check_for_duplicate_transactions() ) return;
N
Nathan Hourt 已提交
757

N
Nathan Hourt 已提交
758
   auto transaction = _db.find<transaction_object, by_trx_id>(trx.id());
D
Daniel Larimer 已提交
759
   EOS_ASSERT(transaction == nullptr, tx_duplicate, "transaction is not unique");
760
}
761

762
void chain_controller::record_transaction(const transaction& trx) {
763 764
   //Insert transaction into unique transactions database.
    _db.create<transaction_object>([&](transaction_object& transaction) {
D
Daniel Larimer 已提交
765 766
        transaction.trx_id = trx.id(); 
        transaction.expiration = trx.expiration;
767 768 769 770
    });
}


D
Daniel Larimer 已提交
771
void chain_controller::validate_tapos(const transaction& trx)const {
N
Nathan Hourt 已提交
772
   if (!should_check_tapos()) return;
773

D
Daniel Larimer 已提交
774
   const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.ref_block_num);
775 776

   //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
D
Daniel Larimer 已提交
777
   EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), transaction_exception,
D
Daniel Larimer 已提交
778
              "transaction's reference block did not match. Is this transaction from a different fork?",
N
Nathan Hourt 已提交
779 780
              ("tapos_summary", tapos_block_summary));
}
781

D
Daniel Larimer 已提交
782 783 784
void chain_controller::validate_referenced_accounts( const transaction& trx )const 
{ try { 
   for( const auto& act : trx.actions ) {
B
Bart Wyatt 已提交
785
      require_account(act.account);
D
Daniel Larimer 已提交
786
      for (const auto& auth : act.authorization )
D
Daniel Larimer 已提交
787
         require_account(auth.actor);
788
   }
D
Daniel Larimer 已提交
789
} FC_CAPTURE_AND_RETHROW() }
D
Daniel Larimer 已提交
790

D
Daniel Larimer 已提交
791
void chain_controller::validate_expiration( const transaction& trx ) const
792
{ try {
D
Daniel Larimer 已提交
793
   fc::time_point now = head_block_time();
D
Daniel Larimer 已提交
794
   const auto& chain_configuration = get_global_properties().configuration;
795

D
Daniel Larimer 已提交
796
   EOS_ASSERT( time_point(trx.expiration) <= now + fc::seconds(chain_configuration.max_transaction_lifetime),
D
Daniel Larimer 已提交
797
              transaction_exception, "transaction expiration is too far in the future",
798
              ("trx.expiration",trx.expiration)("now",now)
D
Daniel Larimer 已提交
799 800
              ("max_til_exp",chain_configuration.max_transaction_lifetime));
   EOS_ASSERT( now <= time_point(trx.expiration), transaction_exception, "transaction is expired",
801 802
              ("now",now)("trx.exp",trx.expiration));
} FC_CAPTURE_AND_RETHROW((trx)) }
803

804

805 806
void chain_controller::require_scope( const scope_name& scope )const {
   switch( uint64_t(scope) ) {
807 808
      case config::eosio_all_scope:
      case config::eosio_auth_scope:
809 810 811 812 813 814
         return; /// built in scopes
      default:
         require_account(scope);
   }
}

D
Daniel Larimer 已提交
815
void chain_controller::require_account(const account_name& name) const {
N
Nathan Hourt 已提交
816 817 818
   auto account = _db.find<account_object, by_name>(name);
   FC_ASSERT(account != nullptr, "Account not found: ${name}", ("name", name));
}
N
Nathan Hourt 已提交
819

820
const producer_object& chain_controller::validate_block_header(uint32_t skip, const signed_block& next_block)const {
821 822
   EOS_ASSERT(head_block_id() == next_block.previous, block_validate_exception, "",
              ("head_block_id",head_block_id())("next.prev",next_block.previous));
D
Daniel Larimer 已提交
823
   EOS_ASSERT(head_block_time() < (fc::time_point)next_block.timestamp, block_validate_exception, "",
824
              ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()));
K
Kevin Heifner 已提交
825
   if (((fc::time_point)next_block.timestamp) > head_block_time() + fc::microseconds(config::block_interval_ms*1000)) {
826
      elog("head_block_time ${h}, next_block ${t}, block_interval ${bi}",
827 828 829
           ("h", head_block_time())("t", next_block.timestamp)("bi", config::block_interval_ms));
      elog("Did not produce block within block_interval ${bi}ms, took ${t}ms)",
           ("bi", config::block_interval_ms)("t", (time_point(next_block.timestamp) - head_block_time()).count() / 1000));
830
   }
D
Daniel Larimer 已提交
831 832
   if (next_block.block_num() % config::blocks_per_round != 0) {
      EOS_ASSERT(!next_block.new_producers, block_validate_exception,
833
                 "Producer changes may only occur at the end of a round.");
N
Nathan Hourt 已提交
834
   }
D
Daniel Larimer 已提交
835 836
   
   const producer_object& producer = get_producer(get_scheduled_producer(get_slot_at_time(next_block.timestamp)));
N
Nathan Hourt 已提交
837

N
Nathan Hourt 已提交
838
   if(!(skip&skip_producer_signature))
839 840 841
      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 已提交
842

843
   if(!(skip&skip_producer_schedule_check)) {
844 845 846
      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 已提交
847 848
   }

849 850 851
   
   FC_ASSERT( next_block.calculate_transaction_merkle_root() == next_block.transaction_mroot, "merkle root does not match" );

N
Nathan Hourt 已提交
852 853 854
   return producer;
}

855
void chain_controller::create_block_summary(const signed_block& next_block) {
856
   auto sid = next_block.block_num() & 0xffff;
857
   _db.modify( _db.get<block_summary_object,by_id>(sid), [&](block_summary_object& p) {
858 859
         p.block_id = next_block.id();
   });
N
Nathan Hourt 已提交
860 861
}

862 863 864 865 866 867 868 869 870
/**
 *  Takes the top config::producer_count producers by total vote excluding any producer whose
 *  block_signing_key is null.  
 */
producer_schedule_type chain_controller::_calculate_producer_schedule()const {
   const auto& producers_by_vote = _db.get_index<contracts::producer_votes_multi_index,contracts::by_votes>();
   auto itr = producers_by_vote.begin();
   producer_schedule_type schedule;
   uint32_t count = 0;
871 872 873
   while( itr != producers_by_vote.end() && count < schedule.producers.size() ) {
      schedule.producers[count].producer_name = itr->owner_name;
      schedule.producers[count].block_signing_key = get_producer(itr->owner_name).signing_key;
874
      ++itr;
875
      if( schedule.producers[count].block_signing_key != public_key_type() ) {
876 877 878
         ++count;
      }
   }
879 880 881 882
   const auto& hps = _head_producer_schedule();
   schedule.version = hps.version;
   if( hps != schedule )
      ++schedule.version;
883 884 885 886 887 888 889 890 891 892 893 894 895
   return schedule;
}

/**
 *  Returns the most recent and/or pending producer schedule
 */
const producer_schedule_type& chain_controller::_head_producer_schedule()const {
   const auto& gpo = get_global_properties();
   if( gpo.pending_active_producers.size() ) 
      return gpo.pending_active_producers.back().second;
   return gpo.active_producers;
}

896
void chain_controller::update_global_properties(const signed_block& b) { try {
897 898
   // If we're at the end of a round, update the BlockchainConfiguration, producer schedule
   // and "producers" special account authority
899 900 901 902 903
   if( is_start_of_round( b.block_num() ) ) {
      auto schedule = _calculate_producer_schedule();
      if( b.new_producers )
      {
          FC_ASSERT( schedule == *b.new_producers, "pending producer set different than expected" );
904 905 906
      }

      const auto& gpo = get_global_properties();
907 908 909

      if( _head_producer_schedule() != schedule ) {
         FC_ASSERT( b.new_producers, "pending producer set changed but block didn't indicate it" );
910
      }
911 912 913 914 915 916 917 918
      _db.modify( gpo, [&]( auto& props ) {
         if( props.pending_active_producers.size() && props.pending_active_producers.back().first == b.block_num() )
            props.pending_active_producers.back().second = schedule;
         else
            props.pending_active_producers.push_back( make_pair(b.block_num(),schedule) );
      });


919

920
      auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
921
      for(auto& name : gpo.active_producers.producers ) {
922
         active_producers_authority.accounts.push_back({{name.producer_name, config::active_name}, 1});
923 924
      }

D
Daniel Larimer 已提交
925
      auto& po = _db.get<permission_object, by_owner>( boost::make_tuple(config::producers_account_name, 
926
                                                                         config::active_name ) );
927 928 929
      _db.modify(po,[active_producers_authority] (permission_object& po) {
         po.auth = active_producers_authority;
      });
930
   }
931
} FC_CAPTURE_AND_RETHROW() } 
932

933
void chain_controller::add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts ) {
934
   for (const auto& i : checkpts)
N
Nathan Hourt 已提交
935 936 937
      _checkpoints[i.first] = i.second;
}

938
bool chain_controller::before_last_checkpoint()const {
N
Nathan Hourt 已提交
939 940 941
   return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
}

942
const global_property_object& chain_controller::get_global_properties()const {
943
   return _db.get<global_property_object>();
N
Nathan Hourt 已提交
944 945
}

946
const dynamic_global_property_object&chain_controller::get_dynamic_global_properties() const {
947
   return _db.get<dynamic_global_property_object>();
N
Nathan Hourt 已提交
948 949
}

D
Daniel Larimer 已提交
950
time_point chain_controller::head_block_time()const {
N
Nathan Hourt 已提交
951 952 953
   return get_dynamic_global_properties().time;
}

954
uint32_t chain_controller::head_block_num()const {
N
Nathan Hourt 已提交
955 956 957
   return get_dynamic_global_properties().head_block_number;
}

958
block_id_type chain_controller::head_block_id()const {
N
Nathan Hourt 已提交
959 960 961
   return get_dynamic_global_properties().head_block_id;
}

D
Daniel Larimer 已提交
962
account_name chain_controller::head_block_producer() const {
963 964 965
   auto b = _fork_db.fetch_block(head_block_id());
   if( b ) return b->data.producer;

N
Nathan Hourt 已提交
966
   if (auto head_block = fetch_block_by_id(head_block_id()))
967
      return head_block->producer;
N
Nathan Hourt 已提交
968 969 970
   return {};
}

D
Daniel Larimer 已提交
971 972
const producer_object& chain_controller::get_producer(const account_name& owner_name) const 
{ try {
B
Bart Wyatt 已提交
973
   return _db.get<producer_object, by_owner>(owner_name);
D
Daniel Larimer 已提交
974
} FC_CAPTURE_AND_RETHROW( (owner_name) ) }
N
Nathan Hourt 已提交
975

976 977 978 979 980
const permission_object&   chain_controller::get_permission( const permission_level& level )const 
{ try {
   return _db.get<permission_object, by_owner>( boost::make_tuple(level.actor,level.permission) );
} FC_CAPTURE_AND_RETHROW( (level) ) }

981
uint32_t chain_controller::last_irreversible_block_num() const {
N
Nathan Hourt 已提交
982
   return get_dynamic_global_properties().last_irreversible_block_num;
N
Nathan Hourt 已提交
983 984
}

D
Daniel Larimer 已提交
985
void chain_controller::_initialize_indexes() {
986 987
   _db.add_index<account_index>();
   _db.add_index<permission_index>();
988
   _db.add_index<permission_usage_index>();
989
   _db.add_index<permission_link_index>();
990
   _db.add_index<action_permission_index>();
991 992 993 994 995
   _db.add_index<contracts::table_id_multi_index>();
   _db.add_index<contracts::key_value_index>();
   _db.add_index<contracts::keystr_value_index>();
   _db.add_index<contracts::key128x128_value_index>();
   _db.add_index<contracts::key64x64x64_value_index>();
996 997 998 999 1000

   _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>();
1001
   _db.add_index<generated_transaction_multi_index>();
1002
   _db.add_index<producer_multi_index>();
1003
   _db.add_index<scope_sequence_multi_index>();
1004 1005
   _db.add_index<bandwidth_usage_index>();
   _db.add_index<compute_usage_index>();
N
Nathan Hourt 已提交
1006 1007
}

D
Daniel Larimer 已提交
1008
void chain_controller::_initialize_chain(contracts::chain_initializer& starter)
N
Nathan Hourt 已提交
1009
{ try {
1010
   if (!_db.find<global_property_object>()) {
N
Nathan Hourt 已提交
1011 1012
      _db.with_write_lock([this, &starter] {
         auto initial_timestamp = starter.get_chain_start_time();
D
Daniel Larimer 已提交
1013 1014 1015
         FC_ASSERT(initial_timestamp != time_point(), "Must initialize genesis timestamp." );
         FC_ASSERT( block_timestamp_type(initial_timestamp) == initial_timestamp,
                    "Genesis timestamp must be divisible by config::block_interval_ms" );
N
Nathan Hourt 已提交
1016

1017
         // Create global properties
1018
         const auto& gp = _db.create<global_property_object>([&starter](global_property_object& p) {
N
Nathan Hourt 已提交
1019 1020
            p.configuration = starter.get_chain_start_configuration();
            p.active_producers = starter.get_chain_start_producers();
1021
         });
1022

1023
         _db.create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
N
Nathan Hourt 已提交
1024
            p.time = initial_timestamp;
1025
            p.recent_slots_filled = uint64_t(-1);
1026 1027
            p.virtual_net_bandwidth = gp.configuration.max_block_size * (config::blocksize_average_window_ms / config::block_interval_ms );
            p.virtual_act_bandwidth = gp.configuration.max_block_acts * (config::blocksize_average_window_ms / config::block_interval_ms );
1028
         });
N
Nathan Hourt 已提交
1029

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

D
Daniel Larimer 已提交
1034 1035
         auto acts = starter.prepare_database(*this, _db);

D
Daniel Larimer 已提交
1036
         transaction genesis_setup_transaction;
D
Daniel Larimer 已提交
1037 1038 1039
         genesis_setup_transaction.actions = move(acts);

         ilog( "applying genesis transaction" );
1040
         with_skip_flags(skip_scope_check | skip_transaction_signatures | skip_authority_check | received_block | genesis_setup, 
D
Daniel Larimer 已提交
1041
         [&](){ 
1042
            transaction_metadata tmeta( genesis_setup_transaction );
1043
            __apply_transaction( tmeta );
1044
         });
1045
         ilog( "done applying genesis transaction" );
1046 1047
      });
   }
N
Nathan Hourt 已提交
1048 1049
} FC_CAPTURE_AND_RETHROW() }

N
Nathan Hourt 已提交
1050

1051
void chain_controller::replay() {
1052
   ilog("Replaying blockchain");
N
Nathan Hourt 已提交
1053
   auto start = fc::time_point::now();
K
Kevin Heifner 已提交
1054

K
Kevin Heifner 已提交
1055
   auto on_exit = fc::make_scoped_exit([&_currently_replaying_blocks = _currently_replaying_blocks](){
K
Kevin Heifner 已提交
1056 1057 1058 1059
      _currently_replaying_blocks = false;
   });
   _currently_replaying_blocks = true;

1060 1061 1062
   auto last_block = _block_log.read_head();
   if (!last_block) {
      elog("No blocks in block log; skipping replay");
N
Nathan Hourt 已提交
1063 1064 1065 1066 1067
      return;
   }

   const auto last_block_num = last_block->block_num();

1068
   ilog("Replaying ${n} blocks...", ("n", last_block_num) );
1069 1070 1071 1072 1073
   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));
D
Daniel Larimer 已提交
1074
      _apply_block(*block, skip_producer_signature |
N
Nathan Hourt 已提交
1075 1076 1077 1078
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_producer_schedule_check |
1079 1080
                          skip_authority_check |
                          received_block);
N
Nathan Hourt 已提交
1081 1082
   }
   auto end = fc::time_point::now();
1083 1084
   ilog("Done replaying ${n} blocks, elapsed time: ${t} sec",
        ("n", head_block_num())("t",double((end-start).count())/1000000.0));
N
Nathan Hourt 已提交
1085

1086
   _db.set_revision(head_block_num());
1087
}
N
Nathan Hourt 已提交
1088

D
Daniel Larimer 已提交
1089
void chain_controller::_spinup_db() {
1090 1091 1092 1093 1094
   // Rewind the database to the last irreversible block
   _db.with_write_lock([&] {
      _db.undo_all();
      FC_ASSERT(_db.revision() == head_block_num(), "Chainbase revision does not match head block num",
                ("rev", _db.revision())("head_block", head_block_num()));
1095

1096 1097
   });
}
N
Nathan Hourt 已提交
1098

D
Daniel Larimer 已提交
1099
void chain_controller::_spinup_fork_db()
N
Nathan Hourt 已提交
1100
{
1101 1102 1103 1104 1105 1106 1107 1108
   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 已提交
1109 1110
}

D
Daniel Larimer 已提交
1111
/*
1112 1113
ProducerRound chain_controller::calculate_next_round(const signed_block& next_block) {
   auto schedule = _admin->get_next_round(_db);
N
Nathan Hourt 已提交
1114 1115 1116 1117
   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));
P
Pravin 已提交
1118 1119 1120
   
   fc::time_point tp = (fc::time_point)next_block.timestamp;
   utilities::rand::random rng(tp.sec_since_epoch());
1121 1122
   rng.shuffle(schedule);
   return schedule;
D
Daniel Larimer 已提交
1123
}*/
1124

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

1128 1129 1130
   const auto& bmroot = _dgp.block_merkle_root.get_root();
   FC_ASSERT( bmroot == b.block_mroot, "block merkle root does not match expected value" );

P
Pravin 已提交
1131
   uint32_t missed_blocks = head_block_num() == 0? 1 : get_slot_at_time((fc::time_point)b.timestamp);
1132
   assert(missed_blocks != 0);
N
Nathan Hourt 已提交
1133
   missed_blocks--;
N
Nathan Hourt 已提交
1134

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

1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
   if (!(_skip_flags & skip_missed_block_penalty)) {
      for (uint32_t i = 0; i < missed_blocks; ++i) {
         const auto &producer_missed = get_producer(get_scheduled_producer(i + 1));
         if (producer_missed.owner != b.producer) {
            /*
            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) );
               */

            _db.modify(producer_missed, [&](producer_object &w) {
               w.total_missed++;
            });
         }
N
Nathan Hourt 已提交
1152 1153 1154
      }
   }

1155 1156
   const auto& props = get_global_properties();

N
Nathan Hourt 已提交
1157
   // dynamic global properties updating
1158
   _db.modify( _dgp, [&]( dynamic_global_property_object& dgp ){
N
Nathan Hourt 已提交
1159 1160 1161
      dgp.head_block_number = b.block_num();
      dgp.head_block_id = b.id();
      dgp.time = b.timestamp;
1162
      dgp.current_producer = b.producer;
N
Nathan Hourt 已提交
1163
      dgp.current_absolute_slot += missed_blocks+1;
1164 1165 1166 1167 1168
      dgp.average_block_size.add_usage( fc::raw::pack_size(b), b.timestamp );

      dgp.update_virtual_net_bandwidth( props.configuration );
      dgp.update_virtual_act_bandwidth( props.configuration );

N
Nathan Hourt 已提交
1169 1170 1171 1172 1173 1174

      // 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;
1175 1176 1177 1178 1179
      } else
         if(config::percent_100 * get_global_properties().active_producers.producers.size() / config::blocks_per_round > config::required_producer_participation)
            dgp.recent_slots_filled = uint64_t(-1);
         else
            dgp.recent_slots_filled = 0;
1180
      dgp.block_merkle_root.append( head_block_id() ); 
N
Nathan Hourt 已提交
1181 1182 1183 1184 1185
   });

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

1186
void chain_controller::update_signing_producer(const producer_object& signing_producer, const signed_block& new_block)
N
Nathan Hourt 已提交
1187 1188
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
P
Pravin 已提交
1189
   uint64_t new_block_aslot = dpo.current_absolute_slot + get_slot_at_time( (fc::time_point)new_block.timestamp );
N
Nathan Hourt 已提交
1190

1191
   _db.modify( signing_producer, [&]( producer_object& _wit )
N
Nathan Hourt 已提交
1192 1193 1194 1195 1196 1197
   {
      _wit.last_aslot = new_block_aslot;
      _wit.last_confirmed_block_num = new_block.block_num();
   } );
}

1198
void chain_controller::update_last_irreversible_block()
N
Nathan Hourt 已提交
1199 1200 1201 1202
{
   const global_property_object& gpo = get_global_properties();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();

N
Nathan Hourt 已提交
1203
   vector<const producer_object*> producer_objs;
1204
   producer_objs.reserve(gpo.active_producers.producers.size());
D
Daniel Larimer 已提交
1205

1206
   std::transform(gpo.active_producers.producers.begin(), gpo.active_producers.producers.end(), std::back_inserter(producer_objs),
D
Daniel Larimer 已提交
1207
                  [this](const producer_key& pk) { return &get_producer(pk.producer_name); });
N
Nathan Hourt 已提交
1208

D
Daniel Larimer 已提交
1209
   static_assert(config::irreversible_threshold_percent > 0, "irreversible threshold must be nonzero");
N
Nathan Hourt 已提交
1210

D
Daniel Larimer 已提交
1211
   size_t offset = EOS_PERCENT(producer_objs.size(), config::percent_100- config::irreversible_threshold_percent);
1212 1213
   std::nth_element(producer_objs.begin(), producer_objs.begin() + offset, producer_objs.end(),
      [](const producer_object* a, const producer_object* b) {
N
Nathan Hourt 已提交
1214
         return a->last_confirmed_block_num < b->last_confirmed_block_num;
1215
      });
N
Nathan Hourt 已提交
1216

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

1219
   if (new_last_irreversible_block_num > dpo.last_irreversible_block_num) {
1220
      _db.modify(dpo, [&](dynamic_global_property_object& _dpo) {
N
Nathan Hourt 已提交
1221
         _dpo.last_irreversible_block_num = new_last_irreversible_block_num;
1222
      });
N
Nathan Hourt 已提交
1223
   }
1224 1225

   // Write newly irreversible blocks to disk. First, get the number of the last block on disk...
1226
   auto old_last_irreversible_block = _block_log.head();
1227 1228 1229 1230
   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();
1231

1232
   if (last_block_on_disk < new_last_irreversible_block_num) {
1233 1234 1235 1236 1237
      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);
1238
         _block_log.append(*block);
K
Kevin Heifner 已提交
1239
         applied_irreversible_block(*block);
1240
      }
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258
   }

   if( new_last_irreversible_block_num > last_block_on_disk ) {
      /// TODO: use upper / lower bound to find
      optional<producer_schedule_type> new_producer_schedule;
      for( const auto& item : gpo.pending_active_producers ) {
         if( item.first < new_last_irreversible_block_num ) {
            new_producer_schedule = item.second;
         }
      }
      if( new_producer_schedule ) {
         _db.modify( gpo, [&]( auto& props ){
             /// TODO: use upper / lower bound to remove range
              while( gpo.pending_active_producers.size() ) {
                 if( gpo.pending_active_producers.front().first < new_last_irreversible_block_num ) {
                   props.pending_active_producers.erase(props.pending_active_producers.begin());
                 }
              }
1259
              props.active_producers = *new_producer_schedule;
1260 1261 1262 1263
         });
      }
   }

N
Nathan Hourt 已提交
1264 1265 1266

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

1270
void chain_controller::clear_expired_transactions()
N
Nathan Hourt 已提交
1271 1272
{ try {
   //Look for expired transactions in the deduplication list, and remove them.
D
Daniel Larimer 已提交
1273
   //transactions must have expired by at least two forking windows in order to be removed.
D
Daniel Larimer 已提交
1274
   /*
1275
   auto& transaction_idx = _db.get_mutable_index<transaction_multi_index>();
N
Nathan Hourt 已提交
1276
   const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
D
Daniel Larimer 已提交
1277
   while( (!dedupe_index.empty()) && (head_block_time() > dedupe_index.rbegin()->expiration) )
N
Nathan Hourt 已提交
1278
      transaction_idx.remove(*dedupe_index.rbegin());
B
Bart Wyatt 已提交
1279
      */
1280
   //Look for expired transactions in the pending generated list, and remove them.
D
Daniel Larimer 已提交
1281
   //transactions must have expired by at least two forking windows in order to be removed.
1282
   auto& generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
B
Bart Wyatt 已提交
1283 1284
   const auto& generated_index = generated_transaction_idx.indices().get<by_expiration>();
   while( (!generated_index.empty()) && (head_block_time() > generated_index.rbegin()->expiration) )
1285
      generated_transaction_idx.remove(*generated_index.rbegin());
B
Bart Wyatt 已提交
1286

N
Nathan Hourt 已提交
1287 1288 1289 1290
} FC_CAPTURE_AND_RETHROW() }

using boost::container::flat_set;

D
Daniel Larimer 已提交
1291
account_name chain_controller::get_scheduled_producer(uint32_t slot_num)const
N
Nathan Hourt 已提交
1292 1293
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
N
Nathan Hourt 已提交
1294
   uint64_t current_aslot = dpo.current_absolute_slot + slot_num;
1295
   const auto& gpo = _db.get<global_property_object>();
D
Daniel Larimer 已提交
1296 1297 1298 1299
   //auto number_of_active_producers = gpo.active_producers.size();
   auto index = current_aslot % (config::blocks_per_round); //TODO configure number of repetitions by producer
   index /= config::producer_repititions;

1300
   return gpo.active_producers.producers[index].producer_name;
N
Nathan Hourt 已提交
1301 1302
}

D
Daniel Larimer 已提交
1303
block_timestamp_type chain_controller::get_slot_time(uint32_t slot_num)const
N
Nathan Hourt 已提交
1304
{
P
Pravin 已提交
1305
   if( slot_num == 0)
D
Daniel Larimer 已提交
1306
      return block_timestamp_type();
N
Nathan Hourt 已提交
1307 1308 1309 1310 1311 1312

   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
P
Pravin 已提交
1313 1314 1315
      auto genesis_time = block_timestamp_type(dpo.time);
      genesis_time.slot += slot_num;
      return (fc::time_point)genesis_time;
N
Nathan Hourt 已提交
1316 1317
   }

D
Daniel Larimer 已提交
1318
   auto head_block_abs_slot = block_timestamp_type(head_block_time());
P
Pravin 已提交
1319
   head_block_abs_slot.slot += slot_num;
D
Daniel Larimer 已提交
1320
   return head_block_abs_slot;
N
Nathan Hourt 已提交
1321 1322
}

D
Daniel Larimer 已提交
1323
uint32_t chain_controller::get_slot_at_time( block_timestamp_type when )const
N
Nathan Hourt 已提交
1324
{
D
Daniel Larimer 已提交
1325
   auto first_slot_time = get_slot_time(1);
N
Nathan Hourt 已提交
1326 1327
   if( when < first_slot_time )
      return 0;
D
Daniel Larimer 已提交
1328
   return block_timestamp_type(when).slot - first_slot_time.slot + 1;
N
Nathan Hourt 已提交
1329 1330
}

1331
uint32_t chain_controller::producer_participation_rate()const
N
Nathan Hourt 已提交
1332 1333
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
D
Daniel Larimer 已提交
1334
   return uint64_t(config::percent_100) * __builtin_popcountll(dpo.recent_slots_filled) / 64;
N
Nathan Hourt 已提交
1335 1336
}

D
Daniel Larimer 已提交
1337 1338
void chain_controller::_set_apply_handler( account_name contract, scope_name scope, action_name action, apply_handler v ) {
   _apply_handlers[contract][make_pair(scope,action)] = v;
1339
}
N
Nathan Hourt 已提交
1340

1341
static void log_handled_exceptions(const transaction& trx) {
B
Bart Wyatt 已提交
1342 1343 1344 1345
   try {
      throw;
   } catch (const checktime_exceeded&) {
      throw;
1346
   } FC_CAPTURE_AND_LOG((trx));
B
Bart Wyatt 已提交
1347 1348
}

1349 1350 1351
transaction_trace chain_controller::__apply_transaction( transaction_metadata& meta ) {
   transaction_trace result(meta.id);
   for (const auto &act : meta.trx.actions) {
B
Bart Wyatt 已提交
1352
      apply_context context(*this, _db, act, meta);
1353 1354 1355
      context.exec();
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
1356
      fc::move_append(result.canceled_deferred, std::move(context.results.canceled_deferred));
B
Bart Wyatt 已提交
1357 1358
      move_append_names(result.read_scopes, std::forward<vector<scope_name>>(context.results.read_scopes));
      move_append_names(result.write_scopes, std::forward<vector<scope_name>>(context.results.write_scopes));
1359
   }
B
Bart Wyatt 已提交
1360

1361
   uint32_t act_usage = result.action_traces.size();
1362

1363 1364 1365 1366
   for (auto &at: result.action_traces) {
      at.region_id = meta.region_id;
      at.cycle_index = meta.cycle_index;
      if (at.receiver == config::system_account_name &&
B
Bart Wyatt 已提交
1367
          at.act.account == config::system_account_name &&
1368 1369
          at.act.name == N(setcode)) {
         act_usage += config::setcode_act_usage;
B
Bart Wyatt 已提交
1370
      }
1371
   }
B
Bart Wyatt 已提交
1372

1373
   update_usage(meta, act_usage);
1374
   record_transaction(meta.trx);
1375 1376
   return result;
}
B
Bart Wyatt 已提交
1377

1378 1379 1380 1381 1382 1383
transaction_trace chain_controller::_apply_transaction( transaction_metadata& meta ) {
   try {
      auto temp_session = _db.start_undo_session(true);
      auto result = __apply_transaction(meta);
      temp_session.squash();
      return result;
B
Bart Wyatt 已提交
1384 1385
   } catch (...) {
      // if there is no sender, there is no error handling possible, rethrow
1386
      if (!meta.sender) {
B
Bart Wyatt 已提交
1387 1388
         throw;
      }
1389 1390
      // log exceptions we can handle with the error handle, throws otherwise
      log_handled_exceptions(meta.trx);
1391

B
Bart Wyatt 已提交
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404
      return _apply_error( meta );
   }
}

transaction_trace chain_controller::_apply_error( transaction_metadata& meta ) {
   transaction_trace result(meta.id);
   result.status = transaction_trace::soft_fail;

   transaction etrx;
   etrx.actions.emplace_back(vector<permission_level>{{meta.sender_id,config::active_name}},
                             contracts::onerror(meta.generated_data, meta.generated_data + meta.generated_size) );

   try {
1405 1406
      auto temp_session = _db.start_undo_session(true);

B
Bart Wyatt 已提交
1407
      apply_context context(*this, _db, etrx.actions.front(), meta);
D
Daniel Larimer 已提交
1408
      context.exec();
1409
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
B
Bart Wyatt 已提交
1410
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
B
Bart Wyatt 已提交
1411 1412
      move_append_names(result.read_scopes, std::forward<vector<scope_name>>(context.results.read_scopes));
      move_append_names(result.write_scopes, std::forward<vector<scope_name>>(context.results.write_scopes));
B
Bart Wyatt 已提交
1413

B
Bart Wyatt 已提交
1414
      uint32_t act_usage = result.action_traces.size();
1415

B
Bart Wyatt 已提交
1416 1417 1418
      for (auto &at: result.action_traces) {
         at.region_id = meta.region_id;
         at.cycle_index = meta.cycle_index;
1419
      }
1420

B
Bart Wyatt 已提交
1421 1422
      update_usage(meta, act_usage);
      record_transaction(meta.trx);
1423 1424

      temp_session.squash();
B
Bart Wyatt 已提交
1425
      return result;
1426

B
Bart Wyatt 已提交
1427
   } catch (...) {
1428 1429 1430 1431
      // log exceptions we can handle with the error handle, throws otherwise
      log_handled_exceptions(etrx);

      // fall through to marking this tx as hard-failing
B
Bart Wyatt 已提交
1432 1433 1434 1435
   }

   // if we have an objective error, on an error handler, we return hard fail for the trx
   result.status = transaction_trace::hard_fail;
1436 1437 1438
   return result;
}

1439
void chain_controller::push_deferred_transactions( bool flush )
B
Bart Wyatt 已提交
1440
{
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457
   if (flush && _pending_cycle_trace && _pending_cycle_trace->shard_traces.size() > 0) {
      // TODO: when we go multithreaded this will need a better way to see if there are flushable
      // deferred transactions in the shards
      auto maybe_start_new_cycle = [&]() {
         for (const auto &st: _pending_cycle_trace->shard_traces) {
            for (const auto &tr: st.transaction_traces) {
               for (const auto &dt: tr.deferred_transactions) {
                  if (fc::time_point(dt.execute_after) <= head_block_time()) {
                     // force a new cycle and break out
                     _finalize_pending_cycle();
                     _start_pending_cycle();
                     return;
                  }
               }
            }
         }
      };
B
Bart Wyatt 已提交
1458

1459 1460
      maybe_start_new_cycle();
   }
B
Bart Wyatt 已提交
1461

1462 1463 1464
   auto& generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
   auto& generated_index = generated_transaction_idx.indices().get<by_delay>();
   vector<const generated_transaction_object*> candidates;
B
Bart Wyatt 已提交
1465

1466 1467 1468 1469
   for( auto itr = generated_index.rbegin(); itr != generated_index.rend() && (head_block_time() >= itr->delay_until); ++itr) {
      const auto &gtrx = *itr;
      candidates.emplace_back(&gtrx);
   }
B
Bart Wyatt 已提交
1470

1471 1472 1473 1474
   for (const auto* trx_p: candidates) {
      if (!is_known_transaction(trx_p->trx_id)) {
         try {
            auto trx = fc::raw::unpack<deferred_transaction>(trx_p->packed_trx.data(), trx_p->packed_trx.size());
1475
            transaction_metadata mtrx (trx, trx_p->published, trx.sender, trx.sender_id, trx_p->packed_trx.data(), trx_p->packed_trx.size());
1476 1477 1478 1479 1480 1481
            _push_transaction(mtrx);
            generated_transaction_idx.remove(*trx_p);
         } FC_CAPTURE_AND_LOG((trx_p->trx_id)(trx_p->sender));
      } else {
         generated_transaction_idx.remove(*trx_p);
      }
B
Bart Wyatt 已提交
1482 1483 1484 1485
   }
}


1486 1487 1488 1489 1490
/**
 *  @param act_usage The number of "actions" delivered directly or indirectly by applying meta.trx
 */
void chain_controller::update_usage( transaction_metadata& meta, uint32_t act_usage )
{
1491
   set<std::pair<account_name, permission_name>> authorizing_accounts;
1492

1493
   for( const auto& act : meta.trx.actions )
1494
      for( const auto& auth : act.authorization )
1495
         authorizing_accounts.emplace( auth.actor, auth.permission );
1496

1497 1498 1499
   auto trx_size = meta.bandwidth_usage + config::fixed_bandwidth_overhead_per_transaction;

   const auto& dgpo = get_dynamic_global_properties();
1500

1501 1502 1503 1504
   if( meta.signing_keys ) {
      act_usage += meta.signing_keys->size();
   }

1505 1506
   auto head_time = head_block_time();
   for( const auto& authaccnt : authorizing_accounts ) {
1507
      const auto& buo = _db.get<bandwidth_usage_object,by_owner>( authaccnt.first );
1508
      _db.modify( buo, [&]( auto& bu ){
1509
          bu.bytes.add_usage( trx_size, head_time );
1510
          bu.acts.add_usage( act_usage, head_time );
1511
      });
1512
      const auto& sbo = _db.get<contracts::staked_balance_object, contracts::by_owner_name>(authaccnt.first);
1513 1514
      // TODO enable this after fixing divide by 0 with virtual_net_bandwidth and total_staked_tokens
      /// note: buo.bytes.value is in ubytes and virtual_net_bandwidth is in bytes, so
1515 1516 1517
      //  we convert to fixed int uin128_t with 60 bits of precision, divide by rate limiting precision
      //  then divide by virtual max_block_size which gives us % of virtual max block size in fixed width

1518 1519 1520 1521 1522 1523 1524 1525
      uint128_t  used_ubytes        = buo.bytes.value;
      uint128_t  used_uacts         = buo.acts.value;
      uint128_t  virtual_max_ubytes = dgpo.virtual_net_bandwidth * config::rate_limiting_precision;
      uint128_t  virtual_max_uacts  = dgpo.virtual_act_bandwidth * config::rate_limiting_precision;
      uint64_t   user_stake         = sbo.staked_balance;
      
      if( !(_skip_flags & genesis_setup) ) {
         FC_ASSERT( (used_ubytes * dgpo.total_staked_tokens) <=  (user_stake * virtual_max_ubytes), "authorizing account '${n}' has insufficient net bandwidth for this transaction",
1526
                    ("n",name(authaccnt.first))
1527 1528 1529 1530 1531 1532
                    ("used_bytes",double(used_ubytes)/1000000.)
                    ("user_stake",user_stake)
                    ("virtual_max_bytes", double(virtual_max_ubytes)/1000000. )
                    ("total_staked_tokens", dgpo.total_staked_tokens)
                    );
         FC_ASSERT( (used_uacts * dgpo.total_staked_tokens)  <=  (user_stake * virtual_max_uacts),  "authorizing account '${n}' has insufficient compute bandwidth for this transaction",
1533
                    ("n",name(authaccnt.first))
1534 1535 1536 1537 1538 1539
                    ("used_acts",double(used_uacts)/1000000.)
                    ("user_stake",user_stake)
                    ("virtual_max_uacts", double(virtual_max_uacts)/1000000. )
                    ("total_staked_tokens", dgpo.total_staked_tokens)
                    );
      }
1540 1541 1542

      // for any transaction not sent by code, update the affirmative last time a given permission was used
      if (!meta.sender) {
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
         const auto *puo = _db.find<permission_usage_object, by_account_permission>(boost::make_tuple(authaccnt.first, authaccnt.second));
         if (puo) {
            _db.modify(*puo, [this](permission_usage_object &pu) {
               pu.last_used = head_block_time();
            });
         } else {
            _db.create<permission_usage_object>([this, &authaccnt](permission_usage_object &pu){
               pu.account = authaccnt.first;
               pu.permission = authaccnt.second;
               pu.last_used = head_block_time();
            });
         }
1555
      }
1556 1557
   }

1558 1559 1560 1561
   _db.modify( dgpo, [&]( auto& props ) {
      props.average_block_acts.add_usage( act_usage, head_time );
   });

D
Daniel Larimer 已提交
1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
}

const apply_handler* chain_controller::find_apply_handler( account_name receiver, account_name scope, action_name act ) const
{
   auto native_handler_scope = _apply_handlers.find( receiver );
   if( native_handler_scope != _apply_handlers.end() ) {
      auto handler = native_handler_scope->second.find( make_pair( scope, act ) );
      if( handler != native_handler_scope->second.end() ) 
         return &handler->second;
   }
   return nullptr;
}

D
Daniel Larimer 已提交
1575
} } /// eosio::chain