chain_controller.cpp 68.8 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>
N
Nathan Hourt 已提交
7

B
Bart Wyatt 已提交
8 9
#include <eosio/chain/block_summary_object.hpp>
#include <eosio/chain/global_property_object.hpp>
10
#include <eosio/chain/contracts/contract_table_objects.hpp>
B
Bart Wyatt 已提交
11 12 13 14 15 16
#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 已提交
17
#include <eosio/chain/contracts/chain_initializer.hpp>
18
#include <eosio/chain/resource_limits.hpp>
19
#include <eosio/chain/scope_sequence_object.hpp>
20
#include <eosio/chain/merkle.hpp>
N
Nathan Hourt 已提交
21

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

24
#include <eosio/utilities/rand.hpp>
25

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

30
#include <boost/range/algorithm/copy.hpp>
31
#include <boost/range/algorithm_ext/erase.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

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

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

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

uint32_t chain_controller::blocks_per_round()const {
47
  return get_global_properties().active_producers.producers.size()*config::producer_repetitions;
48 49
}

D
Daniel Larimer 已提交
50
chain_controller::chain_controller( const chain_controller::controller_config& cfg )
51 52 53
:_db( cfg.shared_memory_dir,
      (cfg.read_only ? database::read_only : database::read_write),
      cfg.shared_memory_size),
54
 _block_log(cfg.block_log_dir),
55
 _limits(cfg.limits)
D
Daniel Larimer 已提交
56 57 58
{
   _initialize_indexes();

59 60
   for (auto& f : cfg.applied_block_callbacks)
      applied_block.connect(f);
61 62
   for (auto& f : cfg.applied_irreversible_block_callbacks)
      applied_irreversible_block.connect(f);
63 64
   for (auto& f : cfg.on_pending_transaction_callbacks)
      on_pending_transaction.connect(f);
65

D
Daniel Larimer 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
   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();
}

87
bool chain_controller::is_known_block(const block_id_type& id)const
N
Nathan Hourt 已提交
88
{
89
   return _fork_db.is_known_block(id) || _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
90 91 92 93 94 95
}
/**
 * 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.
 */
96
bool chain_controller::is_known_transaction(const transaction_id_type& id)const
N
Nathan Hourt 已提交
97
{
98
   const auto& trx_idx = _db.get_index<transaction_multi_index, by_trx_id>();
N
Nathan Hourt 已提交
99 100 101
   return trx_idx.find( id ) != trx_idx.end();
}

102
block_id_type chain_controller::get_block_id_for_num(uint32_t block_num)const
N
Nathan Hourt 已提交
103
{ try {
104 105
   if (const auto& block = fetch_block_by_number(block_num))
      return block->id();
N
Nathan Hourt 已提交
106

107 108 109
   FC_THROW_EXCEPTION(unknown_block_exception, "Could not find block");
} FC_CAPTURE_AND_RETHROW((block_num)) }

110
optional<signed_block> chain_controller::fetch_block_by_id(const block_id_type& id)const
N
Nathan Hourt 已提交
111
{
112 113
   auto b = _fork_db.fetch_block(id);
   if(b) return b->data;
114
   return _block_log.read_block_by_id(id);
N
Nathan Hourt 已提交
115 116
}

117
optional<signed_block> chain_controller::fetch_block_by_number(uint32_t num)const
N
Nathan Hourt 已提交
118
{
119
   if (const auto& block = _block_log.read_block_by_num(num))
120 121
      return *block;

N
Nathan Hourt 已提交
122
   // Not in _block_log, so it must be since the last irreversible block. Grab it from _fork_db instead
123 124 125 126 127 128 129 130
   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 已提交
131 132 133
   return optional<signed_block>();
}

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

152

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

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

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

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

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

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

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

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

259
transaction_trace chain_controller::_push_transaction(const packed_transaction& trx) {
260
   transaction_metadata   mtrx( trx, get_chain_id(), head_block_time());
261
   check_transaction_authorization(mtrx.trx(), trx.signatures);
262
   auto result = _push_transaction(std::move(mtrx));
B
Bart Wyatt 已提交
263 264

   // notify anyone listening to pending transactions
265
   on_pending_transaction(_pending_transaction_metas.back(), trx);
B
Bart Wyatt 已提交
266

267 268
   _pending_block->input_transactions.emplace_back(trx);

B
Bart Wyatt 已提交
269 270 271 272
   return result;

}

B
Bart Wyatt 已提交
273 274 275 276
static void record_locks_for_data_access(const vector<action_trace>& action_traces, vector<shard_lock>& read_locks, vector<shard_lock>& write_locks ) {
   for (const auto& at: action_traces) {
      for (const auto& access: at.data_access) {
         if (access.type == data_access_info::read) {
277
            read_locks.emplace_back(shard_lock{access.code, access.scope});
B
Bart Wyatt 已提交
278
         } else {
279
            write_locks.emplace_back(shard_lock{access.code, access.scope});
B
Bart Wyatt 已提交
280 281 282 283 284
         }
      }
   }
}

285
transaction_trace chain_controller::_push_transaction( transaction_metadata&& data )
B
Bart Wyatt 已提交
286
{
287 288 289 290
   if (_limits.max_push_transaction_us.count() > 0) {
      data.processing_deadline = fc::time_point::now() + _limits.max_push_transaction_us;
   }

291
   const transaction& trx = data.trx();
292 293
   // 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 已提交
294
   if( !_pending_block ) {
D
Daniel Larimer 已提交
295
      _start_pending_block();
D
Daniel Larimer 已提交
296
   }
297

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

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

303 304
   auto cyclenum = _pending_block->regions.back().cycles_summary.size() - 1;

305 306 307
   /// 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 已提交
308 309 310
   // set cycle, shard, region etc
   data.region_id = 0;
   data.cycle_index = cyclenum;
B
Bart Wyatt 已提交
311
   data.shard_index = 0;
B
Bart Wyatt 已提交
312
   auto result = _apply_transaction( data );
313

314
   auto& bcycle = _pending_block->regions.back().cycles_summary.back();
B
Bart Wyatt 已提交
315
   auto& bshard = bcycle.front();
316

B
Bart Wyatt 已提交
317
   record_locks_for_data_access(result.action_traces, bshard.read_locks, bshard.write_locks);
318

319 320
   fc::deduplicate(bshard.read_locks);
   fc::deduplicate(bshard.write_locks);
321

B
Bart Wyatt 已提交
322
   bshard.transactions.emplace_back( result );
323

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

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

329 330
   _pending_transaction_metas.emplace_back(std::forward<transaction_metadata>(data));

B
Bart Wyatt 已提交
331
   return result;
N
Nathan Hourt 已提交
332 333
}

334 335 336 337 338 339
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);
340 341
   _pending_block->regions.resize(1);
   _pending_block_trace->region_traces.resize(1);
342 343 344
   _start_pending_cycle();
}

345 346
/**
 *  Wraps up all work for current shards, starts a new cycle, and
347
 *  executes any pending transactions
348
 */
349
void chain_controller::_start_pending_cycle() {
350
   _pending_block->regions.back().cycles_summary.resize( _pending_block->regions[0].cycles_summary.size() + 1 );
351 352
   _pending_cycle_trace = cycle_trace();
   _start_pending_shard();
353 354

   /// TODO: check for deferred transactions and schedule them
355
} // _start_pending_cycle
356

357
void chain_controller::_start_pending_shard()
B
Bart Wyatt 已提交
358
{
359
   auto& bcycle = _pending_block->regions.back().cycles_summary.back();
360 361 362
   bcycle.resize( bcycle.size()+1 );

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

365 366
void chain_controller::_finalize_pending_cycle()
{
367 368 369 370
   for( auto& shard : _pending_cycle_trace->shard_traces ) {
      shard.calculate_root();
   }

371
   _apply_cycle_trace(*_pending_cycle_trace);
372
   _pending_block_trace->region_traces.back().cycle_traces.emplace_back(std::move(*_pending_cycle_trace));
373 374
   _pending_cycle_trace.reset();
}
B
Bart Wyatt 已提交
375

376 377 378 379 380
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) {
381
            _db.create<generated_transaction_object>([&](generated_transaction_object &obj) {
382 383 384 385 386
               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;
387
               obj.published = head_block_time();
388 389 390 391 392 393
               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);
            });
         }

394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
         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);
               }
            }
         }

409 410 411 412
         ///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 已提交
413
                  "[(${a},${n})->${r}]",
414
                  fc::mutable_variant_object()
B
Bart Wyatt 已提交
415 416
                     ("a", ar.act.account)
                     ("n", ar.act.name)
417 418 419 420 421
                     ("r", ar.receiver));
               std::cerr << prefix << ": CONSOLE OUTPUT BEGIN =====================" << std::endl;
               std::cerr << ar.console;
               std::cerr << prefix << ": CONSOLE OUTPUT END   =====================" << std::endl;
            }
422
         }
B
Bart Wyatt 已提交
423 424 425 426
      }
   }
}

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
/**
 *  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);

   create_block_summary(b);
   clear_expired_transactions();

442
   update_last_irreversible_block();
443
   update_rate_limiting();
444

445
   applied_block( trace ); //emit
446 447 448 449 450
   if (_currently_replaying_blocks)
     applied_irreversible_block(b);

} FC_CAPTURE_AND_RETHROW( (trace.block) ) }

451
signed_block chain_controller::generate_block(
D
Daniel Larimer 已提交
452 453 454
   block_timestamp_type when,
   account_name producer,
   const private_key_type& block_signing_private_key,
N
Nathan Hourt 已提交
455 456 457
   uint32_t skip /* = 0 */
   )
{ try {
458
   return with_skip_flags( skip | created_block, [&](){
D
Daniel Larimer 已提交
459
      return _db.with_write_lock( [&](){
D
Daniel Larimer 已提交
460
         return _generate_block( when, producer, block_signing_private_key );
D
Daniel Larimer 已提交
461
      });
N
Nathan Hourt 已提交
462
   });
D
Daniel Larimer 已提交
463
} FC_CAPTURE_AND_RETHROW( (when) ) }
N
Nathan Hourt 已提交
464

465 466
signed_block chain_controller::_generate_block( block_timestamp_type when,
                                              account_name producer,
D
Daniel Larimer 已提交
467 468
                                              const private_key_type& block_signing_key )
{ try {
469

470 471 472 473 474 475
   try {
      uint32_t skip     = _skip_flags;
      uint32_t slot_num = get_slot_at_time( when );
      FC_ASSERT( slot_num > 0 );
      account_name scheduled_producer = get_scheduled_producer( slot_num );
      FC_ASSERT( scheduled_producer == producer );
N
Nathan Hourt 已提交
476

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

479 480 481
      if( !_pending_block ) {
         _start_pending_block();
      }
482

483
      _finalize_pending_cycle();
484

485
      if( !(skip & skip_producer_signature) )
K
Kevin Heifner 已提交
486 487
         FC_ASSERT( producer_obj.signing_key == block_signing_key.get_public_key(),
                    "producer key ${pk}, block key ${bk}", ("pk", producer_obj.signing_key)("bk", block_signing_key.get_public_key()) );
N
Nathan Hourt 已提交
488

489 490 491 492
         _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();
493
         _pending_block->transaction_mroot = transaction_metadata::calculate_transaction_merkle_root( _pending_transaction_metas );
494
         _pending_block->action_mroot = _pending_block_trace->calculate_action_merkle_root();
495

496 497 498 499 500
         if( is_start_of_round( _pending_block->block_num() ) ) {
         auto latest_producer_schedule = _calculate_producer_schedule();
         if( latest_producer_schedule != _head_producer_schedule() )
            _pending_block->new_producers = latest_producer_schedule;
      }
501

502 503
      if( !(skip & skip_producer_signature) )
         _pending_block->sign( block_signing_key );
504

505
      _finalize_block( *_pending_block_trace );
N
Nathan Hourt 已提交
506

507
      _pending_block_session->push();
D
Daniel Larimer 已提交
508

509
      auto result = move( *_pending_block );
510

511
      clear_pending();
D
Daniel Larimer 已提交
512

513 514 515 516 517
      if (!(skip&skip_fork_db)) {
         _fork_db.push_block(result);
      }
      return result;
   } catch ( ... ) {
518
      clear_pending();
519

520 521 522
      elog( "error while producing block" );
      _start_pending_block();
      throw;
N
Nathan Hourt 已提交
523 524
   }

N
Nathan Hourt 已提交
525
} FC_CAPTURE_AND_RETHROW( (producer) ) }
N
Nathan Hourt 已提交
526 527

/**
N
Nathan Hourt 已提交
528
 * Removes the most recent block from the database and undoes any changes it made.
N
Nathan Hourt 已提交
529
 */
530
void chain_controller::pop_block()
N
Nathan Hourt 已提交
531
{ try {
D
Daniel Larimer 已提交
532
   _pending_block_session.reset();
N
Nathan Hourt 已提交
533 534 535 536 537
   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();
538
   _db.undo();
N
Nathan Hourt 已提交
539 540
} FC_CAPTURE_AND_RETHROW() }

541
void chain_controller::clear_pending()
N
Nathan Hourt 已提交
542
{ try {
543
   _pending_block_trace.reset();
D
Daniel Larimer 已提交
544
   _pending_block.reset();
D
Daniel Larimer 已提交
545
   _pending_block_session.reset();
546
   _pending_transaction_metas.clear();
N
Nathan Hourt 已提交
547 548 549 550
} FC_CAPTURE_AND_RETHROW() }

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

D
Daniel Larimer 已提交
551
void chain_controller::_apply_block(const signed_block& next_block, uint32_t skip)
N
Nathan Hourt 已提交
552 553
{
   auto block_num = next_block.block_num();
554 555 556 557 558
   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 已提交
559

560
      if (_checkpoints.rbegin()->first >= block_num)
N
Nathan Hourt 已提交
561 562
         skip = ~0;// WE CAN SKIP ALMOST EVERYTHING
   }
N
Nathan Hourt 已提交
563 564 565

   with_applying_block([&] {
      with_skip_flags(skip, [&] {
D
Daniel Larimer 已提交
566
         __apply_block(next_block);
N
Nathan Hourt 已提交
567 568
      });
   });
N
Nathan Hourt 已提交
569 570
}

571 572
static void validate_shard_locks(const vector<shard_lock>& locks, const string& tag) {
   if (locks.size() < 2) {
573 574 575
      return;
   }

B
Bart Wyatt 已提交
576
   for (auto cur = locks.begin() + 1; cur != locks.end(); ++cur) {
577
      auto prev = cur - 1;
B
Bart Wyatt 已提交
578 579
      EOS_ASSERT(*prev != *cur, block_lock_exception, "${tag} lock \"${a}::${s}\" is not unique", ("tag",tag)("a",cur->account)("s",cur->scope));
      EOS_ASSERT(*prev < *cur,  block_lock_exception, "${tag} locks are not sorted", ("tag",tag));
580 581
   }
}
582

D
Daniel Larimer 已提交
583
void chain_controller::__apply_block(const signed_block& next_block)
N
Nathan Hourt 已提交
584
{ try {
585 586
   optional<fc::time_point> processing_deadline;
   if (!_currently_replaying_blocks && _limits.max_push_block_us.count() > 0) {
B
Bart Wyatt 已提交
587
      processing_deadline = fc::time_point::now() + _limits.max_push_block_us;
588 589
   }

N
Nathan Hourt 已提交
590
   uint32_t skip = _skip_flags;
N
Nathan Hourt 已提交
591

D
Daniel Larimer 已提交
592
   /*
593
   FC_ASSERT((skip & skip_merkle_check)
D
Daniel Larimer 已提交
594
             || next_block.transaction_merkle_root == next_block.calculate_merkle_root(),
595 596
             "", ("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 已提交
597
             */
N
Nathan Hourt 已提交
598 599

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

601 602 603 604
   /// 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 );

605 606 607

   /// cache the input tranasction ids so that they can be looked up when executing the
   /// summary
608
   vector<transaction_metadata> input_metas;
B
Bart Wyatt 已提交
609 610
   input_metas.reserve(next_block.input_transactions.size());
   map<transaction_id_type,size_t> trx_index;
611
   for( const auto& t : next_block.input_transactions ) {
612
      input_metas.emplace_back(t, chain_id_type(), next_block.timestamp);
B
Bart Wyatt 已提交
613
      trx_index[input_metas.back().id] =  input_metas.size() - 1;
614
   }
615 616

   block_trace next_block_trace(next_block);
617 618
   next_block_trace.region_traces.reserve(next_block.regions.size());

619
   for( const auto& r : next_block.regions ) {
620 621 622
      region_trace r_trace;
      r_trace.cycle_traces.reserve(r.cycles_summary.size());

623
      for (uint32_t cycle_index = 0; cycle_index < r.cycles_summary.size(); cycle_index++) {
624
         const auto& cycle = r.cycles_summary.at(cycle_index);
625 626 627
         cycle_trace c_trace;
         c_trace.shard_traces.reserve(cycle.size());

628 629
         // validate that no read_scope is used as a write scope in this cycle and that no two shards
         // share write scopes
630 631
         set<shard_lock> read_locks;
         map<shard_lock, uint32_t> write_locks;
632 633 634 635 636

         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
637 638 639 640
            validate_shard_locks(shard.read_locks,  "read");
            validate_shard_locks(shard.write_locks, "write");

            for (const auto& s: shard.read_locks) {
B
Bart Wyatt 已提交
641
               EOS_ASSERT(write_locks.count(s) == 0, block_concurrency_exception,
642 643 644
                  "shard ${i} requires read lock \"${a}::${s}\" which is locked for write by shard ${j}",
                  ("i", shard_index)("s", s)("j", write_locks[s]));
               read_locks.emplace(s);
645 646
            }

647
            for (const auto& s: shard.write_locks) {
B
Bart Wyatt 已提交
648
               EOS_ASSERT(write_locks.count(s) == 0, block_concurrency_exception,
649
                  "shard ${i} requires write lock \"${a}::${s}\" which is locked for write by shard ${j}",
B
Bart Wyatt 已提交
650 651 652 653
                  ("i", shard_index)("a", s.account)("s", s.scope)("j", write_locks[s]));
               EOS_ASSERT(read_locks.count(s) == 0, block_concurrency_exception,
                  "shard ${i} requires write lock \"${a}::${s}\" which is locked for read",
                  ("i", shard_index)("a", s.account)("s", s.scope));
654
               write_locks[s] = shard_index;
655 656
            }

B
Bart Wyatt 已提交
657 658 659
            vector<shard_lock> used_read_locks;
            vector<shard_lock> used_write_locks;

660
            shard_trace s_trace;
B
Bart Wyatt 已提交
661
            for (const auto& receipt : shard.transactions) {
662 663
                optional<transaction_metadata> _temp;
                auto make_metadata = [&]() -> transaction_metadata* {
664 665
                  auto itr = trx_index.find(receipt.id);
                  if( itr != trx_index.end() ) {
B
Bart Wyatt 已提交
666
                     return &input_metas.at(itr->second);
B
Bart Wyatt 已提交
667
                  } else {
668
                     const auto& gtrx = _db.get<generated_transaction_object,by_trx_id>(receipt.id);
B
Bart Wyatt 已提交
669
                     auto trx = fc::raw::unpack<deferred_transaction>(gtrx.packed_trx.data(), gtrx.packed_trx.size());
670 671
                     _temp.emplace(trx, gtrx.published, trx.sender, trx.sender_id, gtrx.packed_trx.data(), gtrx.packed_trx.size() );
                     return &*_temp;
672
                  }
673
               };
B
Bart Wyatt 已提交
674

675 676 677 678 679 680
               auto *mtrx = make_metadata();
               mtrx->region_id = r.region;
               mtrx->cycle_index = cycle_index;
               mtrx->shard_index = shard_index;
               mtrx->allowed_read_locks.emplace(&shard.read_locks);
               mtrx->allowed_write_locks.emplace(&shard.write_locks);
681
               mtrx->processing_deadline = processing_deadline;
B
Bart Wyatt 已提交
682

683
               s_trace.transaction_traces.emplace_back(_apply_transaction(*mtrx));
B
Bart Wyatt 已提交
684
               record_locks_for_data_access(s_trace.transaction_traces.back().action_traces, used_read_locks, used_write_locks);
685 686

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

688 689 690 691 692
               // 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 已提交
693

B
Bart Wyatt 已提交
694 695 696 697 698 699 700 701 702 703
            // Validate that the producer didn't list extra locks to bloat the size of the block
            // TODO: this check can be removed when blocks are irreversible
            fc::deduplicate(used_read_locks);
            fc::deduplicate(used_write_locks);

            EOS_ASSERT(std::equal(used_read_locks.cbegin(), used_read_locks.cend(), shard.read_locks.begin()),
               block_lock_exception, "Read locks for executing shard: ${s} do not match those listed in the block", ("s", shard_index));
            EOS_ASSERT(std::equal(used_write_locks.cbegin(), used_write_locks.cend(), shard.write_locks.begin()),
               block_lock_exception, "Write locks for executing shard: ${s} do not match those listed in the block", ("s", shard_index));

704 705 706
            s_trace.calculate_root();
            c_trace.shard_traces.emplace_back(move(s_trace));
         } /// for each shard
D
Daniel Larimer 已提交
707

708 709 710
         _apply_cycle_trace(c_trace);
         r_trace.cycle_traces.emplace_back(move(c_trace));
      } /// for each cycle
D
Daniel Larimer 已提交
711

712 713
      next_block_trace.region_traces.emplace_back(move(r_trace));
   } /// for each region
N
Nathan Hourt 已提交
714

715
   FC_ASSERT(next_block.action_mroot == next_block_trace.calculate_action_merkle_root());
716
   FC_ASSERT( transaction_metadata::calculate_transaction_merkle_root(input_metas) == next_block.transaction_mroot, "merkle root does not match" );
N
Nathan Hourt 已提交
717

718
   _finalize_block( next_block_trace );
719
} FC_CAPTURE_AND_RETHROW( (next_block.block_num()) )  }
D
Daniel Larimer 已提交
720

721 722
flat_set<public_key_type> chain_controller::get_required_keys(const transaction& trx,
                                                              const flat_set<public_key_type>& candidate_keys)const
D
Daniel Larimer 已提交
723
{
724
   auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
725 726
                                     get_global_properties().configuration.max_authority_depth,
                                     candidate_keys);
727

728
   for (const auto& act : trx.actions ) {
D
Daniel Larimer 已提交
729 730 731
      for (const auto& declared_auth : act.authorization) {
         if (!checker.satisfied(declared_auth)) {
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
732
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
733
                       ("auth", declared_auth));
734 735 736 737 738 739 740
         }
      }
   }

   return checker.used_keys();
}

741
void chain_controller::check_authorization( const vector<action>& actions,
742 743 744
                                            flat_set<public_key_type> provided_keys,
                                            bool allow_unused_signatures,
                                            flat_set<account_name>    provided_accounts  )const
D
Daniel Larimer 已提交
745
{
746
   auto checker = make_auth_checker( [&](const permission_level& p){ return get_permission(p).auth; },
747
                                     get_global_properties().configuration.max_authority_depth,
748 749
                                     provided_keys, provided_accounts );

N
Nathan Hourt 已提交
750

751
   for( const auto& act : actions ) {
752
      for( const auto& declared_auth : act.authorization ) {
D
Daniel Larimer 已提交
753

754
         // check a minimum permission if one is set, otherwise assume the contract code will validate
B
Bart Wyatt 已提交
755
         auto min_permission_name = lookup_minimum_permission(declared_auth.actor, act.account, act.name);
756 757 758 759 760 761 762 763 764 765 766
         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 已提交
767 768
         }
         if ((_skip_flags & skip_transaction_signatures) == false) {
D
Daniel Larimer 已提交
769
            EOS_ASSERT(checker.satisfied(declared_auth), tx_missing_sigs,
D
Daniel Larimer 已提交
770
                       "transaction declares authority '${auth}', but does not have signatures for it.",
D
Daniel Larimer 已提交
771
                       ("auth", declared_auth));
N
Nathan Hourt 已提交
772 773
         }
      }
774
   }
N
Nathan Hourt 已提交
775

776
   if (!allow_unused_signatures && (_skip_flags & skip_transaction_signatures) == false)
777
      EOS_ASSERT(checker.all_keys_used(), tx_irrelevant_sig,
778
                 "transaction bears irrelevant signatures from these keys: ${keys}",
779
                 ("keys", checker.unused_keys()));
N
Nathan Hourt 已提交
780 781
}

782 783
void chain_controller::check_transaction_authorization(const transaction& trx,
                                                       const vector<signature_type>& signatures,
784
                                                       bool allow_unused_signatures)const
785
{
786
   check_authorization( trx.actions, trx.get_signature_keys( signatures, chain_id_type{} ), allow_unused_signatures );
787 788
}

789
optional<permission_name> chain_controller::lookup_minimum_permission(account_name authorizer_account,
D
Daniel Larimer 已提交
790 791
                                                                    account_name scope,
                                                                    action_name act_name) const {
792 793 794 795 796 797
   // 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 已提交
798
   try {
D
Daniel Larimer 已提交
799 800 801
      // 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);
802 803 804
      // If no specific link found, check for a contract-wide default
      if (link == nullptr) {
         get<2>(key) = "";
D
Daniel Larimer 已提交
805
         link = _db.find<permission_link_object, by_action_name>(key);
806 807 808 809
      }

      // If no specific or default link found, use active permission
      if (link != nullptr)
810 811 812
         return link->required_permission;
      else
         return N(active);
D
Daniel Larimer 已提交
813
   } FC_CAPTURE_AND_RETHROW((authorizer_account)(scope)(act_name))
N
Nathan Hourt 已提交
814 815
}

816
void chain_controller::validate_uniqueness( const transaction& trx )const {
N
Nathan Hourt 已提交
817
   if( !should_check_for_duplicate_transactions() ) return;
N
Nathan Hourt 已提交
818

819
   auto transaction = _db.find<transaction_object, by_trx_id>(trx.id());
D
Daniel Larimer 已提交
820
   EOS_ASSERT(transaction == nullptr, tx_duplicate, "transaction is not unique");
821
}
822

823
void chain_controller::record_transaction(const transaction& trx) {
824 825
   //Insert transaction into unique transactions database.
    _db.create<transaction_object>([&](transaction_object& transaction) {
826
        transaction.trx_id = trx.id();
D
Daniel Larimer 已提交
827
        transaction.expiration = trx.expiration;
828 829 830 831
    });
}


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

D
Daniel Larimer 已提交
835
   const auto& tapos_block_summary = _db.get<block_summary_object>((uint16_t)trx.ref_block_num);
836 837

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

843 844
void chain_controller::validate_referenced_accounts( const transaction& trx )const
{ try {
D
Daniel Larimer 已提交
845
   for( const auto& act : trx.actions ) {
B
Bart Wyatt 已提交
846
      require_account(act.account);
D
Daniel Larimer 已提交
847
      for (const auto& auth : act.authorization )
D
Daniel Larimer 已提交
848
         require_account(auth.actor);
849
   }
D
Daniel Larimer 已提交
850
} FC_CAPTURE_AND_RETHROW() }
D
Daniel Larimer 已提交
851

D
Daniel Larimer 已提交
852
void chain_controller::validate_expiration( const transaction& trx ) const
853
{ try {
D
Daniel Larimer 已提交
854
   fc::time_point now = head_block_time();
D
Daniel Larimer 已提交
855
   const auto& chain_configuration = get_global_properties().configuration;
856

D
Daniel Larimer 已提交
857
   EOS_ASSERT( time_point(trx.expiration) <= now + fc::seconds(chain_configuration.max_transaction_lifetime),
D
Daniel Larimer 已提交
858
              transaction_exception, "transaction expiration is too far in the future",
859
              ("trx.expiration",trx.expiration)("now",now)
D
Daniel Larimer 已提交
860 861
              ("max_til_exp",chain_configuration.max_transaction_lifetime));
   EOS_ASSERT( now <= time_point(trx.expiration), transaction_exception, "transaction is expired",
862 863
              ("now",now)("trx.exp",trx.expiration));
} FC_CAPTURE_AND_RETHROW((trx)) }
864

865

866 867
void chain_controller::require_scope( const scope_name& scope )const {
   switch( uint64_t(scope) ) {
868 869
      case config::eosio_all_scope:
      case config::eosio_auth_scope:
870 871 872 873 874 875
         return; /// built in scopes
      default:
         require_account(scope);
   }
}

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

881
const producer_object& chain_controller::validate_block_header(uint32_t skip, const signed_block& next_block)const {
882 883
   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 已提交
884
   EOS_ASSERT(head_block_time() < (fc::time_point)next_block.timestamp, block_validate_exception, "",
885
              ("head_block_time",head_block_time())("next",next_block.timestamp)("blocknum",next_block.block_num()));
K
Kevin Heifner 已提交
886
   if (((fc::time_point)next_block.timestamp) > head_block_time() + fc::microseconds(config::block_interval_ms*1000)) {
887
      elog("head_block_time ${h}, next_block ${t}, block_interval ${bi}",
888 889 890
           ("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));
891
   }
892 893

   if( !is_start_of_round( next_block.block_num() ) )  {
D
Daniel Larimer 已提交
894
      EOS_ASSERT(!next_block.new_producers, block_validate_exception,
895
                 "Producer changes may only occur at the end of a round.");
N
Nathan Hourt 已提交
896
   }
897

D
Daniel Larimer 已提交
898
   const producer_object& producer = get_producer(get_scheduled_producer(get_slot_at_time(next_block.timestamp)));
N
Nathan Hourt 已提交
899

N
Nathan Hourt 已提交
900
   if(!(skip&skip_producer_signature))
901 902 903
      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 已提交
904

905
   if(!(skip&skip_producer_schedule_check)) {
906 907 908
      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 已提交
909 910
   }

911

N
Nathan Hourt 已提交
912 913 914
   return producer;
}

915
void chain_controller::create_block_summary(const signed_block& next_block) {
916
   auto sid = next_block.block_num() & 0xffff;
917
   _db.modify( _db.get<block_summary_object,by_id>(sid), [&](block_summary_object& p) {
918 919
         p.block_id = next_block.id();
   });
N
Nathan Hourt 已提交
920 921
}

922 923
/**
 *  Takes the top config::producer_count producers by total vote excluding any producer whose
924
 *  block_signing_key is null.
925 926
 */
producer_schedule_type chain_controller::_calculate_producer_schedule()const {
927
   producer_schedule_type schedule = get_global_properties().new_active_producers;
928

929 930 931 932
   const auto& hps = _head_producer_schedule();
   schedule.version = hps.version;
   if( hps != schedule )
      ++schedule.version;
933 934 935 936 937 938
   return schedule;
}

/**
 *  Returns the most recent and/or pending producer schedule
 */
D
Daniel Larimer 已提交
939
const shared_producer_schedule_type& chain_controller::_head_producer_schedule()const {
940
   const auto& gpo = get_global_properties();
941
   if( gpo.pending_active_producers.size() )
942 943 944 945
      return gpo.pending_active_producers.back().second;
   return gpo.active_producers;
}

946
void chain_controller::update_global_properties(const signed_block& b) { try {
947 948
   // If we're at the end of a round, update the BlockchainConfiguration, producer schedule
   // and "producers" special account authority
949 950 951 952 953
   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" );
954 955 956
      }

      const auto& gpo = get_global_properties();
957 958 959

      if( _head_producer_schedule() != schedule ) {
         FC_ASSERT( b.new_producers, "pending producer set changed but block didn't indicate it" );
960
      }
961 962 963 964
      _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
D
Daniel Larimer 已提交
965 966 967 968 969
         {
            props.pending_active_producers.emplace_back( props.pending_active_producers.get_allocator() );// props.pending_active_producers.size()+1, props.pending_active_producers.get_allocator() );
            auto& back = props.pending_active_producers.back();
            back.first = b.block_num();
            back.second = schedule;
970

D
Daniel Larimer 已提交
971
         }
972 973
      });

974

975
      auto active_producers_authority = authority(config::producers_authority_threshold, {}, {});
976
      for(auto& name : gpo.active_producers.producers ) {
977
         active_producers_authority.accounts.push_back({{name.producer_name, config::active_name}, 1});
978 979
      }

980
      auto& po = _db.get<permission_object, by_owner>( boost::make_tuple(config::producers_account_name,
981
                                                                         config::active_name ) );
982 983 984
      _db.modify(po,[active_producers_authority] (permission_object& po) {
         po.auth = active_producers_authority;
      });
985
   }
986
} FC_CAPTURE_AND_RETHROW() }
987

988
void chain_controller::add_checkpoints( const flat_map<uint32_t,block_id_type>& checkpts ) {
989
   for (const auto& i : checkpts)
N
Nathan Hourt 已提交
990 991 992
      _checkpoints[i.first] = i.second;
}

993
bool chain_controller::before_last_checkpoint()const {
N
Nathan Hourt 已提交
994 995 996
   return (_checkpoints.size() > 0) && (_checkpoints.rbegin()->first >= head_block_num());
}

997
const global_property_object& chain_controller::get_global_properties()const {
998
   return _db.get<global_property_object>();
N
Nathan Hourt 已提交
999 1000
}

1001
const dynamic_global_property_object&chain_controller::get_dynamic_global_properties() const {
1002
   return _db.get<dynamic_global_property_object>();
N
Nathan Hourt 已提交
1003 1004
}

D
Daniel Larimer 已提交
1005
time_point chain_controller::head_block_time()const {
N
Nathan Hourt 已提交
1006 1007 1008
   return get_dynamic_global_properties().time;
}

1009
uint32_t chain_controller::head_block_num()const {
N
Nathan Hourt 已提交
1010 1011 1012
   return get_dynamic_global_properties().head_block_number;
}

1013
block_id_type chain_controller::head_block_id()const {
N
Nathan Hourt 已提交
1014 1015 1016
   return get_dynamic_global_properties().head_block_id;
}

D
Daniel Larimer 已提交
1017
account_name chain_controller::head_block_producer() const {
1018 1019 1020
   auto b = _fork_db.fetch_block(head_block_id());
   if( b ) return b->data.producer;

N
Nathan Hourt 已提交
1021
   if (auto head_block = fetch_block_by_id(head_block_id()))
1022
      return head_block->producer;
N
Nathan Hourt 已提交
1023 1024 1025
   return {};
}

1026
const producer_object& chain_controller::get_producer(const account_name& owner_name) const
D
Daniel Larimer 已提交
1027
{ try {
B
Bart Wyatt 已提交
1028
   return _db.get<producer_object, by_owner>(owner_name);
D
Daniel Larimer 已提交
1029
} FC_CAPTURE_AND_RETHROW( (owner_name) ) }
N
Nathan Hourt 已提交
1030

1031
const permission_object&   chain_controller::get_permission( const permission_level& level )const
1032 1033 1034 1035
{ try {
   return _db.get<permission_object, by_owner>( boost::make_tuple(level.actor,level.permission) );
} FC_CAPTURE_AND_RETHROW( (level) ) }

1036
uint32_t chain_controller::last_irreversible_block_num() const {
N
Nathan Hourt 已提交
1037
   return get_dynamic_global_properties().last_irreversible_block_num;
N
Nathan Hourt 已提交
1038 1039
}

D
Daniel Larimer 已提交
1040
void chain_controller::_initialize_indexes() {
1041 1042
   _db.add_index<account_index>();
   _db.add_index<permission_index>();
1043
   _db.add_index<permission_usage_index>();
1044
   _db.add_index<permission_link_index>();
1045
   _db.add_index<action_permission_index>();
D
Daniel Larimer 已提交
1046 1047 1048



1049 1050
   _db.add_index<contracts::table_id_multi_index>();
   _db.add_index<contracts::key_value_index>();
D
Daniel Larimer 已提交
1051
   _db.add_index<contracts::index64_index>();
1052
   _db.add_index<contracts::index128_index>();
1053
   _db.add_index<contracts::index256_index>();
D
Daniel Larimer 已提交
1054 1055


1056 1057
   _db.add_index<contracts::keystr_value_index>();
   _db.add_index<contracts::key128x128_value_index>();
1058
   _db.add_index<contracts::key64x64_value_index>();
1059
   _db.add_index<contracts::key64x64x64_value_index>();
1060 1061 1062 1063 1064

   _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>();
1065
   _db.add_index<generated_transaction_multi_index>();
1066
   _db.add_index<producer_multi_index>();
1067
   _db.add_index<scope_sequence_multi_index>();
1068 1069
   _db.add_index<bandwidth_usage_index>();
   _db.add_index<compute_usage_index>();
N
Nathan Hourt 已提交
1070 1071
}

D
Daniel Larimer 已提交
1072
void chain_controller::_initialize_chain(contracts::chain_initializer& starter)
N
Nathan Hourt 已提交
1073
{ try {
1074
   if (!_db.find<global_property_object>()) {
N
Nathan Hourt 已提交
1075 1076
      _db.with_write_lock([this, &starter] {
         auto initial_timestamp = starter.get_chain_start_time();
D
Daniel Larimer 已提交
1077 1078 1079
         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 已提交
1080

1081
         // Create global properties
1082
         const auto& gp = _db.create<global_property_object>([&starter](global_property_object& p) {
N
Nathan Hourt 已提交
1083 1084
            p.configuration = starter.get_chain_start_configuration();
            p.active_producers = starter.get_chain_start_producers();
1085
            p.new_active_producers = starter.get_chain_start_producers();
1086
            wdump((starter.get_chain_start_producers()));
1087
         });
1088

1089
         _db.create<dynamic_global_property_object>([&](dynamic_global_property_object& p) {
N
Nathan Hourt 已提交
1090
            p.time = initial_timestamp;
1091
            p.recent_slots_filled = uint64_t(-1);
1092 1093
            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 );
1094
         });
N
Nathan Hourt 已提交
1095

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

B
Bart Wyatt 已提交
1100
         starter.prepare_database(*this, _db);
1101

B
Bart Wyatt 已提交
1102
         ilog( "done initializing chain" );
1103 1104
      });
   }
N
Nathan Hourt 已提交
1105 1106
} FC_CAPTURE_AND_RETHROW() }

N
Nathan Hourt 已提交
1107

1108
void chain_controller::replay() {
1109
   ilog("Replaying blockchain");
N
Nathan Hourt 已提交
1110
   auto start = fc::time_point::now();
K
Kevin Heifner 已提交
1111

K
Kevin Heifner 已提交
1112
   auto on_exit = fc::make_scoped_exit([&_currently_replaying_blocks = _currently_replaying_blocks](){
K
Kevin Heifner 已提交
1113 1114 1115 1116
      _currently_replaying_blocks = false;
   });
   _currently_replaying_blocks = true;

1117 1118 1119
   auto last_block = _block_log.read_head();
   if (!last_block) {
      elog("No blocks in block log; skipping replay");
N
Nathan Hourt 已提交
1120 1121 1122 1123 1124
      return;
   }

   const auto last_block_num = last_block->block_num();

1125
   ilog("Replaying ${n} blocks...", ("n", last_block_num) );
1126 1127 1128 1129 1130
   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 已提交
1131
      _apply_block(*block, skip_producer_signature |
N
Nathan Hourt 已提交
1132 1133 1134 1135
                          skip_transaction_signatures |
                          skip_transaction_dupe_check |
                          skip_tapos_check |
                          skip_producer_schedule_check |
1136 1137
                          skip_authority_check |
                          received_block);
N
Nathan Hourt 已提交
1138 1139
   }
   auto end = fc::time_point::now();
1140 1141
   ilog("Done replaying ${n} blocks, elapsed time: ${t} sec",
        ("n", head_block_num())("t",double((end-start).count())/1000000.0));
N
Nathan Hourt 已提交
1142

1143
   _db.set_revision(head_block_num());
1144
}
N
Nathan Hourt 已提交
1145

D
Daniel Larimer 已提交
1146
void chain_controller::_spinup_db() {
1147 1148 1149 1150 1151
   // 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()));
1152

1153 1154
   });
}
N
Nathan Hourt 已提交
1155

D
Daniel Larimer 已提交
1156
void chain_controller::_spinup_fork_db()
N
Nathan Hourt 已提交
1157
{
1158 1159 1160 1161 1162 1163 1164 1165
   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 已提交
1166 1167
}

D
Daniel Larimer 已提交
1168
/*
1169 1170
ProducerRound chain_controller::calculate_next_round(const signed_block& next_block) {
   auto schedule = _admin->get_next_round(_db);
N
Nathan Hourt 已提交
1171 1172 1173 1174
   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));
1175

P
Pravin 已提交
1176 1177
   fc::time_point tp = (fc::time_point)next_block.timestamp;
   utilities::rand::random rng(tp.sec_since_epoch());
1178 1179
   rng.shuffle(schedule);
   return schedule;
D
Daniel Larimer 已提交
1180
}*/
1181

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

1185 1186 1187
   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 已提交
1188
   uint32_t missed_blocks = head_block_num() == 0? 1 : get_slot_at_time((fc::time_point)b.timestamp);
1189
   assert(missed_blocks != 0);
N
Nathan Hourt 已提交
1190
   missed_blocks--;
N
Nathan Hourt 已提交
1191

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

1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208
   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 已提交
1209 1210 1211
      }
   }

1212 1213
   const auto& props = get_global_properties();

N
Nathan Hourt 已提交
1214
   // dynamic global properties updating
1215
   _db.modify( _dgp, [&]( dynamic_global_property_object& dgp ){
N
Nathan Hourt 已提交
1216 1217 1218
      dgp.head_block_number = b.block_num();
      dgp.head_block_id = b.id();
      dgp.time = b.timestamp;
1219
      dgp.current_producer = b.producer;
N
Nathan Hourt 已提交
1220
      dgp.current_absolute_slot += missed_blocks+1;
1221 1222 1223 1224 1225
      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 已提交
1226 1227 1228 1229 1230 1231

      // 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;
1232
      } else
1233
         if(config::percent_100 * get_global_properties().active_producers.producers.size() / blocks_per_round() > config::required_producer_participation)
1234 1235 1236
            dgp.recent_slots_filled = uint64_t(-1);
         else
            dgp.recent_slots_filled = 0;
1237
      dgp.block_merkle_root.append( head_block_id() );
N
Nathan Hourt 已提交
1238 1239 1240 1241 1242
   });

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

1243
void chain_controller::update_signing_producer(const producer_object& signing_producer, const signed_block& new_block)
N
Nathan Hourt 已提交
1244 1245
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
P
Pravin 已提交
1246
   uint64_t new_block_aslot = dpo.current_absolute_slot + get_slot_at_time( (fc::time_point)new_block.timestamp );
N
Nathan Hourt 已提交
1247

1248
   _db.modify( signing_producer, [&]( producer_object& _wit )
N
Nathan Hourt 已提交
1249 1250 1251 1252 1253 1254
   {
      _wit.last_aslot = new_block_aslot;
      _wit.last_confirmed_block_num = new_block.block_num();
   } );
}

1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
void chain_controller::update_or_create_producers( const producer_schedule_type& producers ) {
   for ( auto prod : producers.producers ) {
      if ( _db.find<producer_object, by_owner>(prod.producer_name) == nullptr ) {
         _db.create<producer_object>( [&]( auto& pro ) {
            pro.owner       = prod.producer_name;
            pro.signing_key = prod.block_signing_key;
         });
      }
   }
}

1266
void chain_controller::update_last_irreversible_block()
N
Nathan Hourt 已提交
1267 1268 1269 1270
{
   const global_property_object& gpo = get_global_properties();
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();

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

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

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

D
Daniel Larimer 已提交
1280
   size_t offset = EOS_PERCENT(producer_objs.size(), config::percent_100- config::irreversible_threshold_percent);
1281 1282
   std::nth_element(producer_objs.begin(), producer_objs.begin() + offset, producer_objs.end(),
      [](const producer_object* a, const producer_object* b) {
N
Nathan Hourt 已提交
1283
         return a->last_confirmed_block_num < b->last_confirmed_block_num;
1284
      });
N
Nathan Hourt 已提交
1285

1286 1287 1288 1289 1290 1291
   uint32_t new_last_irreversible_block_num = producer_objs[offset]->last_confirmed_block_num;
   // TODO: right now the code cannot handle the head block being irreversible for reasons that are purely
   // implementation details.  We can and should remove this special case once the rest of the logic is fixed.
   if (producer_objs.size() == 1) {
      new_last_irreversible_block_num -= 1;
   }
1292

N
Nathan Hourt 已提交
1293

1294
   if (new_last_irreversible_block_num > dpo.last_irreversible_block_num) {
1295
      _db.modify(dpo, [&](dynamic_global_property_object& _dpo) {
N
Nathan Hourt 已提交
1296
         _dpo.last_irreversible_block_num = new_last_irreversible_block_num;
1297
      });
N
Nathan Hourt 已提交
1298
   }
1299 1300

   // Write newly irreversible blocks to disk. First, get the number of the last block on disk...
1301
   auto old_last_irreversible_block = _block_log.head();
1302
   unsigned last_block_on_disk = 0;
1303 1304 1305
   // 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();
1306

1307
   if (last_block_on_disk < new_last_irreversible_block_num) {
1308 1309 1310 1311
      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);
1312
         FC_ASSERT( block, "unable to find last irreversible block to write" );
1313
         _block_log.append(*block);
K
Kevin Heifner 已提交
1314
         applied_irreversible_block(*block);
1315
      }
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326
   }

   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 ) {
1327
         update_or_create_producers( *new_producer_schedule );
1328
         _db.modify( gpo, [&]( auto& props ){
1329
              boost::range::remove_erase_if(props.pending_active_producers,
1330
                                            [new_last_irreversible_block_num](const typename decltype(props.pending_active_producers)::value_type& v) -> bool {
1331 1332
                                               return v.first < new_last_irreversible_block_num;
                                            });
1333
              props.active_producers = *new_producer_schedule;
1334 1335 1336 1337
         });
      }
   }

N
Nathan Hourt 已提交
1338 1339
   // Trim fork_database and undo histories
   _fork_db.set_max_size(head_block_num() - new_last_irreversible_block_num + 1);
1340
   _db.commit(new_last_irreversible_block_num);
N
Nathan Hourt 已提交
1341 1342
}

1343 1344
void chain_controller::update_rate_limiting()
{
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
   auto& resource_limits_index = _db.get_mutable_index<resource_limits_index>();
   auto& by_owner_index = resource_limits_index.indices().get<by_owner>();

   auto updated_state = _db.get<resource_limits_state_object>();

   while(!by_owner_index.empty()) {
      const auto& itr = by_owner_index.lower_bound(boost::make_tuple(true));
      if (itr == by_owner_index.end() || itr->pending!= true) {
         break;
      }

      const auto& actual_entry = _db.get<resource_limits_object, by_owner>(boost::make_tuple(false, itr->owner));
      _db.modify(actual_entry, [&](resource_limits_object& rlo){
         // convenience local lambda to reduce clutter
         auto update_state_and_value = [](uint64_t &total, int64_t &value, int64_t pending_value, const char* debug_which) -> void {
            if (value > 0) {
               EOS_ASSERT(total >= value, rate_limiting_state_inconsistent, "underflow when reverting old value to ${which}", ("which", debug_which));
               total -= value;
            }

            if (pending_value > 0) {
               EOS_ASSERT(UINT64_MAX - total < value, rate_limiting_state_inconsistent, "overflow when applying new value to ${which}", ("which", debug_which));
               total += pending_value;
            }

            value = pending_value;
         };

         update_state_and_value(updated_state.total_ram_bytes,  rlo.ram_bytes,  itr->ram_bytes, "ram_bytes");
         update_state_and_value(updated_state.total_cpu_weight, rlo.cpu_weight, itr->cpu_weight, "cpu_weight");
         update_state_and_value(updated_state.total_net_weight, rlo.net_weight, itr->net_weight, "net_wright");
1376
      });
1377 1378

      by_owner_index.remove(*itr);
1379
   }
1380 1381 1382 1383

   _db.modify(updated_state, [&updated_state](resource_limits_state_object rso){
      rso = updated_state;
   });
1384 1385
}

1386
void chain_controller::clear_expired_transactions()
N
Nathan Hourt 已提交
1387 1388
{ try {
   //Look for expired transactions in the deduplication list, and remove them.
D
Daniel Larimer 已提交
1389
   //transactions must have expired by at least two forking windows in order to be removed.
D
Daniel Larimer 已提交
1390
   /*
1391
   auto& transaction_idx = _db.get_mutable_index<transaction_multi_index>();
N
Nathan Hourt 已提交
1392
   const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
D
Daniel Larimer 已提交
1393
   while( (!dedupe_index.empty()) && (head_block_time() > dedupe_index.rbegin()->expiration) )
N
Nathan Hourt 已提交
1394
      transaction_idx.remove(*dedupe_index.rbegin());
B
Bart Wyatt 已提交
1395
      */
1396
   //Look for expired transactions in the pending generated list, and remove them.
D
Daniel Larimer 已提交
1397
   //transactions must have expired by at least two forking windows in order to be removed.
1398
   auto& generated_transaction_idx = _db.get_mutable_index<generated_transaction_multi_index>();
B
Bart Wyatt 已提交
1399 1400
   const auto& generated_index = generated_transaction_idx.indices().get<by_expiration>();
   while( (!generated_index.empty()) && (head_block_time() > generated_index.rbegin()->expiration) )
1401
      generated_transaction_idx.remove(*generated_index.rbegin());
B
Bart Wyatt 已提交
1402

N
Nathan Hourt 已提交
1403 1404 1405 1406
} FC_CAPTURE_AND_RETHROW() }

using boost::container::flat_set;

D
Daniel Larimer 已提交
1407
account_name chain_controller::get_scheduled_producer(uint32_t slot_num)const
N
Nathan Hourt 已提交
1408 1409
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
N
Nathan Hourt 已提交
1410
   uint64_t current_aslot = dpo.current_absolute_slot + slot_num;
1411
   const auto& gpo = _db.get<global_property_object>();
1412
   auto number_of_active_producers = gpo.active_producers.producers.size();
1413 1414
   auto index = current_aslot % (number_of_active_producers * config::producer_repetitions);
   index /= config::producer_repetitions;
1415 1416
   FC_ASSERT( gpo.active_producers.producers.size() > 0, "no producers defined" );

1417
   return gpo.active_producers.producers[index].producer_name;
N
Nathan Hourt 已提交
1418 1419
}

D
Daniel Larimer 已提交
1420
block_timestamp_type chain_controller::get_slot_time(uint32_t slot_num)const
N
Nathan Hourt 已提交
1421
{
P
Pravin 已提交
1422
   if( slot_num == 0)
D
Daniel Larimer 已提交
1423
      return block_timestamp_type();
N
Nathan Hourt 已提交
1424 1425 1426 1427 1428 1429

   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 已提交
1430 1431 1432
      auto genesis_time = block_timestamp_type(dpo.time);
      genesis_time.slot += slot_num;
      return (fc::time_point)genesis_time;
N
Nathan Hourt 已提交
1433 1434
   }

D
Daniel Larimer 已提交
1435
   auto head_block_abs_slot = block_timestamp_type(head_block_time());
P
Pravin 已提交
1436
   head_block_abs_slot.slot += slot_num;
D
Daniel Larimer 已提交
1437
   return head_block_abs_slot;
N
Nathan Hourt 已提交
1438 1439
}

D
Daniel Larimer 已提交
1440
uint32_t chain_controller::get_slot_at_time( block_timestamp_type when )const
N
Nathan Hourt 已提交
1441
{
D
Daniel Larimer 已提交
1442
   auto first_slot_time = get_slot_time(1);
N
Nathan Hourt 已提交
1443 1444
   if( when < first_slot_time )
      return 0;
D
Daniel Larimer 已提交
1445
   return block_timestamp_type(when).slot - first_slot_time.slot + 1;
N
Nathan Hourt 已提交
1446 1447
}

1448
uint32_t chain_controller::producer_participation_rate()const
N
Nathan Hourt 已提交
1449 1450
{
   const dynamic_global_property_object& dpo = get_dynamic_global_properties();
D
Daniel Larimer 已提交
1451
   return uint64_t(config::percent_100) * __builtin_popcountll(dpo.recent_slots_filled) / 64;
N
Nathan Hourt 已提交
1452 1453
}

D
Daniel Larimer 已提交
1454 1455
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;
1456
}
N
Nathan Hourt 已提交
1457

1458
static void log_handled_exceptions(const transaction& trx) {
B
Bart Wyatt 已提交
1459 1460 1461 1462
   try {
      throw;
   } catch (const checktime_exceeded&) {
      throw;
1463
   } FC_CAPTURE_AND_LOG((trx));
B
Bart Wyatt 已提交
1464 1465
}

1466 1467
transaction_trace chain_controller::__apply_transaction( transaction_metadata& meta ) {
   transaction_trace result(meta.id);
D
Daniel Larimer 已提交
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478

   for (const auto &act : meta.trx().context_free_actions) {
      FC_ASSERT( act.authorization.size() == 0, "context free actions cannot require authorization" );
      apply_context context(*this, _db, act, meta);
      context.context_free = true;
      context.exec();
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
      FC_ASSERT( result.deferred_transactions.size() == 0 );
      FC_ASSERT( result.canceled_deferred.size() == 0 );
   }

1479
   for (const auto &act : meta.trx().actions) {
1480
      apply_context context(*this, _db, act, meta);
1481
      context.exec();
D
Daniel Larimer 已提交
1482 1483 1484
      context.used_context_free_api |= act.authorization.size();

      FC_ASSERT( context.used_context_free_api, "action did not reference database state, it should be moved to context_free_actions", ("act",act) );
1485 1486
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));
1487
      fc::move_append(result.canceled_deferred, std::move(context.results.canceled_deferred));
1488
   }
B
Bart Wyatt 已提交
1489

1490
   uint32_t act_usage = result.action_traces.size();
1491

1492 1493 1494 1495
   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 已提交
1496
          at.act.account == config::system_account_name &&
1497 1498
          at.act.name == N(setcode)) {
         act_usage += config::setcode_act_usage;
B
Bart Wyatt 已提交
1499
      }
1500
   }
B
Bart Wyatt 已提交
1501

1502
   update_usage(meta, act_usage);
1503
   record_transaction(meta.trx());
1504 1505
   return result;
}
B
Bart Wyatt 已提交
1506

1507 1508 1509 1510 1511 1512
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 已提交
1513 1514
   } catch (...) {
      // if there is no sender, there is no error handling possible, rethrow
1515
      if (!meta.sender) {
B
Bart Wyatt 已提交
1516 1517
         throw;
      }
1518
      // log exceptions we can handle with the error handle, throws otherwise
1519
      log_handled_exceptions(meta.trx());
1520

B
Bart Wyatt 已提交
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530
      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}},
1531
                             contracts::onerror(meta.raw_data, meta.raw_data + meta.raw_size) );
B
Bart Wyatt 已提交
1532 1533

   try {
1534 1535
      auto temp_session = _db.start_undo_session(true);

1536
      apply_context context(*this, _db, etrx.actions.front(), meta);
D
Daniel Larimer 已提交
1537
      context.exec();
1538
      fc::move_append(result.action_traces, std::move(context.results.applied_actions));
B
Bart Wyatt 已提交
1539 1540
      fc::move_append(result.deferred_transactions, std::move(context.results.generated_transactions));

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

B
Bart Wyatt 已提交
1543 1544 1545
      for (auto &at: result.action_traces) {
         at.region_id = meta.region_id;
         at.cycle_index = meta.cycle_index;
1546
      }
1547

B
Bart Wyatt 已提交
1548
      update_usage(meta, act_usage);
1549
      record_transaction(meta.trx());
1550 1551

      temp_session.squash();
B
Bart Wyatt 已提交
1552
      return result;
1553

B
Bart Wyatt 已提交
1554
   } catch (...) {
1555 1556 1557 1558
      // 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 已提交
1559 1560 1561 1562
   }

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

1566
void chain_controller::push_deferred_transactions( bool flush )
B
Bart Wyatt 已提交
1567
{
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584
   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 已提交
1585

1586 1587
      maybe_start_new_cycle();
   }
B
Bart Wyatt 已提交
1588

1589 1590 1591
   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 已提交
1592

1593 1594 1595 1596
   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 已提交
1597

1598 1599 1600 1601
   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());
1602
            transaction_metadata mtrx (trx, trx_p->published, trx.sender, trx.sender_id, trx_p->packed_trx.data(), trx_p->packed_trx.size());
1603
            _push_transaction(std::move(mtrx));
1604 1605 1606 1607 1608
            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 已提交
1609 1610 1611 1612
   }
}


1613 1614 1615 1616 1617
/**
 *  @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 )
{
1618 1619
   const auto& config = _db.get<resource_limits_config_object>();
   const auto& state = _db.get<resource_limits_state_object>();
1620
   set<std::pair<account_name, permission_name>> authorizing_accounts;
1621

1622
   for( const auto& act : meta.trx().actions )
1623
      for( const auto& auth : act.authorization )
1624
         authorizing_accounts.emplace( auth.actor, auth.permission );
1625

1626 1627
   auto net_usage = meta.bandwidth_usage + config.base_per_transaction_net_usage;
   auto cpu_usage = act_usage + config.base_per_transaction_net_usage;
1628

1629
   // charge a system controlled amount for signature verification/recovery
1630
   if( meta.signing_keys ) {
1631
      cpu_usage += meta.signing_keys->size() * config.per_signature_cpu_usage;
1632 1633
   }

1634 1635
   auto head_time = head_block_time();
   for( const auto& authaccnt : authorizing_accounts ) {
1636

1637 1638 1639 1640 1641
      const auto& usage = _db.get<resource_usage_object,by_owner>( authaccnt.first );
      const auto& limits = _db.get<resource_limits_object,by_owner>( boost::make_tuple(false, authaccnt.first));
      _db.modify( usage, [&]( auto& bu ){
          bu.net_usage.add_usage( net_usage, head_time );
          bu.cpu_usage.add_usage( cpu_usage, head_time );
1642
      });
1643

1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
      uint128_t  consumed_cpu_ex = usage.cpu_usage.value // this is pre-multiplied by config::rate_limiting_precision
      uint128_t  capacity_cpu_ex = state.virtual_cpu_limit * config::rate_limiting_precision;
      EOS_ASSERT( limits.cpu_weight < 0 || (consumed_cpu_ex * state.total_cpu_weight) <= (limits.cpu_weight * capacity_cpu_ex),
                  tx_resource_exhausted,
                  "authorizing account '${n}' has insufficient cpu resources for this transaction",
                  ("n",                    name(authaccnt.first))
                  ("consumed",             (double)consumed_cpu_ex/(double)config::rate_limiting_precision)
                  ("cpu_weight",           limits.cpu_weight)
                  ("virtual_cpu_capacity", (double)state.virtual_cpu_limit/(double)config::rate_limiting_precision )
                  ("total_cpu_weight",     state.total_cpu_weight)
      );

      uint128_t  consumed_net_ex = usage.net_usage.value // this is pre-multiplied by config::rate_limiting_precision
      uint128_t  capacity_net_ex = state.virtual_net_limit * config::rate_limiting_precision;

      EOS_ASSERT( limits.net_weight < 0 || (consumed_net_ex * state.total_net_weight) <= (limits.net_weight * capacity_net_ex),
                  tx_resource_exhausted,
                  "authorizing account '${n}' has insufficient cpu resources for this transaction",
                  ("n",                    name(authaccnt.first))
                  ("consumed",             (double)consumed_net_ex/(double)config::rate_limiting_precision)
                  ("net_weight",           limits.net_weight)
                  ("virtual_net_capacity", (double)state.virtual_net_limit/(double)config::rate_limiting_precision )
                  ("total_net_weight",     state.total_net_weight)
      );
1668 1669 1670

      // for any transaction not sent by code, update the affirmative last time a given permission was used
      if (!meta.sender) {
1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
         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();
            });
         }
1683
      }
1684 1685
   }

B
Bart Wyatt 已提交
1686 1687
   _db.modify( state, [&]( rate_limiting_state_object& rls ) {
      rls.average_block_cpu_usage.add_usage( cpu_usage, head_time );
1688
   });
D
Daniel Larimer 已提交
1689 1690 1691 1692 1693 1694 1695
}

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 ) );
1696
      if( handler != native_handler_scope->second.end() )
D
Daniel Larimer 已提交
1697 1698 1699 1700 1701
         return &handler->second;
   }
   return nullptr;
}

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