controller.cpp 45.6 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>();
D
Daniel Larimer 已提交
157 158 159 160 161 162 163 164

      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>();

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

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

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

188 189 190 191 192 193 194 195
      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 已提交
196

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

      initialize_database();
A
arhag 已提交
203

D
Daniel Larimer 已提交
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
      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 已提交
224 225
   }

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

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

240 241 242 243
      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 已提交
244 245

      resource_limits.initialize_account(name);
246 247 248 249 250 251 252 253
      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 已提交
254 255 256 257 258 259 260
   }

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

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

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

      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 已提交
276

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

281 282
      create_native_account( config::nobody_account_name, empty_authority, empty_authority );
      create_native_account( config::producers_account_name, empty_authority, active_producers_authority );
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
      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 已提交
299 300
   }

301

302

A
arhag 已提交
303
   void commit_block( bool add_to_fork_db ) {
D
Daniel Larimer 已提交
304 305
      if( add_to_fork_db ) {
         pending->_pending_block_state->validated = true;
306 307 308
         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" );
309
      }
310

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

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

321
   transaction_trace_ptr apply_onerror( const generated_transaction_object& gto, fc::time_point deadline, uint32_t cpu_usage ) {
D
Daniel Larimer 已提交
322 323 324
      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 已提交
325

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

      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();

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

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

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

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

      db.remove( gto );
   }

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

354
      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 已提交
355 356 357 358
      if( gto.expiration <= self.pending_block_time() ) {
         expire_scheduled_transaction( gto );
         return;
      }
359 360 361

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

365 366
      auto sender = gto.sender;

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

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

376
         trx_context.trace->scheduled = true;
377 378 379 380 381 382 383 384 385 386 387 388 389 390
         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 已提交
391 392 393 394
         trx_context.trace->receipt = push_receipt( gto.trx_id,
                                                    transaction_receipt::executed,
                                                    trx_context.trace->kcpu_usage(),
                                                    0 );
395 396

         db.remove( gto );
397

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

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

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

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

      db.remove( gto );

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

437 438 439 440

   /**
    *  Adds the transaction receipt to the pending block and returns it.
    */
441 442
   template<typename T>
   const transaction_receipt& push_receipt( const T& trx, transaction_receipt_header::status_enum status,
443 444 445 446 447 448 449 450 451
                      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;
   }

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

457 458 459
      // 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 已提交
460 461
   }

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

469 470 471 472 473
   /**
    *  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.
    */
474 475
   void push_transaction( const transaction_metadata_ptr& trx,
                          fc::time_point deadline = fc::time_point::maximum(),
D
Daniel Larimer 已提交
476
                          bool implicit = false ) {
D
Daniel Larimer 已提交
477 478 479
      //if( !implicit )
      //   idump((fc::json::to_pretty_string(trx->trx)));

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

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

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

A
arhag 已提交
492
         auto required_delay = limit_delay( authorization.check_authorization( trx->trx.actions, trx->recover_keys() ) );
493 494 495 496
         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()) );
497

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

D
Daniel Larimer 已提交
504 505 506 507
         fc::move_append( pending->_actions, move(trx_context.executed) );

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

514 515 516 517 518
         transaction_trace_notify(trx, trace);

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

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

531
   } /// push_transaction
D
Daniel Larimer 已提交
532

533

534
   void start_block( block_timestamp_type when ) {
535
      FC_ASSERT( !pending );
D
Daniel Larimer 已提交
536

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

540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
      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 已提交
562

563 564 565 566 567 568
      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 已提交
569 570 571

      clear_expired_input_transactions();
      update_producers_authority();
572
   } // start_block
D
Daniel Larimer 已提交
573 574


D
Daniel Larimer 已提交
575

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

582
   void apply_block( const signed_block_ptr& b ) { try {
583 584 585 586 587 588 589 590 591
      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 已提交
592 593 594
            else if( receipt.trx.contains<transaction_id_type>() ) {
               self.push_scheduled_transaction( receipt.trx.get<transaction_id_type>() );
            }
595
         }
D
Daniel Larimer 已提交
596

597 598
         finalize_block();
         sign_block( [&]( const auto& ){ return b->producer_signature; } );
D
Daniel Larimer 已提交
599

600 601 602
         // 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 已提交
603

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


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

622 623 624 625 626 627 628
   void push_confirmation( const header_confirmation& c ) {
      fork_db.add( c );
      self.accepted_confirmation( c );
      maybe_switch_forks();
   }

   void maybe_switch_forks() {
629 630 631 632
      auto new_head = fork_db.head();

      if( new_head->header.previous == head->id ) {
         try {
633
            abort_block();
634
            apply_block( new_head->block );
635
            fork_db.mark_in_current_chain( new_head, true );
636 637 638
            fork_db.set_validity( new_head, true );
            head = new_head;
         } catch ( const fc::exception& e ) {
639
            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.
640 641
            throw;
         }
642
      } else if( new_head->id != head->id ) {
643
         ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
A
arhag 已提交
644
              ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) );
645 646
         auto branches = fork_db.fetch_branch_from( new_head->id, head->id );

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

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

665 666 667 668
               while (ritr != branches.first.rend() ) {
                  fork_db.set_validity( *ritr, false );
                  ++ritr;
               }
669

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

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

691
   void abort_block() {
692
      if( pending ) {
693
         for( const auto& t : pending->_pending_block_state->trxs )
694
            unapplied_transactions[t->signed_id] = t;
695 696
         pending.reset();
      }
697 698
   }

D
Daniel Larimer 已提交
699 700 701 702 703

   bool should_enforce_runtime_limits()const {
      return false;
   }

D
Daniel Larimer 已提交
704 705 706 707 708 709 710 711
   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 已提交
712

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

D
Daniel Larimer 已提交
720
      pending->_pending_block_state->header.transaction_mroot = merkle( move(trx_digests) );
D
Daniel Larimer 已提交
721 722 723
   }


724
   void finalize_block()
D
Daniel Larimer 已提交
725
   { try {
D
Daniel Larimer 已提交
726 727 728
      if( !pending ) self.start_block();

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

A
arhag 已提交
742 743 744 745 746 747 748 749 750
      // 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 已提交
751 752 753 754 755 756
      set_action_merkle();
      set_trx_merkle();

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

A
arhag 已提交
757
      create_block_summary(p->id);
D
Daniel Larimer 已提交
758 759 760

   } FC_CAPTURE_AND_RETHROW() }

A
arhag 已提交
761 762 763 764
   void update_producers_authority() {
      const auto& producers = pending->_pending_block_state->active_schedule.producers;
      //TODO: Complete implementation
   }
D
Daniel Larimer 已提交
765

A
arhag 已提交
766 767 768
   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 已提交
769
      db.modify( db.get<block_summary_object,by_id>(sid), [&](block_summary_object& bso ) {
A
arhag 已提交
770
          bso.block_id = id;
D
Daniel Larimer 已提交
771 772 773
      });
   }

A
arhag 已提交
774 775

   void clear_expired_input_transactions() {
D
Daniel Larimer 已提交
776 777 778
      //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 已提交
779 780
      auto now = self.pending_block_time();
      while( (!dedupe_index.empty()) && ( now > fc::time_point(dedupe_index.begin()->expiration) ) ) {
D
Daniel Larimer 已提交
781 782 783 784
         transaction_idx.remove(*dedupe_index.begin());
      }
   }

A
arhag 已提交
785 786
   fc::microseconds limit_delay( fc::microseconds delay )const {
      auto max_delay = fc::seconds( self.get_global_properties().configuration.max_transaction_delay );
787
      return std::min(delay, max_delay);
A
arhag 已提交
788 789
   }

D
Daniel Larimer 已提交
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
   /*
   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 已提交
810
   signed_transaction get_on_block_transaction()
D
Daniel Larimer 已提交
811 812 813 814 815
   {
      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 已提交
816
      on_block_act.data = fc::raw::pack(self.head_block_header());
D
Daniel Larimer 已提交
817

D
Daniel Larimer 已提交
818
      signed_transaction trx;
D
Daniel Larimer 已提交
819
      trx.actions.emplace_back(std::move(on_block_act));
A
arhag 已提交
820 821
      trx.set_reference_block(self.head_block_id());
      trx.expiration = self.head_block_time() + fc::seconds(1);
D
Daniel Larimer 已提交
822 823 824
      return trx;
   }

825
}; /// controller_impl
D
Daniel Larimer 已提交
826

827
const resource_limits_manager&   controller::get_resource_limits_manager()const
D
Daniel Larimer 已提交
828 829 830
{
   return my->resource_limits;
}
831
resource_limits_manager&         controller::get_mutable_resource_limits_manager()
D
Daniel Larimer 已提交
832 833 834
{
   return my->resource_limits;
}
D
Daniel Larimer 已提交
835

836 837 838 839 840 841 842 843
const authorization_manager&   controller::get_authorization_manager()const
{
   return my->authorization;
}
authorization_manager&         controller::get_mutable_authorization_manager()
{
   return my->authorization;
}
D
Daniel Larimer 已提交
844 845 846 847 848 849 850 851 852 853 854

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

controller::~controller() {
}


void controller::startup() {
855
   my->init();
D
Daniel Larimer 已提交
856 857 858 859

   /*
   my->head = my->fork_db.head();
   if( !my->head ) {
D
Daniel Larimer 已提交
860
      elog( "No head block in fork db, perhaps we need to replay" );
D
Daniel Larimer 已提交
861 862 863 864
   }
   */
}

D
Daniel Larimer 已提交
865
chainbase::database& controller::db()const { return my->db; }
D
Daniel Larimer 已提交
866 867 868


void controller::start_block( block_timestamp_type when ) {
869
   my->start_block(when);
D
Daniel Larimer 已提交
870 871 872
}

void controller::finalize_block() {
D
Daniel Larimer 已提交
873
   my->finalize_block();
D
Daniel Larimer 已提交
874 875
}

876 877
void controller::sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
   my->sign_block( signer_callback );
D
Daniel Larimer 已提交
878 879 880
}

void controller::commit_block() {
D
Daniel Larimer 已提交
881
   my->commit_block(true);
D
Daniel Larimer 已提交
882 883
}

884 885
void controller::abort_block() {
   my->abort_block();
D
Daniel Larimer 已提交
886 887
}

D
Daniel Larimer 已提交
888
void controller::push_block( const signed_block_ptr& b ) {
889
   my->push_block( b );
D
Daniel Larimer 已提交
890 891 892
   if( !my->replaying ) {
      log_irreversible_blocks();
   }
D
Daniel Larimer 已提交
893 894
}

895 896 897 898
void controller::push_confirmation( const header_confirmation& c ) {
   my->push_confirmation( c );
}

D
Daniel Larimer 已提交
899 900 901
void controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline ) {
   my->push_transaction(trx, deadline);
}
902 903 904

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

D
Daniel Larimer 已提交
907 908
transaction_trace_ptr controller::sync_push( const transaction_metadata_ptr& trx, time_point deadline ) {
   FC_ASSERT( deadline != fc::time_point() );
909
   transaction_trace_ptr trace;
910
   trx->on_result = [&]( const transaction_trace_ptr& t ){ trace = t; };
D
Daniel Larimer 已提交
911
   my->push_transaction( trx, deadline );
912
   return trace;
D
Daniel Larimer 已提交
913
}
D
Daniel Larimer 已提交
914

915
bool controller::push_next_scheduled_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
916
   const auto& idx = db().get_index<generated_transaction_multi_index,by_delay>();
917 918 919 920 921 922
   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 已提交
923
}
D
Daniel Larimer 已提交
924

925
void controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline ) {
D
Daniel Larimer 已提交
926 927 928 929
   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 已提交
930 931 932 933 934
}

uint32_t controller::head_block_num()const {
   return my->head->block_num;
}
A
arhag 已提交
935 936 937
time_point controller::head_block_time()const {
   return my->head->header.timestamp;
}
D
Daniel Larimer 已提交
938 939 940
block_id_type controller::head_block_id()const {
   return my->head->id;
}
D
Daniel Larimer 已提交
941 942 943
account_name  controller::head_block_producer()const {
   return my->head->header.producer;
}
A
arhag 已提交
944 945
const block_header& controller::head_block_header()const {
   return my->head->header;
D
Daniel Larimer 已提交
946
}
A
arhag 已提交
947 948
block_state_ptr controller::head_block_state()const {
   return my->head;
D
Daniel Larimer 已提交
949 950
}

A
arhag 已提交
951 952 953
block_state_ptr controller::pending_block_state()const {
   if( my->pending ) return my->pending->_pending_block_state;
   return block_state_ptr();
954 955 956 957
}
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 已提交
958 959
}

A
arhag 已提交
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
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 已提交
975 976 977
const dynamic_global_property_object& controller::get_dynamic_global_properties()const {
  return my->db.get<dynamic_global_property_object>();
}
D
Daniel Larimer 已提交
978 979 980
const global_property_object& controller::get_global_properties()const {
  return my->db.get<global_property_object>();
}
D
Daniel Larimer 已提交
981 982 983 984

/**
 *  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
985
 *  fork database, saves it to disk, then removes the block from the fork database.
D
Daniel Larimer 已提交
986 987 988 989
 *
 *  Any forks built off of a different block with the same number are also pruned.
 */
void controller::log_irreversible_blocks() {
990
   if( !my->blog.head() )
D
Daniel Larimer 已提交
991
      my->blog.read_head();
992

D
Daniel Larimer 已提交
993 994 995 996
   const auto& log_head = my->blog.head();
   auto lib = my->head->dpos_last_irreversible_blocknum;

   if( lib > 1 ) {
D
Daniel Larimer 已提交
997
      while( log_head && (log_head->block_num()+1) < lib ) {
D
Daniel Larimer 已提交
998
         auto lhead = log_head->block_num();
999 1000
         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));
1001
         irreversible_block( blk );
D
Daniel Larimer 已提交
1002
         my->blog.append( blk->block );
D
Daniel Larimer 已提交
1003 1004
         my->fork_db.prune( blk );
         my->db.commit( lhead );
D
Daniel Larimer 已提交
1005 1006 1007
      }
   }
}
1008
signed_block_ptr controller::fetch_block_by_id( block_id_type id )const {
D
Daniel Larimer 已提交
1009
   idump((id));
1010 1011
   auto state = my->fork_db.get_block(id);
   if( state ) return state->block;
D
Daniel Larimer 已提交
1012
   edump((block_header::num_from_id(id)));
1013
   auto bptr = fetch_block_by_number( block_header::num_from_id(id) );
D
Daniel Larimer 已提交
1014 1015
   if( bptr && bptr->id() == id ) return bptr;
   elog( "not found" );
1016 1017 1018
   return signed_block_ptr();
}

D
Daniel Larimer 已提交
1019
signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const  { try {
1020
   auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
D
Daniel Larimer 已提交
1021 1022 1023
   if( blk_state ) {
      return blk_state->block;
   }
1024

D
Daniel Larimer 已提交
1025
   ilog( "blog read by number ${n}", ("n", block_num) );
D
Daniel Larimer 已提交
1026
   return my->blog.read_block_by_num(block_num);
D
Daniel Larimer 已提交
1027
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
D
Daniel Larimer 已提交
1028 1029

void controller::pop_block() {
1030
   my->pop_block();
D
Daniel Larimer 已提交
1031 1032
}

1033
bool controller::set_proposed_producers( vector<producer_key> producers ) {
1034 1035
   const auto& gpo = get_global_properties();
   auto cur_block_num = head_block_num() + 1;
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050

   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;

1051
   if( my->pending->_pending_block_state->pending_schedule.producers.size() == 0 ) {
1052 1053 1054 1055
      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;
1056
   } else {
1057 1058 1059 1060
      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;
1061
   }
1062 1063 1064 1065 1066 1067

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

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

1068 1069
   my->db.modify( gpo, [&]( auto& gp ) {
      gp.proposed_schedule_block_num = cur_block_num;
1070
      gp.proposed_schedule = std::move(sch);
1071
   });
1072
   return true;
D
Daniel Larimer 已提交
1073
}
1074 1075

const producer_schedule_type&    controller::active_producers()const {
1076 1077
   if ( !(my->pending) )
      return  my->head->active_schedule;
D
Daniel Larimer 已提交
1078 1079 1080
   return my->pending->_pending_block_state->active_schedule;
}

1081
const producer_schedule_type&    controller::pending_producers()const {
1082 1083
   if ( !(my->pending) )
      return  my->head->pending_schedule;
D
Daniel Larimer 已提交
1084 1085 1086
   return my->pending->_pending_block_state->pending_schedule;
}

1087 1088 1089 1090 1091 1092 1093 1094 1095
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 已提交
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
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 已提交
1109

1110
const account_object& controller::get_account( account_name name )const
D
Daniel Larimer 已提交
1111 1112 1113
{ try {
   return my->db.get<account_object, by_name>(name);
} FC_CAPTURE_AND_RETHROW( (name) ) }
D
Daniel Larimer 已提交
1114

1115 1116 1117 1118
const map<digest_type, transaction_metadata_ptr>&  controller::unapplied_transactions()const {
   return my->unapplied_transactions;
}

A
arhag 已提交
1119 1120 1121
fc::microseconds controller::limit_delay( fc::microseconds delay )const {
   return my->limit_delay( delay );
}
1122 1123 1124 1125 1126 1127

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 已提交
1128
   bool one_auth = false;
1129 1130
   for( const auto& a : trx.actions ) {
      get_account( a.account );
1131
      for( const auto& auth : a.authorization ) {
D
Daniel Larimer 已提交
1132
         one_auth = true;
1133 1134 1135
         get_account( auth.actor );
      }
   }
D
Daniel Larimer 已提交
1136
   EOS_ASSERT( one_auth, tx_no_auths, "transaction must have at least one authorization" );
1137 1138 1139 1140 1141
}

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

1142 1143 1144 1145 1146
   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()));
1147 1148 1149 1150 1151 1152 1153 1154
   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 已提交
1155 1156 1157 1158 1159 1160 1161
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();

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

A
arhag 已提交
1162 1163 1164 1165 1166 1167 1168 1169 1170
   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 已提交
1171 1172 1173 1174

   return actual_net_usage;
}

1175 1176 1177 1178 1179 1180 1181
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));
1182 1183
} FC_CAPTURE_AND_RETHROW() }

1184

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