controller.cpp 47.8 KB
Newer Older
D
Daniel Larimer 已提交
1
#include <eosio/chain/controller.hpp>
2
#include <eosio/chain/transaction_context.hpp>
D
Daniel Larimer 已提交
3 4 5 6 7 8 9 10 11 12 13 14

#include <eosio/chain/block_log.hpp>
#include <eosio/chain/fork_database.hpp>

#include <eosio/chain/account_object.hpp>
#include <eosio/chain/scope_sequence_object.hpp>
#include <eosio/chain/block_summary_object.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/contract_table_objects.hpp>
#include <eosio/chain/generated_transaction_object.hpp>
#include <eosio/chain/transaction_object.hpp>

15
#include <eosio/chain/authorization_manager.hpp>
D
Daniel Larimer 已提交
16 17
#include <eosio/chain/resource_limits.hpp>

D
Daniel Larimer 已提交
18
#include <chainbase/chainbase.hpp>
D
Daniel Larimer 已提交
19 20
#include <fc/io/json.hpp>

D
Daniel Larimer 已提交
21 22
#include <eosio/chain/eosio_contract.hpp>

D
Daniel Larimer 已提交
23 24 25 26
namespace eosio { namespace chain {

using resource_limits::resource_limits_manager;

D
Daniel Larimer 已提交
27

D
Daniel Larimer 已提交
28 29 30 31 32 33 34 35
struct pending_state {
   pending_state( database::session&& s )
   :_db_session( move(s) ){}

   database::session                  _db_session;

   block_state_ptr                    _pending_block_state;

D
Daniel Larimer 已提交
36
   vector<action_receipt>             _actions;
D
Daniel Larimer 已提交
37

D
Daniel Larimer 已提交
38

D
Daniel Larimer 已提交
39 40 41 42 43 44
   void push() {
      _db_session.push();
   }
};

struct controller_impl {
D
Daniel Larimer 已提交
45
   controller&                    self;
D
Daniel Larimer 已提交
46 47 48
   chainbase::database            db;
   block_log                      blog;
   optional<pending_state>        pending;
49 50
   block_state_ptr                head;
   fork_database                  fork_db;
D
Daniel Larimer 已提交
51
   wasm_interface                 wasmif;
D
Daniel Larimer 已提交
52
   resource_limits_manager        resource_limits;
53
   authorization_manager          authorization;
D
Daniel Larimer 已提交
54
   controller::config             conf;
D
Daniel Larimer 已提交
55
   bool                           replaying = false;
D
Daniel Larimer 已提交
56

D
Daniel Larimer 已提交
57 58 59
   typedef pair<scope_name,action_name>                   handler_key;
   map< account_name, map<handler_key, apply_handler> >   apply_handlers;

D
Daniel Larimer 已提交
60 61 62 63 64
   /**
    *  Transactions that were undone by pop_block or abort_block, transactions
    *  are removed from this list if they are re-applied in other blocks. Producers
    *  can query this list when scheduling new transactions into blocks.
    */
65
   map<digest_type, transaction_metadata_ptr>     unapplied_transactions;
D
Daniel Larimer 已提交
66

D
Daniel Larimer 已提交
67
   void pop_block() {
68 69
      auto prev = fork_db.get_block( head->header.previous );
      FC_ASSERT( prev, "attempt to pop beyond last irreversible block" );
D
Daniel Larimer 已提交
70
      for( const auto& t : head->trxs )
71
         unapplied_transactions[t->signed_id] = t;
72
      head = prev;
D
Daniel Larimer 已提交
73
      db.undo();
D
Daniel Larimer 已提交
74 75 76
   }


D
Daniel Larimer 已提交
77 78 79 80
   void set_apply_handler( account_name contract, scope_name scope, action_name action, apply_handler v ) {
      apply_handlers[contract][make_pair(scope,action)] = v;
   }

D
Daniel Larimer 已提交
81
   controller_impl( const controller::config& cfg, controller& s  )
D
Daniel Larimer 已提交
82 83
   :self(s),
    db( cfg.shared_memory_dir,
D
Daniel Larimer 已提交
84 85 86
        cfg.read_only ? database::read_only : database::read_write,
        cfg.shared_memory_size ),
    blog( cfg.block_log_dir ),
D
Daniel Larimer 已提交
87
    fork_db( cfg.shared_memory_dir ),
D
Daniel Larimer 已提交
88
    wasmif( cfg.wasm_runtime ),
D
Daniel Larimer 已提交
89
    resource_limits( db ),
D
Daniel Larimer 已提交
90 91
    authorization( s, db ),
    conf( cfg )
D
Daniel Larimer 已提交
92
   {
D
Daniel Larimer 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109

#define SET_APP_HANDLER( contract, scope, action, nspace ) \
   set_apply_handler( #contract, #scope, #action, &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) )
   SET_APP_HANDLER( eosio, eosio, newaccount, eosio );
   SET_APP_HANDLER( eosio, eosio, setcode, eosio );
   SET_APP_HANDLER( eosio, eosio, setabi, eosio );
   SET_APP_HANDLER( eosio, eosio, updateauth, eosio );
   SET_APP_HANDLER( eosio, eosio, deleteauth, eosio );
   SET_APP_HANDLER( eosio, eosio, linkauth, eosio );
   SET_APP_HANDLER( eosio, eosio, unlinkauth, eosio );
   SET_APP_HANDLER( eosio, eosio, onerror, eosio );
   SET_APP_HANDLER( eosio, eosio, postrecovery, eosio );
   SET_APP_HANDLER( eosio, eosio, passrecovery, eosio );
   SET_APP_HANDLER( eosio, eosio, vetorecovery, eosio );
   SET_APP_HANDLER( eosio, eosio, canceldelay, eosio );


D
Daniel Larimer 已提交
110 111 112 113
   }

   void init() {
      // ilog( "${c}", ("c",fc::json::to_pretty_string(cfg)) );
114
      add_indices();
D
Daniel Larimer 已提交
115 116

      /**
117 118 119 120 121 122 123 124 125 126 127 128 129 130
      *  The fork database needs an initial block_state to be set before
      *  it can accept any new blocks. This initial block state can be found
      *  in the database (whose head block state should be irreversible) or
      *  it would be the genesis state.
      */
      if( !head ) {
         initialize_fork_db(); // set head to genesis state
      }

      FC_ASSERT( db.revision() == head->block_num, "fork database is inconsistent with shared memory",
                 ("db",db.revision())("head",head->block_num) );

      /**
       * The undoable state contains state transitions from blocks
D
Daniel Larimer 已提交
131 132 133 134 135
       * in the fork database that could be reversed. Because this
       * is a new startup and the fork database is empty, we must
       * unwind that pending state. This state will be regenerated
       * when we catch up to the head block later.
       */
136
      //clear_all_undo();
D
Daniel Larimer 已提交
137 138 139 140
   }

   ~controller_impl() {
      pending.reset();
D
Daniel Larimer 已提交
141 142 143

      edump((db.revision())(head->block_num));

D
Daniel Larimer 已提交
144 145 146
      db.flush();
   }

147
   void add_indices() {
D
Daniel Larimer 已提交
148
      db.add_index<account_index>();
149
      db.add_index<account_sequence_index>();
D
Daniel Larimer 已提交
150

D
Daniel Larimer 已提交
151 152 153 154 155 156
      db.add_index<table_id_multi_index>();
      db.add_index<key_value_index>();
      db.add_index<index64_index>();
      db.add_index<index128_index>();
      db.add_index<index256_index>();
      db.add_index<index_double_index>();
K
Khaled Al-Hassanieh 已提交
157
      db.add_index<index_long_double_index>();
D
Daniel Larimer 已提交
158 159 160 161 162 163 164 165

      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>();
      db.add_index<generated_transaction_multi_index>();
      db.add_index<scope_sequence_multi_index>();

166 167
      authorization.add_indices();
      resource_limits.add_indices();
D
Daniel Larimer 已提交
168 169 170 171 172 173 174
   }

   void clear_all_undo() {
      // Rewind the database to the last irreversible block
      db.with_write_lock([&] {
         db.undo_all();
         /*
175
         FC_ASSERT(db.revision() == self.head_block_num(),
D
Daniel Larimer 已提交
176 177 178 179 180 181 182
                   "Chainbase revision does not match head block num",
                   ("rev", db.revision())("head_block", self.head_block_num()));
                   */
      });
   }

   /**
183
    *  Sets fork database head to the genesis state.
D
Daniel Larimer 已提交
184 185
    */
   void initialize_fork_db() {
186 187
      wlog( " Initializing new blockchain with genesis state                  " );
      producer_schedule_type initial_schedule{ 0, {{N(eosio), conf.genesis.initial_key}} };
D
Daniel Larimer 已提交
188

189 190 191 192 193 194 195 196
      block_header_state genheader;
      genheader.active_schedule       = initial_schedule;
      genheader.pending_schedule      = initial_schedule;
      genheader.pending_schedule_hash = fc::sha256::hash(initial_schedule);
      genheader.header.timestamp      = conf.genesis.initial_timestamp;
      genheader.header.action_mroot   = conf.genesis.compute_chain_id();
      genheader.id                    = genheader.header.id();
      genheader.block_num             = genheader.header.block_num();
D
Daniel Larimer 已提交
197

198
      head = std::make_shared<block_state>( genheader );
D
Daniel Larimer 已提交
199
      head->block = std::make_shared<signed_block>(genheader.header);
200
      fork_db.set( head );
D
Daniel Larimer 已提交
201 202 203
      db.set_revision( head->block_num );

      initialize_database();
A
arhag 已提交
204

D
Daniel Larimer 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
      auto end = blog.read_head();
      if( end && end->block_num() > 1 ) {
         replaying = true;
         ilog( "existing block log, attempting to replay ${n} blocks", ("n",end->block_num()) );

         auto start = fc::time_point::now();
         while( auto next = blog.read_block_by_num( head->block_num + 1 ) ) {
            self.push_block( next );
            if( next->block_num() % 10 == 0 ) {
               std::cerr << std::setw(10) << next->block_num() << " of " << end->block_num() <<"\r";
            }
         }
         std::cerr<< "\n";
         auto end = fc::time_point::now();
         ilog( "replayed blocks in ${n} seconds", ("n", (end-start).count()/1000000.0) );
         replaying = false;

      } else if( !end ) {
         blog.append( head->block );
      }
D
Daniel Larimer 已提交
225 226
   }

227
   void create_native_account( account_name name, const authority& owner, const authority& active, bool is_privileged = false ) {
228
      db.create<account_object>([&](auto& a) {
D
Daniel Larimer 已提交
229 230
         a.name = name;
         a.creation_date = conf.genesis.initial_timestamp;
231
         a.privileged = is_privileged;
D
Daniel Larimer 已提交
232 233

         if( name == config::system_account_name ) {
D
Daniel Larimer 已提交
234
            a.set_abi(eosio_contract_abi(abi_def()));
D
Daniel Larimer 已提交
235 236
         }
      });
237 238 239 240
      db.create<account_sequence_object>([&](auto & a) {
        a.name = name;
      });

241 242 243 244
      const auto& owner_permission  = authorization.create_permission(name, config::owner_name, 0,
                                                                      owner, conf.genesis.initial_timestamp );
      const auto& active_permission = authorization.create_permission(name, config::active_name, owner_permission.id,
                                                                      active, conf.genesis.initial_timestamp );
D
Daniel Larimer 已提交
245 246

      resource_limits.initialize_account(name);
247 248 249 250 251 252 253 254
      resource_limits.add_pending_account_ram_usage(
         name,
         (int64_t)(config::billable_size_v<permission_object> + owner_permission.auth.get_billable_size())
      );
      resource_limits.add_pending_account_ram_usage(
         name,
         (int64_t)(config::billable_size_v<permission_object> + active_permission.auth.get_billable_size())
      );
D
Daniel Larimer 已提交
255 256 257 258 259 260 261
   }

   void initialize_database() {
      // Initialize block summary index
      for (int i = 0; i < 0x10000; i++)
         db.create<block_summary_object>([&](block_summary_object&) {});

262 263 264 265 266
      const auto& tapos_block_summary = db.get<block_summary_object>(1);
      db.modify( tapos_block_summary, [&]( auto& bs ) {
        bs.block_id = head->id;
      });

267 268 269 270
      db.create<global_property_object>([&](auto& gpo ){
        gpo.configuration = conf.genesis.initial_configuration;
      });
      db.create<dynamic_global_property_object>([](auto&){});
271 272 273 274 275 276

      authorization.initialize_database();
      resource_limits.initialize_database();

      authority system_auth(conf.genesis.initial_key);
      create_native_account( config::system_account_name, system_auth, system_auth, true );
D
Daniel Larimer 已提交
277

278 279
      auto empty_authority = authority(1, {}, {});
      auto active_producers_authority = authority(1, {}, {});
D
Daniel Larimer 已提交
280 281
      active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1});

282 283
      create_native_account( config::nobody_account_name, empty_authority, empty_authority );
      create_native_account( config::producers_account_name, empty_authority, active_producers_authority );
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
      const auto& active_permission       = authorization.get_permission({config::producers_account_name, config::active_name});
      const auto& majority_permission     = authorization.create_permission( config::producers_account_name,
                                                                             config::majority_producers_permission_name,
                                                                             active_permission.id,
                                                                             active_producers_authority,
                                                                             conf.genesis.initial_timestamp );
      const auto& minority_permission     = authorization.create_permission( config::producers_account_name,
                                                                             config::minority_producers_permission_name,
                                                                             majority_permission.id,
                                                                             active_producers_authority,
                                                                             conf.genesis.initial_timestamp );
      const auto& any_producer_permission = authorization.create_permission( config::producers_account_name,
                                                                             config::any_producer_permission_name,
                                                                             minority_permission.id,
                                                                             active_producers_authority,
                                                                             conf.genesis.initial_timestamp );
D
Daniel Larimer 已提交
300 301
   }

302

303

A
arhag 已提交
304
   void commit_block( bool add_to_fork_db ) {
D
Daniel Larimer 已提交
305 306
      if( add_to_fork_db ) {
         pending->_pending_block_state->validated = true;
307 308 309
         auto new_bsp = fork_db.add( pending->_pending_block_state );
         head = fork_db.head();
         FC_ASSERT( new_bsp == head, "committed block did not become the new head in fork database" );
310
      }
311

312
      //ilog((fc::json::to_pretty_string(*pending->_pending_block_state->block)));
D
Daniel Larimer 已提交
313
      self.accepted_block( pending->_pending_block_state );
D
Daniel Larimer 已提交
314 315
      pending->push();
      pending.reset();
D
Daniel Larimer 已提交
316 317 318 319

      if( !replaying ) {
         self.log_irreversible_blocks();
      }
D
Daniel Larimer 已提交
320
   }
D
Daniel Larimer 已提交
321

322
   transaction_trace_ptr apply_onerror( const generated_transaction_object& gto, fc::time_point deadline, uint32_t cpu_usage ) {
D
Daniel Larimer 已提交
323 324 325
      signed_transaction etrx;
      etrx.actions.emplace_back(vector<permission_level>{{gto.sender,config::active_name}},
                                onerror( gto.sender_id, gto.packed_trx.data(), gto.packed_trx.size()) );
D
Daniel Larimer 已提交
326

D
Daniel Larimer 已提交
327 328 329 330 331 332 333 334 335 336

      etrx.expiration = self.pending_block_time() + fc::seconds(1);
      etrx.set_reference_block( self.head_block_id() );

      transaction_context trx_context( self, etrx, etrx.id() );
      trx_context.deadline = deadline;
      /// TODO: forward cpu usage into error trx_context.cpu_usage = cpu_usage;
      trx_context.is_input  = false;
      trx_context.exec();

337
      self.applied_transaction(trx_context.trace);
D
Daniel Larimer 已提交
338 339 340
      trx_context.squash();

      return move(trx_context.trace);
D
Daniel Larimer 已提交
341 342
   }

D
Daniel Larimer 已提交
343 344 345
   void expire_scheduled_transaction( const generated_transaction_object& gto ) {
      auto receipt = push_receipt( gto.trx_id, transaction_receipt::expired, 0, 0 );

346
      resource_limits.add_pending_account_ram_usage(gto.payer,
D
Daniel Larimer 已提交
347 348 349 350 351
               -(config::billable_size_v<generated_transaction_object> + gto.packed_trx.size()));

      db.remove( gto );
   }

D
Daniel Larimer 已提交
352
   void push_scheduled_transaction( const generated_transaction_object& gto, fc::time_point deadline  ) {
D
Daniel Larimer 已提交
353
      fc::datastream<const char*> ds( gto.packed_trx.data(), gto.packed_trx.size() );
D
Daniel Larimer 已提交
354

355
      FC_ASSERT( gto.delay_until <= self.pending_block_time(), "this transaction isn't ready", ("gto.delay_until",gto.delay_until)("pbt",self.pending_block_time()) );
D
Daniel Larimer 已提交
356 357 358 359
      if( gto.expiration <= self.pending_block_time() ) {
         expire_scheduled_transaction( gto );
         return;
      }
360 361 362

      optional<fc::exception> soft_except;
      optional<fc::exception> hard_except;
D
Daniel Larimer 已提交
363 364
      std::exception_ptr soft_except_ptr;
      std::exception_ptr hard_except_ptr;
365

366 367
      auto sender = gto.sender;

D
Daniel Larimer 已提交
368
      transaction_trace_ptr trace;
369
      uint32_t apply_cpu_usage = 0;
D
Daniel Larimer 已提交
370 371 372
      try {
         signed_transaction dtrx;
         fc::raw::unpack(ds,static_cast<transaction&>(dtrx) );
373 374

         transaction_context trx_context( self, dtrx, gto.trx_id );
D
Daniel Larimer 已提交
375
         trace = trx_context.trace;
376

377
         trx_context.trace->scheduled = true;
378 379 380 381 382 383 384 385 386 387 388 389 390 391
         trx_context.deadline  = deadline;
         trx_context.published = gto.published;
         trx_context.net_usage = 0;
         trx_context.apply_context_free = false;
         trx_context.is_input           = false;
         try {
            trx_context.exec();
         } catch ( ... ) {
            apply_cpu_usage = trx_context.trace->cpu_usage;
            throw;
         }

         fc::move_append( pending->_actions, move(trx_context.executed) );

A
arhag 已提交
392 393 394 395
         trx_context.trace->receipt = push_receipt( gto.trx_id,
                                                    transaction_receipt::executed,
                                                    trx_context.trace->kcpu_usage(),
                                                    0 );
396 397

         db.remove( gto );
398

D
Daniel Larimer 已提交
399
         self.applied_transaction( trx_context.trace );
400
         trx_context.squash();
401 402

         return;
D
Daniel Larimer 已提交
403
      } catch( const fc::exception& e ) {
404
         soft_except = e;
D
Daniel Larimer 已提交
405
         soft_except_ptr = std::current_exception();
D
Daniel Larimer 已提交
406
      }
407
      if( soft_except && sender != account_name() ) { /// TODO: soft errors should not go to error handlers (deadline error)
408 409 410 411
         edump((soft_except->to_detail_string()));
         try {
            auto trace = apply_onerror( gto, deadline, apply_cpu_usage  );
            trace->soft_except = soft_except;
D
Daniel Larimer 已提交
412
            self.applied_transaction( trace );
413 414
         } catch ( const fc::exception& e ) {
            hard_except = e;
D
Daniel Larimer 已提交
415
            trace->hard_except_ptr = std::current_exception();
416
         }
D
Daniel Larimer 已提交
417
      }
418

419
      /*
420
      if( hard_except )
421
         edump((hard_except->to_detail_string()));
422
      if( soft_except )
423 424 425
         edump((soft_except->to_detail_string()));
       */

426
      FC_ASSERT( bool(trace), "failed to deserialize transaction" );
427
      trace->receipt  = push_receipt( gto.trx_id, transaction_receipt::hard_fail, (apply_cpu_usage+1023)/1024, 0 );
D
Daniel Larimer 已提交
428 429
      trace->soft_except = soft_except;
      trace->hard_except = hard_except;
D
Daniel Larimer 已提交
430 431
      trace->soft_except_ptr = soft_except_ptr;
      trace->hard_except_ptr = hard_except_ptr;
432 433 434

      db.remove( gto );

D
Daniel Larimer 已提交
435
      self.applied_transaction( trace );
D
Daniel Larimer 已提交
436
   } /// push_scheduled_transaction
D
Daniel Larimer 已提交
437

438 439 440 441

   /**
    *  Adds the transaction receipt to the pending block and returns it.
    */
442 443
   template<typename T>
   const transaction_receipt& push_receipt( const T& trx, transaction_receipt_header::status_enum status,
444 445 446 447 448 449 450 451 452
                      uint32_t kcpu_usage, uint32_t net_usage_words ) {
      pending->_pending_block_state->block->transactions.emplace_back( trx );
      transaction_receipt& r = pending->_pending_block_state->block->transactions.back();
      r.kcpu_usage           = kcpu_usage;
      r.net_usage_words      = net_usage_words;
      r.status               = status;
      return r;
   }

453
   bool push_next_unapplied_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
454
      auto itr = unapplied_transactions.begin();
455
      if( itr == unapplied_transactions.end() )
456
         return false;
D
Daniel Larimer 已提交
457

458 459 460
      // Intentionally copy transaction_metadata_ptr because it will be removed from unapplied_transactions and make the const& dangling.
      push_transaction( transaction_metadata_ptr(itr->second), deadline );
      return true;
D
Daniel Larimer 已提交
461 462
   }

463 464
   void transaction_trace_notify( const transaction_metadata_ptr& trx, const transaction_trace_ptr& trace ) {
      if( trx->on_result ) {
465 466
         (trx->on_result)(trace);
         trx->on_result = decltype(trx->on_result)(); //assign empty std::function
467 468
      }
   }
469

470 471 472 473 474
   /**
    *  This is the entry point for new transactions to the block state. It will check authorization and
    *  determine whether to execute it now or to delay it. Lastly it inserts a transaction receipt into
    *  the pending block.
    */
475 476
   void push_transaction( const transaction_metadata_ptr& trx,
                          fc::time_point deadline = fc::time_point::maximum(),
D
Daniel Larimer 已提交
477
                          bool implicit = false ) {
D
Daniel Larimer 已提交
478 479 480
      //if( !implicit )
      //   idump((fc::json::to_pretty_string(trx->trx)));

D
Daniel Larimer 已提交
481
      if( deadline == fc::time_point() ) {
482
         unapplied_transactions[trx->signed_id] = trx;
D
Daniel Larimer 已提交
483 484
         return;
      }
485

486
      transaction_trace_ptr trace;
D
Daniel Larimer 已提交
487 488
      try {
         unapplied_transactions.erase( trx->signed_id );
489

D
Daniel Larimer 已提交
490
         transaction_context trx_context( self, trx->trx, trx->id );
491
         trace = trx_context.trace;
492

493 494 495 496
         fc::microseconds required_delay(0);
         if (!implicit) {
            required_delay = limit_delay( authorization.check_authorization( trx->trx.actions, trx->recover_keys() ) );
         }
497 498 499 500
         trx_context.delay = fc::seconds(trx->trx.delay_sec);
         EOS_ASSERT( trx_context.delay >= required_delay, transaction_exception,
                     "authorization imposes a delay (${required_delay} sec) greater than the delay specified in transaction header (${specified_delay} sec)",
                     ("required_delay", required_delay.to_seconds())("specified_delay", trx_context.delay.to_seconds()) );
501

D
Daniel Larimer 已提交
502 503
         trx_context.deadline  = deadline;
         trx_context.published = self.pending_block_time();
A
arhag 已提交
504
         trx_context.net_usage = self.validate_net_usage( trx ); // Returns multiple of 8
D
Daniel Larimer 已提交
505 506
         trx_context.is_input  = !implicit;
         trx_context.exec();
507

D
Daniel Larimer 已提交
508 509 510 511
         fc::move_append( pending->_actions, move(trx_context.executed) );

         if( !implicit ) {
            if( trx_context.delay == fc::seconds(0) ) {
A
arhag 已提交
512
               trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::executed, trace->kcpu_usage(), trx_context.net_usage/8 );
D
Daniel Larimer 已提交
513
            } else {
A
arhag 已提交
514
               trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::delayed, trace->kcpu_usage(), trx_context.net_usage/8 );
D
Daniel Larimer 已提交
515
            }
516
         }
517

518 519 520 521 522
         transaction_trace_notify(trx, trace);

         if( !implicit )
            pending->_pending_block_state->trxs.emplace_back(trx);

D
Daniel Larimer 已提交
523
         self.accepted_transaction(trx);
524
         self.applied_transaction(trace);
D
Daniel Larimer 已提交
525
         trx_context.squash();
526
         return;
D
Daniel Larimer 已提交
527
      } catch ( const fc::exception& e ) {
528
         trace->soft_except = e;
D
Daniel Larimer 已提交
529
         trace->hard_except_ptr = std::current_exception();
530 531
         //wlog( "caught exception in push_transaction" );
         //wdump((trace));
D
Daniel Larimer 已提交
532
      }
533
      transaction_trace_notify(trx, trace);
534

535
   } /// push_transaction
D
Daniel Larimer 已提交
536

537

538
   void start_block( block_timestamp_type when ) {
539
      FC_ASSERT( !pending );
D
Daniel Larimer 已提交
540

541
      FC_ASSERT( db.revision() == head->block_num, "",
A
arhag 已提交
542
                ("db_head_block", db.revision())("controller_head_block", head->block_num)("fork_db_head_block", fork_db.head()->block_num) );
D
Daniel Larimer 已提交
543

544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
      pending = db.start_undo_session(true);
      pending->_pending_block_state = std::make_shared<block_state>( *head, when ); // promotes pending schedule (if any) to active
      pending->_pending_block_state->in_current_chain = true;

      const auto& gpo = db.get<global_property_object>();
      if( gpo.proposed_schedule_block_num.valid() && // if there is a proposed schedule that was proposed in a block ...
          ( *gpo.proposed_schedule_block_num <= pending->_pending_block_state->dpos_last_irreversible_blocknum ) && // ... that has now become irreversible ...
          pending->_pending_block_state->pending_schedule.producers.size() == 0 && // ... and there is room for a new pending schedule ...
          head->pending_schedule.producers.size() == 0 // ... and not just because it was promoted to active at the start of this block, then:
        )
      {
         // Promote proposed schedule to pending schedule.
         ilog( "promoting proposed schedule (set in block ${proposed_num}) to pending; current block: ${n} lib: ${lib} schedule: ${schedule} ",
               ("proposed_num", *gpo.proposed_schedule_block_num)("n", pending->_pending_block_state->block_num)
               ("lib", pending->_pending_block_state->dpos_last_irreversible_blocknum)
               ("schedule", static_cast<producer_schedule_type>(gpo.proposed_schedule) ) );
         pending->_pending_block_state->set_new_producers( gpo.proposed_schedule );
         db.modify( gpo, [&]( auto& gp ) {
            gp.proposed_schedule_block_num = optional<block_num_type>();
            gp.proposed_schedule.clear();
         });
      }
D
Daniel Larimer 已提交
566

567 568 569 570 571 572
      try {
         auto onbtrx = std::make_shared<transaction_metadata>( get_on_block_transaction() );
         push_transaction( onbtrx, fc::time_point::maximum(), true );
      } catch ( ... ) {
         ilog( "on block transaction failed, but shouldn't impact block generation, system contract needs update" );
      }
A
arhag 已提交
573 574 575

      clear_expired_input_transactions();
      update_producers_authority();
576
   } // start_block
D
Daniel Larimer 已提交
577 578


D
Daniel Larimer 已提交
579

580 581
   void sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
      auto p = pending->_pending_block_state;
582
      p->sign( signer_callback );
583 584
      static_cast<signed_block_header&>(*p->block) = p->header;
   } /// sign_block
D
Daniel Larimer 已提交
585

586
   void apply_block( const signed_block_ptr& b ) { try {
587 588 589 590 591 592 593 594 595
      try {
         start_block( b->timestamp );

         for( const auto& receipt : b->transactions ) {
            if( receipt.trx.contains<packed_transaction>() ) {
               auto& pt = receipt.trx.get<packed_transaction>();
               auto mtrx = std::make_shared<transaction_metadata>(pt);
               push_transaction( mtrx );
            }
D
Daniel Larimer 已提交
596 597 598
            else if( receipt.trx.contains<transaction_id_type>() ) {
               self.push_scheduled_transaction( receipt.trx.get<transaction_id_type>() );
            }
599
         }
D
Daniel Larimer 已提交
600

601 602
         finalize_block();
         sign_block( [&]( const auto& ){ return b->producer_signature; } );
D
Daniel Larimer 已提交
603

604 605 606
         // this is implied by the signature passing
         //FC_ASSERT( b->id() == pending->_pending_block_state->block->id(),
         //           "applying block didn't produce expected block id" );
D
Daniel Larimer 已提交
607

608 609
         commit_block(false);
         return;
D
Daniel Larimer 已提交
610
      } catch ( const fc::exception& e ) {
611 612
         edump((e.to_detail_string()));
         abort_block();
D
Daniel Larimer 已提交
613 614
         throw;
      }
615
   } FC_CAPTURE_AND_RETHROW() } /// apply_block
616 617


618
   void push_block( const signed_block_ptr& b ) {
D
Daniel Larimer 已提交
619 620 621 622
      try {
         auto new_header_state = fork_db.add( b );
         self.accepted_block_header( new_header_state );
         maybe_switch_forks();
A
arhag 已提交
623
      } FC_LOG_AND_RETHROW()
624
   }
625

626 627 628 629 630 631 632
   void push_confirmation( const header_confirmation& c ) {
      fork_db.add( c );
      self.accepted_confirmation( c );
      maybe_switch_forks();
   }

   void maybe_switch_forks() {
633 634 635 636
      auto new_head = fork_db.head();

      if( new_head->header.previous == head->id ) {
         try {
637
            abort_block();
638
            apply_block( new_head->block );
639
            fork_db.mark_in_current_chain( new_head, true );
640 641 642
            fork_db.set_validity( new_head, true );
            head = new_head;
         } catch ( const fc::exception& e ) {
643
            fork_db.set_validity( new_head, false ); // Removes new_head from fork_db index, so no need to mark it as not in the current chain.
644 645
            throw;
         }
646
      } else if( new_head->id != head->id ) {
647
         ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
A
arhag 已提交
648
              ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) );
649 650
         auto branches = fork_db.fetch_branch_from( new_head->id, head->id );

651 652
         for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) {
            fork_db.mark_in_current_chain( *itr , false );
653
            pop_block();
654
         }
A
arhag 已提交
655
         FC_ASSERT( self.head_block_id() == branches.second.back()->header.previous,
656
                    "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
657 658 659 660 661

         for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
            optional<fc::exception> except;
            try {
               apply_block( (*ritr)->block );
662
               head = *ritr;
663
               fork_db.mark_in_current_chain( *ritr, true );
664 665 666
            }
            catch (const fc::exception& e) { except = e; }
            if (except) {
667
               elog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));
668

669 670 671 672
               while (ritr != branches.first.rend() ) {
                  fork_db.set_validity( *ritr, false );
                  ++ritr;
               }
673

674
               // pop all blocks from the bad fork
675 676
               for( auto itr = (ritr + 1).base(); itr != branches.second.end(); ++itr ) {
                  fork_db.mark_in_current_chain( *itr , false );
677
                  pop_block();
678
               }
A
arhag 已提交
679
               FC_ASSERT( self.head_block_id() == branches.second.back()->header.previous,
680
                          "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail
681

682 683 684
               // re-apply good blocks
               for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
                  apply_block( (*ritr)->block );
685
                  head = *ritr;
686
                  fork_db.mark_in_current_chain( *ritr, true );
687 688 689 690
               }
               throw *except;
            } // end if exception
         } /// end for each block in branch
691
         ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id));
692 693 694
      }
   } /// push_block

695
   void abort_block() {
696
      if( pending ) {
697
         for( const auto& t : pending->_pending_block_state->trxs )
698
            unapplied_transactions[t->signed_id] = t;
699 700
         pending.reset();
      }
701 702
   }

D
Daniel Larimer 已提交
703 704 705 706 707

   bool should_enforce_runtime_limits()const {
      return false;
   }

D
Daniel Larimer 已提交
708 709 710 711 712 713 714 715
   void set_action_merkle() {
      vector<digest_type> action_digests;
      action_digests.reserve( pending->_actions.size() );
      for( const auto& a : pending->_actions )
         action_digests.emplace_back( a.digest() );

      pending->_pending_block_state->header.action_mroot = merkle( move(action_digests) );
   }
D
Daniel Larimer 已提交
716

D
Daniel Larimer 已提交
717 718
   void set_trx_merkle() {
      vector<digest_type> trx_digests;
D
Daniel Larimer 已提交
719 720 721
      const auto& trxs = pending->_pending_block_state->block->transactions;
      trx_digests.reserve( trxs.size() );
      for( const auto& a : trxs )
D
Daniel Larimer 已提交
722
         trx_digests.emplace_back( a.digest() );
D
Daniel Larimer 已提交
723

D
Daniel Larimer 已提交
724
      pending->_pending_block_state->header.transaction_mroot = merkle( move(trx_digests) );
D
Daniel Larimer 已提交
725 726 727
   }


728
   void finalize_block()
D
Daniel Larimer 已提交
729
   { try {
D
Daniel Larimer 已提交
730 731 732
      if( !pending ) self.start_block();

      /*
733
      ilog( "finalize block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} #dtrxs: ${ndtrxs} ${np}",
A
arhag 已提交
734 735
            ("n",pending->_pending_block_state->block_num)
            ("id",pending->_pending_block_state->header.id())
736
            ("t",pending->_pending_block_state->header.timestamp)
A
arhag 已提交
737 738
            ("p",pending->_pending_block_state->header.producer)
            ("signing_key", pending->_pending_block_state->block_signing_key)
739 740
            ("v",pending->_pending_block_state->header.schedule_version)
            ("lib",pending->_pending_block_state->dpos_last_irreversible_blocknum)
741
            ("ndtrxs",db.get_index<generated_transaction_multi_index,by_trx_id>().size())
742 743
            ("np",pending->_pending_block_state->header.new_producers)
            );
744
      */
D
Daniel Larimer 已提交
745

A
arhag 已提交
746 747 748 749 750 751 752 753 754
      // Update resource limits:
      resource_limits.process_account_limit_updates();
      const auto& chain_config = self.get_global_properties().configuration;
      resource_limits.set_block_parameters(
         {EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct), chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}},
         {EOS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, 1000, {99, 100}, {1000, 999}}
      );
      resource_limits.process_block_usage(pending->_pending_block_state->block_num);

D
Daniel Larimer 已提交
755 756 757 758 759 760
      set_action_merkle();
      set_trx_merkle();

      auto p = pending->_pending_block_state;
      p->id = p->header.id();

A
arhag 已提交
761
      create_block_summary(p->id);
D
Daniel Larimer 已提交
762 763 764

   } FC_CAPTURE_AND_RETHROW() }

A
arhag 已提交
765 766
   void update_producers_authority() {
      const auto& producers = pending->_pending_block_state->active_schedule.producers;
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801

      auto update_permission = [&]( auto& permission, auto threshold ) {
         auto auth = authority( threshold, {}, {});
         for( auto& p : producers ) {
            auth.accounts.push_back({{p.producer_name, config::active_name}, 1});
         }

         if( static_cast<authority>(permission.auth) != auth ) { // TODO: use a more efficient way to check that authority has not changed
            db.modify(permission, [&]( auto& po ) {
               po.auth = auth;
            });
         }
      };

      uint32_t num_producers = producers.size();
      auto calculate_threshold = [=]( uint32_t numerator, uint32_t denominator ) {
         return ( (num_producers * numerator) / denominator ) + 1;
      };

      update_permission( authorization.get_permission({config::producers_account_name,
                                                       config::active_name}),
                         calculate_threshold( 2, 3 ) /* more than two-thirds */                      );

      update_permission( authorization.get_permission({config::producers_account_name,
                                                       config::majority_producers_permission_name}),
                         calculate_threshold( 1, 2 ) /* more than one-half */                        );

      update_permission( authorization.get_permission({config::producers_account_name,
                                                       config::minority_producers_permission_name}),
                         calculate_threshold( 1, 3 ) /* more than one-third */                       );

      update_permission( authorization.get_permission({config::producers_account_name,
                                                       config::any_producer_permission_name}), 1     );

      //TODO: Add tests
A
arhag 已提交
802
   }
D
Daniel Larimer 已提交
803

A
arhag 已提交
804 805 806
   void create_block_summary(const block_id_type& id) {
      auto block_num = block_header::num_from_id(id);
      auto sid = block_num & 0xffff;
D
Daniel Larimer 已提交
807
      db.modify( db.get<block_summary_object,by_id>(sid), [&](block_summary_object& bso ) {
A
arhag 已提交
808
          bso.block_id = id;
D
Daniel Larimer 已提交
809 810 811
      });
   }

A
arhag 已提交
812 813

   void clear_expired_input_transactions() {
D
Daniel Larimer 已提交
814 815 816
      //Look for expired transactions in the deduplication list, and remove them.
      auto& transaction_idx = db.get_mutable_index<transaction_multi_index>();
      const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
A
arhag 已提交
817 818
      auto now = self.pending_block_time();
      while( (!dedupe_index.empty()) && ( now > fc::time_point(dedupe_index.begin()->expiration) ) ) {
D
Daniel Larimer 已提交
819 820 821 822
         transaction_idx.remove(*dedupe_index.begin());
      }
   }

A
arhag 已提交
823 824
   fc::microseconds limit_delay( fc::microseconds delay )const {
      auto max_delay = fc::seconds( self.get_global_properties().configuration.max_transaction_delay );
825
      return std::min(delay, max_delay);
A
arhag 已提交
826 827
   }

D
Daniel Larimer 已提交
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
   /*
   bool should_check_tapos()const { return true; }

   void validate_tapos( const transaction& trx )const {
      if( !should_check_tapos() ) return;

      const auto& tapos_block_summary = db.get<block_summary_object>((uint16_t)trx.ref_block_num);

      //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
      EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), invalid_ref_block_exception,
                 "Transaction's reference block did not match. Is this transaction from a different fork?",
                 ("tapos_summary", tapos_block_summary));
   }
   */


   /**
    *  At the start of each block we notify the system contract with a transaction that passes in
    *  the block header of the prior block (which is currently our head block)
    */
D
Daniel Larimer 已提交
848
   signed_transaction get_on_block_transaction()
D
Daniel Larimer 已提交
849 850 851 852 853
   {
      action on_block_act;
      on_block_act.account = config::system_account_name;
      on_block_act.name = N(onblock);
      on_block_act.authorization = vector<permission_level>{{config::system_account_name, config::active_name}};
A
arhag 已提交
854
      on_block_act.data = fc::raw::pack(self.head_block_header());
D
Daniel Larimer 已提交
855

D
Daniel Larimer 已提交
856
      signed_transaction trx;
D
Daniel Larimer 已提交
857
      trx.actions.emplace_back(std::move(on_block_act));
A
arhag 已提交
858 859
      trx.set_reference_block(self.head_block_id());
      trx.expiration = self.head_block_time() + fc::seconds(1);
D
Daniel Larimer 已提交
860 861 862
      return trx;
   }

863
}; /// controller_impl
D
Daniel Larimer 已提交
864

865
const resource_limits_manager&   controller::get_resource_limits_manager()const
D
Daniel Larimer 已提交
866 867 868
{
   return my->resource_limits;
}
869
resource_limits_manager&         controller::get_mutable_resource_limits_manager()
D
Daniel Larimer 已提交
870 871 872
{
   return my->resource_limits;
}
D
Daniel Larimer 已提交
873

874 875 876 877 878 879 880 881
const authorization_manager&   controller::get_authorization_manager()const
{
   return my->authorization;
}
authorization_manager&         controller::get_mutable_authorization_manager()
{
   return my->authorization;
}
D
Daniel Larimer 已提交
882 883 884 885 886 887 888 889 890 891 892

controller::controller( const controller::config& cfg )
:my( new controller_impl( cfg, *this ) )
{
}

controller::~controller() {
}


void controller::startup() {
893
   my->init();
D
Daniel Larimer 已提交
894 895 896 897

   /*
   my->head = my->fork_db.head();
   if( !my->head ) {
D
Daniel Larimer 已提交
898
      elog( "No head block in fork db, perhaps we need to replay" );
D
Daniel Larimer 已提交
899 900 901 902
   }
   */
}

D
Daniel Larimer 已提交
903
chainbase::database& controller::db()const { return my->db; }
D
Daniel Larimer 已提交
904 905 906


void controller::start_block( block_timestamp_type when ) {
907
   my->start_block(when);
D
Daniel Larimer 已提交
908 909 910
}

void controller::finalize_block() {
D
Daniel Larimer 已提交
911
   my->finalize_block();
D
Daniel Larimer 已提交
912 913
}

914 915
void controller::sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
   my->sign_block( signer_callback );
D
Daniel Larimer 已提交
916 917 918
}

void controller::commit_block() {
D
Daniel Larimer 已提交
919
   my->commit_block(true);
D
Daniel Larimer 已提交
920 921
}

922 923
void controller::abort_block() {
   my->abort_block();
D
Daniel Larimer 已提交
924 925
}

D
Daniel Larimer 已提交
926
void controller::push_block( const signed_block_ptr& b ) {
927
   my->push_block( b );
D
Daniel Larimer 已提交
928 929 930
   if( !my->replaying ) {
      log_irreversible_blocks();
   }
D
Daniel Larimer 已提交
931 932
}

933 934 935 936
void controller::push_confirmation( const header_confirmation& c ) {
   my->push_confirmation( c );
}

D
Daniel Larimer 已提交
937 938 939
void controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline ) {
   my->push_transaction(trx, deadline);
}
940 941 942

bool controller::push_next_unapplied_transaction( fc::time_point deadline ) {
   return my->push_next_unapplied_transaction( deadline );
D
Daniel Larimer 已提交
943 944
}

D
Daniel Larimer 已提交
945 946
transaction_trace_ptr controller::sync_push( const transaction_metadata_ptr& trx, time_point deadline ) {
   FC_ASSERT( deadline != fc::time_point() );
947
   transaction_trace_ptr trace;
948
   trx->on_result = [&]( const transaction_trace_ptr& t ){ trace = t; };
D
Daniel Larimer 已提交
949
   my->push_transaction( trx, deadline );
950
   return trace;
D
Daniel Larimer 已提交
951
}
D
Daniel Larimer 已提交
952

953
bool controller::push_next_scheduled_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
954
   const auto& idx = db().get_index<generated_transaction_multi_index,by_delay>();
955 956 957 958 959 960
   auto itr = idx.begin();
   if( itr != idx.end() && itr->delay_until <= pending_block_time() ) {
      my->push_scheduled_transaction( *itr, deadline );
      return true;
   }
   return false;
D
Daniel Larimer 已提交
961
}
D
Daniel Larimer 已提交
962

963
void controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline ) {
D
Daniel Larimer 已提交
964 965 966 967
   const auto& idx = db().get_index<generated_transaction_multi_index,by_trx_id>();
   auto itr = idx.find( trxid );
   FC_ASSERT( itr != idx.end(), "unknown transaction" );
   my->push_scheduled_transaction( *itr, deadline );
D
Daniel Larimer 已提交
968 969 970 971 972
}

uint32_t controller::head_block_num()const {
   return my->head->block_num;
}
A
arhag 已提交
973 974 975
time_point controller::head_block_time()const {
   return my->head->header.timestamp;
}
D
Daniel Larimer 已提交
976 977 978
block_id_type controller::head_block_id()const {
   return my->head->id;
}
D
Daniel Larimer 已提交
979 980 981
account_name  controller::head_block_producer()const {
   return my->head->header.producer;
}
A
arhag 已提交
982 983
const block_header& controller::head_block_header()const {
   return my->head->header;
D
Daniel Larimer 已提交
984
}
A
arhag 已提交
985 986
block_state_ptr controller::head_block_state()const {
   return my->head;
D
Daniel Larimer 已提交
987 988
}

A
arhag 已提交
989 990 991
block_state_ptr controller::pending_block_state()const {
   if( my->pending ) return my->pending->_pending_block_state;
   return block_state_ptr();
992 993 994 995
}
time_point controller::pending_block_time()const {
   FC_ASSERT( my->pending, "no pending block" );
   return my->pending->_pending_block_state->header.timestamp;
D
Daniel Larimer 已提交
996 997
}

A
arhag 已提交
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
uint32_t controller::last_irreversible_block_num() const {
   return my->head->bft_irreversible_blocknum;
}

block_id_type controller::last_irreversible_block_id() const {
   auto lib_num = my->head->bft_irreversible_blocknum;
   const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)lib_num);

   if( block_header::num_from_id(tapos_block_summary.block_id) == lib_num )
      return tapos_block_summary.block_id;

   return fetch_block_by_number(lib_num)->id();

}

D
Daniel Larimer 已提交
1013 1014 1015
const dynamic_global_property_object& controller::get_dynamic_global_properties()const {
  return my->db.get<dynamic_global_property_object>();
}
D
Daniel Larimer 已提交
1016 1017 1018
const global_property_object& controller::get_global_properties()const {
  return my->db.get<global_property_object>();
}
D
Daniel Larimer 已提交
1019 1020 1021 1022

/**
 *  This method reads the current dpos_irreverible block number, if it is higher
 *  than the last block number of the log, it grabs the next block from the
1023
 *  fork database, saves it to disk, then removes the block from the fork database.
D
Daniel Larimer 已提交
1024 1025 1026 1027
 *
 *  Any forks built off of a different block with the same number are also pruned.
 */
void controller::log_irreversible_blocks() {
1028
   if( !my->blog.head() )
D
Daniel Larimer 已提交
1029
      my->blog.read_head();
1030

D
Daniel Larimer 已提交
1031 1032 1033 1034
   const auto& log_head = my->blog.head();
   auto lib = my->head->dpos_last_irreversible_blocknum;

   if( lib > 1 ) {
D
Daniel Larimer 已提交
1035
      while( log_head && (log_head->block_num()+1) < lib ) {
D
Daniel Larimer 已提交
1036
         auto lhead = log_head->block_num();
1037 1038
         auto blk = my->fork_db.get_block_in_current_chain_by_num( lhead + 1 );
         FC_ASSERT( blk, "unable to find block state", ("block_num",lhead+1));
1039
         irreversible_block( blk );
D
Daniel Larimer 已提交
1040
         my->blog.append( blk->block );
D
Daniel Larimer 已提交
1041 1042
         my->fork_db.prune( blk );
         my->db.commit( lhead );
D
Daniel Larimer 已提交
1043 1044 1045
      }
   }
}
1046
signed_block_ptr controller::fetch_block_by_id( block_id_type id )const {
D
Daniel Larimer 已提交
1047
   idump((id));
1048 1049
   auto state = my->fork_db.get_block(id);
   if( state ) return state->block;
D
Daniel Larimer 已提交
1050
   edump((block_header::num_from_id(id)));
1051
   auto bptr = fetch_block_by_number( block_header::num_from_id(id) );
D
Daniel Larimer 已提交
1052 1053
   if( bptr && bptr->id() == id ) return bptr;
   elog( "not found" );
1054 1055 1056
   return signed_block_ptr();
}

D
Daniel Larimer 已提交
1057
signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const  { try {
1058
   auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
D
Daniel Larimer 已提交
1059 1060 1061
   if( blk_state ) {
      return blk_state->block;
   }
1062

D
Daniel Larimer 已提交
1063
   ilog( "blog read by number ${n}", ("n", block_num) );
D
Daniel Larimer 已提交
1064
   return my->blog.read_block_by_num(block_num);
D
Daniel Larimer 已提交
1065
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
D
Daniel Larimer 已提交
1066 1067

void controller::pop_block() {
1068
   my->pop_block();
D
Daniel Larimer 已提交
1069 1070
}

1071
bool controller::set_proposed_producers( vector<producer_key> producers ) {
1072 1073
   const auto& gpo = get_global_properties();
   auto cur_block_num = head_block_num() + 1;
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088

   if( gpo.proposed_schedule_block_num.valid() ) {
      if( *gpo.proposed_schedule_block_num != cur_block_num )
         return false; // there is already a proposed schedule set in a previous block, wait for it to become pending

      if( std::equal( producers.begin(), producers.end(),
                      gpo.proposed_schedule.producers.begin(), gpo.proposed_schedule.producers.end() ) )
         return false; // the proposed producer schedule does not change
   }

   producer_schedule_type sch;

   decltype(sch.producers.cend()) end;
   decltype(end)                  begin;

1089
   if( my->pending->_pending_block_state->pending_schedule.producers.size() == 0 ) {
1090 1091 1092 1093
      const auto& active_sch = my->pending->_pending_block_state->active_schedule;
      begin = active_sch.producers.begin();
      end   = active_sch.producers.end();
      sch.version = active_sch.version + 1;
1094
   } else {
1095 1096 1097 1098
      const auto& pending_sch = my->pending->_pending_block_state->pending_schedule;
      begin = pending_sch.producers.begin();
      end   = pending_sch.producers.end();
      sch.version = pending_sch.version + 1;
1099
   }
1100 1101 1102 1103 1104 1105

   if( std::equal( producers.begin(), producers.end(), begin, end ) )
      return false; // the producer schedule would not change

   sch.producers = std::move(producers);

1106 1107
   my->db.modify( gpo, [&]( auto& gp ) {
      gp.proposed_schedule_block_num = cur_block_num;
1108
      gp.proposed_schedule = std::move(sch);
1109
   });
1110
   return true;
D
Daniel Larimer 已提交
1111
}
1112 1113

const producer_schedule_type&    controller::active_producers()const {
1114 1115
   if ( !(my->pending) )
      return  my->head->active_schedule;
D
Daniel Larimer 已提交
1116 1117 1118
   return my->pending->_pending_block_state->active_schedule;
}

1119
const producer_schedule_type&    controller::pending_producers()const {
1120 1121
   if ( !(my->pending) )
      return  my->head->pending_schedule;
D
Daniel Larimer 已提交
1122 1123 1124
   return my->pending->_pending_block_state->pending_schedule;
}

1125 1126 1127 1128 1129 1130 1131 1132 1133
optional<producer_schedule_type> controller::proposed_producers()const {
   const auto& gpo = get_global_properties();
   if( !gpo.proposed_schedule_block_num.valid() )
      return optional<producer_schedule_type>();

   return gpo.proposed_schedule;
}


D
Daniel Larimer 已提交
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
const apply_handler* controller::find_apply_handler( account_name receiver, account_name scope, action_name act ) const
{
   auto native_handler_scope = my->apply_handlers.find( receiver );
   if( native_handler_scope != my->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;
}
wasm_interface& controller::get_wasm_interface() {
   return my->wasmif;
}
D
Daniel Larimer 已提交
1147

1148
const account_object& controller::get_account( account_name name )const
D
Daniel Larimer 已提交
1149 1150 1151
{ try {
   return my->db.get<account_object, by_name>(name);
} FC_CAPTURE_AND_RETHROW( (name) ) }
D
Daniel Larimer 已提交
1152

1153 1154 1155 1156
const map<digest_type, transaction_metadata_ptr>&  controller::unapplied_transactions()const {
   return my->unapplied_transactions;
}

A
arhag 已提交
1157 1158 1159
fc::microseconds controller::limit_delay( fc::microseconds delay )const {
   return my->limit_delay( delay );
}
1160 1161 1162 1163 1164 1165

void controller::validate_referenced_accounts( const transaction& trx )const {
   for( const auto& a : trx.context_free_actions ) {
      get_account( a.account );
      FC_ASSERT( a.authorization.size() == 0 );
   }
D
Daniel Larimer 已提交
1166
   bool one_auth = false;
1167 1168
   for( const auto& a : trx.actions ) {
      get_account( a.account );
1169
      for( const auto& auth : a.authorization ) {
D
Daniel Larimer 已提交
1170
         one_auth = true;
1171 1172 1173
         get_account( auth.actor );
      }
   }
D
Daniel Larimer 已提交
1174
   EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" );
1175 1176 1177 1178 1179
}

void controller::validate_expiration( const transaction& trx )const { try {
   const auto& chain_configuration = get_global_properties().configuration;

1180 1181 1182 1183 1184
   EOS_ASSERT( time_point(trx.expiration) >= pending_block_time(),
               expired_tx_exception,
               "transaction has expired, "
               "expiration is ${trx.expiration} and pending block time is ${pending_block_time}",
               ("trx.expiration",trx.expiration)("pending_block_time",pending_block_time()));
1185 1186 1187 1188 1189 1190 1191 1192
   EOS_ASSERT( time_point(trx.expiration) <= pending_block_time() + fc::seconds(chain_configuration.max_transaction_lifetime),
               tx_exp_too_far_exception,
               "Transaction expiration is too far in the future relative to the reference time of ${reference_time}, "
               "expiration is ${trx.expiration} and the maximum transaction lifetime is ${max_til_exp} seconds",
               ("trx.expiration",trx.expiration)("reference_time",pending_block_time())
               ("max_til_exp",chain_configuration.max_transaction_lifetime) );
} FC_CAPTURE_AND_RETHROW((trx)) }

D
Daniel Larimer 已提交
1193 1194 1195 1196
uint64_t controller::validate_net_usage( const transaction_metadata_ptr& trx )const {
   const auto& cfg = get_global_properties().configuration;

   auto actual_net_usage = cfg.base_per_transaction_net_usage + trx->packed_trx.get_billable_size();
A
arhag 已提交
1197 1198 1199 1200 1201
   if( trx->trx.delay_sec.value > 0 ) {
       // If delayed, also charge ahead of time for the additional net usage needed to retire the delayed transaction
       // whether that be by successfully executing, soft failure, hard failure, or expiration.
      actual_net_usage += cfg.base_per_transaction_net_usage + ::eosio::chain::config::transaction_id_net_usage;
   }
D
Daniel Larimer 已提交
1202 1203 1204

   actual_net_usage = ((actual_net_usage + 7)/8) * 8; // Round up to nearest multiple of 8

A
arhag 已提交
1205 1206 1207 1208 1209 1210 1211 1212 1213
   uint32_t net_usage_limit = cfg.max_transaction_net_usage;
   // TODO: reduce net_usage_limit to the minimum of the amount that the paying accounts can afford to pay
   uint32_t trx_specified_net_usage_limit = trx->trx.max_net_usage_words.value * 8UL; // overflow checked in transaction_header::validate()
   if( trx_specified_net_usage_limit > 0 )
      net_usage_limit = std::min( net_usage_limit, trx_specified_net_usage_limit );

   EOS_ASSERT( actual_net_usage <= net_usage_limit, tx_resource_exhausted,
               "net usage of transaction is too high: ${actual_net_usage} > ${net_usage_limit}",
               ("actual_net_usage", actual_net_usage)("net_usage_limit",net_usage_limit) );
D
Daniel Larimer 已提交
1214 1215 1216 1217

   return actual_net_usage;
}

1218 1219 1220 1221 1222 1223 1224
void controller::validate_tapos( const transaction& trx )const { try {
   const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)trx.ref_block_num);

   //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
   EOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), invalid_ref_block_exception,
              "Transaction's reference block did not match. Is this transaction from a different fork?",
              ("tapos_summary", tapos_block_summary));
1225 1226
} FC_CAPTURE_AND_RETHROW() }

1227

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