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 68 69 70 71 72 73 74 75 76 77
   block_id_type head_block_id()const {
      return head->id;
   }
   time_point head_block_time()const {
      return head->header.timestamp;
   }
   const block_header& head_block_header()const {
      return head->header;
   }

   void pop_block() {
78 79
      auto prev = fork_db.get_block( head->header.previous );
      FC_ASSERT( prev, "attempt to pop beyond last irreversible block" );
D
Daniel Larimer 已提交
80
      for( const auto& t : head->trxs )
81
         unapplied_transactions[t->signed_id] = t;
82
      head = prev;
D
Daniel Larimer 已提交
83
      db.undo();
D
Daniel Larimer 已提交
84 85 86
   }


D
Daniel Larimer 已提交
87 88 89 90
   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 已提交
91
   controller_impl( const controller::config& cfg, controller& s  )
D
Daniel Larimer 已提交
92 93
   :self(s),
    db( cfg.shared_memory_dir,
D
Daniel Larimer 已提交
94 95 96
        cfg.read_only ? database::read_only : database::read_write,
        cfg.shared_memory_size ),
    blog( cfg.block_log_dir ),
D
Daniel Larimer 已提交
97
    fork_db( cfg.shared_memory_dir ),
D
Daniel Larimer 已提交
98
    wasmif( cfg.wasm_runtime ),
D
Daniel Larimer 已提交
99
    resource_limits( db ),
D
Daniel Larimer 已提交
100 101
    authorization( s, db ),
    conf( cfg )
D
Daniel Larimer 已提交
102
   {
D
Daniel Larimer 已提交
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119

#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 已提交
120 121 122 123
   }

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

      /**
127 128 129 130 131 132 133 134 135 136 137 138 139 140
      *  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 已提交
141 142 143 144 145
       * 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.
       */
146
      //clear_all_undo();
D
Daniel Larimer 已提交
147 148 149 150
   }

   ~controller_impl() {
      pending.reset();
D
Daniel Larimer 已提交
151 152 153

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

D
Daniel Larimer 已提交
154 155 156
      db.flush();
   }

157
   void add_indices() {
D
Daniel Larimer 已提交
158
      db.add_index<account_index>();
159
      db.add_index<account_sequence_index>();
D
Daniel Larimer 已提交
160

D
Daniel Larimer 已提交
161 162 163 164 165 166
      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 已提交
167 168 169 170 171 172 173 174

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

175 176
      authorization.add_indices();
      resource_limits.add_indices();
D
Daniel Larimer 已提交
177 178 179 180 181 182 183
   }

   void clear_all_undo() {
      // Rewind the database to the last irreversible block
      db.with_write_lock([&] {
         db.undo_all();
         /*
184
         FC_ASSERT(db.revision() == self.head_block_num(),
D
Daniel Larimer 已提交
185 186 187 188 189 190 191
                   "Chainbase revision does not match head block num",
                   ("rev", db.revision())("head_block", self.head_block_num()));
                   */
      });
   }

   /**
192
    *  Sets fork database head to the genesis state.
D
Daniel Larimer 已提交
193 194
    */
   void initialize_fork_db() {
195 196
      wlog( " Initializing new blockchain with genesis state                  " );
      producer_schedule_type initial_schedule{ 0, {{N(eosio), conf.genesis.initial_key}} };
D
Daniel Larimer 已提交
197

198 199 200 201 202 203 204 205
      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 已提交
206

207
      head = std::make_shared<block_state>( genheader );
D
Daniel Larimer 已提交
208
      head->block = std::make_shared<signed_block>(genheader.header);
209
      fork_db.set( head );
D
Daniel Larimer 已提交
210 211 212
      db.set_revision( head->block_num );

      initialize_database();
A
arhag 已提交
213

D
Daniel Larimer 已提交
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
      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 已提交
234 235
   }

236
   void create_native_account( account_name name, const authority& owner, const authority& active, bool is_privileged = false ) {
237
      db.create<account_object>([&](auto& a) {
D
Daniel Larimer 已提交
238 239
         a.name = name;
         a.creation_date = conf.genesis.initial_timestamp;
240
         a.privileged = is_privileged;
D
Daniel Larimer 已提交
241 242

         if( name == config::system_account_name ) {
D
Daniel Larimer 已提交
243
            a.set_abi(eosio_contract_abi(abi_def()));
D
Daniel Larimer 已提交
244 245
         }
      });
246 247 248 249
      db.create<account_sequence_object>([&](auto & a) {
        a.name = name;
      });

250 251 252 253
      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 已提交
254 255

      resource_limits.initialize_account(name);
256 257 258 259 260 261 262 263
      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 已提交
264 265 266 267 268 269 270
   }

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

271 272 273 274 275
      const auto& tapos_block_summary = db.get<block_summary_object>(1);
      db.modify( tapos_block_summary, [&]( auto& bs ) {
        bs.block_id = head->id;
      });

276 277 278 279
      db.create<global_property_object>([&](auto& gpo ){
        gpo.configuration = conf.genesis.initial_configuration;
      });
      db.create<dynamic_global_property_object>([](auto&){});
280 281 282 283 284 285

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

287 288
      auto empty_authority = authority(1, {}, {});
      auto active_producers_authority = authority(1, {}, {});
D
Daniel Larimer 已提交
289 290
      active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1});

291 292
      create_native_account( config::nobody_account_name, empty_authority, empty_authority );
      create_native_account( config::producers_account_name, empty_authority, active_producers_authority );
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
      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 已提交
309 310
   }

311 312 313 314 315 316 317
   void set_pending_tapos() {
      const auto& tapos_block_summary = db.get<block_summary_object>((uint16_t)pending->_pending_block_state->block_num);
      db.modify( tapos_block_summary, [&]( auto& bs ) {
        bs.block_id = pending->_pending_block_state->id;
      });
   }

D
Daniel Larimer 已提交
318
   void commit_block( bool add_to_fork_db ) {
319 320 321 322
      set_pending_tapos();
      resource_limits.process_account_limit_updates();
      resource_limits.process_block_usage( pending->_pending_block_state->block_num );

D
Daniel Larimer 已提交
323 324
      if( add_to_fork_db ) {
         pending->_pending_block_state->validated = true;
325 326 327
         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" );
328
      }
329

330
      //ilog((fc::json::to_pretty_string(*pending->_pending_block_state->block)));
D
Daniel Larimer 已提交
331
      self.accepted_block( pending->_pending_block_state );
D
Daniel Larimer 已提交
332 333
      pending->push();
      pending.reset();
D
Daniel Larimer 已提交
334 335 336 337

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

340
   transaction_trace_ptr apply_onerror( const generated_transaction_object& gto, fc::time_point deadline, uint32_t cpu_usage ) {
D
Daniel Larimer 已提交
341 342 343
      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 已提交
344

D
Daniel Larimer 已提交
345 346 347 348 349 350 351 352 353 354

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

355
      self.applied_transaction(trx_context.trace);
D
Daniel Larimer 已提交
356 357 358
      trx_context.squash();

      return move(trx_context.trace);
D
Daniel Larimer 已提交
359 360
   }

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

364
      resource_limits.add_pending_account_ram_usage(gto.payer,
D
Daniel Larimer 已提交
365 366 367 368 369
               -(config::billable_size_v<generated_transaction_object> + gto.packed_trx.size()));

      db.remove( gto );
   }

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

373
      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 已提交
374 375 376 377
      if( gto.expiration <= self.pending_block_time() ) {
         expire_scheduled_transaction( gto );
         return;
      }
378 379 380

      optional<fc::exception> soft_except;
      optional<fc::exception> hard_except;
D
Daniel Larimer 已提交
381 382
      std::exception_ptr soft_except_ptr;
      std::exception_ptr hard_except_ptr;
383

384 385
      auto sender = gto.sender;

D
Daniel Larimer 已提交
386
      transaction_trace_ptr trace;
387
      uint32_t apply_cpu_usage = 0;
D
Daniel Larimer 已提交
388 389 390
      try {
         signed_transaction dtrx;
         fc::raw::unpack(ds,static_cast<transaction&>(dtrx) );
391 392

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

395
         trx_context.trace->scheduled = true;
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
         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) );

         trx_context.trace->receipt = push_receipt( gto.trx_id, transaction_receipt::executed, trx_context.trace->kcpu_usage(), 0 );
411 412

         db.remove( gto );
413

D
Daniel Larimer 已提交
414
         self.applied_transaction( trx_context.trace );
415
         trx_context.squash();
416 417

         return;
D
Daniel Larimer 已提交
418
      } catch( const fc::exception& e ) {
419
         soft_except = e;
D
Daniel Larimer 已提交
420
         soft_except_ptr = std::current_exception();
D
Daniel Larimer 已提交
421
      }
422
      if( soft_except && sender != account_name() ) { /// TODO: soft errors should not go to error handlers (deadline error)
423 424 425 426
         edump((soft_except->to_detail_string()));
         try {
            auto trace = apply_onerror( gto, deadline, apply_cpu_usage  );
            trace->soft_except = soft_except;
D
Daniel Larimer 已提交
427
            self.applied_transaction( trace );
428 429
         } catch ( const fc::exception& e ) {
            hard_except = e;
D
Daniel Larimer 已提交
430
            trace->hard_except_ptr = std::current_exception();
431
         }
D
Daniel Larimer 已提交
432
      }
433

434
      /*
435
      if( hard_except )
436
         edump((hard_except->to_detail_string()));
437
      if( soft_except )
438 439 440
         edump((soft_except->to_detail_string()));
       */

441
      FC_ASSERT( bool(trace), "failed to deserialize transaction" );
442
      trace->receipt  = push_receipt( gto.trx_id, transaction_receipt::hard_fail, (apply_cpu_usage+1023)/1024, 0 );
D
Daniel Larimer 已提交
443 444
      trace->soft_except = soft_except;
      trace->hard_except = hard_except;
D
Daniel Larimer 已提交
445 446
      trace->soft_except_ptr = soft_except_ptr;
      trace->hard_except_ptr = hard_except_ptr;
447 448 449

      db.remove( gto );

D
Daniel Larimer 已提交
450
      self.applied_transaction( trace );
D
Daniel Larimer 已提交
451
   } /// push_scheduled_transaction
D
Daniel Larimer 已提交
452

453 454 455 456

   /**
    *  Adds the transaction receipt to the pending block and returns it.
    */
457 458
   template<typename T>
   const transaction_receipt& push_receipt( const T& trx, transaction_receipt_header::status_enum status,
459 460 461 462 463 464 465 466 467
                      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;
   }

468
   bool push_next_unapplied_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
469
      auto itr = unapplied_transactions.begin();
470
      if( itr == unapplied_transactions.end() )
471
         return false;
D
Daniel Larimer 已提交
472

473 474 475
      // 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 已提交
476 477
   }

478 479
   void transaction_trace_notify( const transaction_metadata_ptr& trx, const transaction_trace_ptr& trace ) {
      if( trx->on_result ) {
480 481
         (trx->on_result)(trace);
         trx->on_result = decltype(trx->on_result)(); //assign empty std::function
482 483
      }
   }
484

485 486 487 488 489
   /**
    *  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.
    */
490 491
   void push_transaction( const transaction_metadata_ptr& trx,
                          fc::time_point deadline = fc::time_point::maximum(),
D
Daniel Larimer 已提交
492
                          bool implicit = false ) {
D
Daniel Larimer 已提交
493 494 495
      //if( !implicit )
      //   idump((fc::json::to_pretty_string(trx->trx)));

D
Daniel Larimer 已提交
496
      if( deadline == fc::time_point() ) {
497
         unapplied_transactions[trx->signed_id] = trx;
D
Daniel Larimer 已提交
498 499
         return;
      }
500

501
      transaction_trace_ptr trace;
D
Daniel Larimer 已提交
502 503
      try {
         unapplied_transactions.erase( trx->signed_id );
504

D
Daniel Larimer 已提交
505
         transaction_context trx_context( self, trx->trx, trx->id );
506
         trace = trx_context.trace;
507

A
arhag 已提交
508
         auto required_delay = limit_delay( authorization.check_authorization( trx->trx.actions, trx->recover_keys() ) );
509 510 511 512
         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()) );
513

D
Daniel Larimer 已提交
514 515
         trx_context.deadline  = deadline;
         trx_context.published = self.pending_block_time();
516
         trx_context.net_usage = self.validate_net_usage( trx ); // / 8; // <-- BUG? Needed to be removed to fix auth_tests/no_double_billing
D
Daniel Larimer 已提交
517 518
         trx_context.is_input  = !implicit;
         trx_context.exec();
519

D
Daniel Larimer 已提交
520 521 522 523 524 525 526 527
         fc::move_append( pending->_actions, move(trx_context.executed) );

         if( !implicit ) {
            if( trx_context.delay == fc::seconds(0) ) {
               trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::executed, trace->kcpu_usage(), trx_context.net_usage );
            } else {
               trace->receipt = push_receipt( trx->packed_trx, transaction_receipt::delayed, trace->kcpu_usage(), trx_context.net_usage );
            }
528
         }
529

530 531 532 533 534
         transaction_trace_notify(trx, trace);

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

D
Daniel Larimer 已提交
535
         self.accepted_transaction(trx);
536
         self.applied_transaction(trace);
D
Daniel Larimer 已提交
537
         trx_context.squash();
538
         return;
D
Daniel Larimer 已提交
539
      } catch ( const fc::exception& e ) {
540
         trace->soft_except = e;
D
Daniel Larimer 已提交
541
         trace->hard_except_ptr = std::current_exception();
542 543
         //wlog( "caught exception in push_transaction" );
         //wdump((trace));
D
Daniel Larimer 已提交
544
      }
545
      transaction_trace_notify(trx, trace);
546

547
   } /// push_transaction
D
Daniel Larimer 已提交
548

549

550
   void start_block( block_timestamp_type when ) {
551
      FC_ASSERT( !pending );
D
Daniel Larimer 已提交
552

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

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
      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 已提交
578

579 580 581 582 583 584
      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" );
      }
585
   } // start_block
D
Daniel Larimer 已提交
586 587


D
Daniel Larimer 已提交
588

589 590
   void sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
      auto p = pending->_pending_block_state;
591
      p->sign( signer_callback );
592 593
      static_cast<signed_block_header&>(*p->block) = p->header;
   } /// sign_block
D
Daniel Larimer 已提交
594

595
   void apply_block( const signed_block_ptr& b ) { try {
596 597 598 599 600 601 602 603 604
      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 已提交
605 606 607
            else if( receipt.trx.contains<transaction_id_type>() ) {
               self.push_scheduled_transaction( receipt.trx.get<transaction_id_type>() );
            }
608
         }
D
Daniel Larimer 已提交
609

610 611
         finalize_block();
         sign_block( [&]( const auto& ){ return b->producer_signature; } );
D
Daniel Larimer 已提交
612

613 614 615
         // 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 已提交
616

617 618
         commit_block(false);
         return;
D
Daniel Larimer 已提交
619
      } catch ( const fc::exception& e ) {
620 621
         edump((e.to_detail_string()));
         abort_block();
D
Daniel Larimer 已提交
622 623
         throw;
      }
624
   } FC_CAPTURE_AND_RETHROW() } /// apply_block
625 626


627
   void push_block( const signed_block_ptr& b ) {
D
Daniel Larimer 已提交
628 629 630 631
      try {
         auto new_header_state = fork_db.add( b );
         self.accepted_block_header( new_header_state );
         maybe_switch_forks();
A
arhag 已提交
632
      } FC_LOG_AND_RETHROW()
633
   }
634

635 636 637 638 639 640 641
   void push_confirmation( const header_confirmation& c ) {
      fork_db.add( c );
      self.accepted_confirmation( c );
      maybe_switch_forks();
   }

   void maybe_switch_forks() {
642 643 644 645
      auto new_head = fork_db.head();

      if( new_head->header.previous == head->id ) {
         try {
646
            abort_block();
647
            apply_block( new_head->block );
648
            fork_db.mark_in_current_chain( new_head, true );
649 650 651
            fork_db.set_validity( new_head, true );
            head = new_head;
         } catch ( const fc::exception& e ) {
652
            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.
653 654
            throw;
         }
655
      } else if( new_head->id != head->id ) {
656
         ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
A
arhag 已提交
657
              ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) );
658 659
         auto branches = fork_db.fetch_branch_from( new_head->id, head->id );

660 661
         for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) {
            fork_db.mark_in_current_chain( *itr , false );
662
            pop_block();
663 664 665
         }
         FC_ASSERT( head_block_id() == branches.second.back()->header.previous,
                    "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
666 667 668 669 670

         for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr) {
            optional<fc::exception> except;
            try {
               apply_block( (*ritr)->block );
671
               head = *ritr;
672
               fork_db.mark_in_current_chain( *ritr, true );
673 674 675
            }
            catch (const fc::exception& e) { except = e; }
            if (except) {
676
               elog("exception thrown while switching forks ${e}", ("e",except->to_detail_string()));
677

678 679 680 681
               while (ritr != branches.first.rend() ) {
                  fork_db.set_validity( *ritr, false );
                  ++ritr;
               }
682

683
               // pop all blocks from the bad fork
684 685
               for( auto itr = (ritr + 1).base(); itr != branches.second.end(); ++itr ) {
                  fork_db.mark_in_current_chain( *itr , false );
686
                  pop_block();
687 688 689
               }
               FC_ASSERT( head_block_id() == branches.second.back()->header.previous,
                          "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail
690

691 692 693
               // re-apply good blocks
               for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
                  apply_block( (*ritr)->block );
694
                  head = *ritr;
695
                  fork_db.mark_in_current_chain( *ritr, true );
696 697 698 699
               }
               throw *except;
            } // end if exception
         } /// end for each block in branch
700
         ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id));
701 702 703
      }
   } /// push_block

704
   void abort_block() {
705
      if( pending ) {
706
         for( const auto& t : pending->_pending_block_state->trxs )
707
            unapplied_transactions[t->signed_id] = t;
708 709
         pending.reset();
      }
710 711
   }

D
Daniel Larimer 已提交
712 713 714 715 716

   bool should_enforce_runtime_limits()const {
      return false;
   }

D
Daniel Larimer 已提交
717 718 719 720 721 722 723 724
   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 已提交
725

D
Daniel Larimer 已提交
726 727
   void set_trx_merkle() {
      vector<digest_type> trx_digests;
D
Daniel Larimer 已提交
728 729 730
      const auto& trxs = pending->_pending_block_state->block->transactions;
      trx_digests.reserve( trxs.size() );
      for( const auto& a : trxs )
D
Daniel Larimer 已提交
731
         trx_digests.emplace_back( a.digest() );
D
Daniel Larimer 已提交
732

D
Daniel Larimer 已提交
733
      pending->_pending_block_state->header.transaction_mroot = merkle( move(trx_digests) );
D
Daniel Larimer 已提交
734 735 736
   }


737
   void finalize_block()
D
Daniel Larimer 已提交
738
   { try {
D
Daniel Larimer 已提交
739 740 741
      if( !pending ) self.start_block();

      /*
742
      ilog( "finalize block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} #dtrxs: ${ndtrxs} ${np}",
A
arhag 已提交
743 744
            ("n",pending->_pending_block_state->block_num)
            ("id",pending->_pending_block_state->header.id())
745
            ("t",pending->_pending_block_state->header.timestamp)
A
arhag 已提交
746 747
            ("p",pending->_pending_block_state->header.producer)
            ("signing_key", pending->_pending_block_state->block_signing_key)
748 749
            ("v",pending->_pending_block_state->header.schedule_version)
            ("lib",pending->_pending_block_state->dpos_last_irreversible_blocknum)
750
            ("ndtrxs",db.get_index<generated_transaction_multi_index,by_trx_id>().size())
751 752
            ("np",pending->_pending_block_state->header.new_producers)
            );
753
      */
D
Daniel Larimer 已提交
754 755 756 757 758 759 760

      set_action_merkle();
      set_trx_merkle();

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

D
Daniel Larimer 已提交
761
      create_block_summary();
D
Daniel Larimer 已提交
762

D
Daniel Larimer 已提交
763 764 765 766 767 768 769 770
      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}}
      );

   } FC_CAPTURE_AND_RETHROW() }

D
Daniel Larimer 已提交
771 772 773 774 775 776 777 778 779

   void create_block_summary() {
      auto p = pending->_pending_block_state;
      auto sid = p->block_num & 0xffff;
      db.modify( db.get<block_summary_object,by_id>(sid), [&](block_summary_object& bso ) {
          bso.block_id = p->id;
      });
   }

D
Daniel Larimer 已提交
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
   void clear_expired_transactions() {
      //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>();
      while( (!dedupe_index.empty()) && (head_block_time() > fc::time_point(dedupe_index.begin()->expiration) ) ) {
         transaction_idx.remove(*dedupe_index.begin());
      }

      // Look for expired transactions in the pending generated list, and remove them.
      // TODO: expire these by sending error to handler
      auto& generated_transaction_idx = db.get_mutable_index<generated_transaction_multi_index>();
      const auto& generated_index = generated_transaction_idx.indices().get<by_expiration>();
      while( (!generated_index.empty()) && (head_block_time() > generated_index.begin()->expiration) ) {
      // TODO:   destroy_generated_transaction(*generated_index.begin());
      }
   }

A
arhag 已提交
797 798
   fc::microseconds limit_delay( fc::microseconds delay )const {
      auto max_delay = fc::seconds( self.get_global_properties().configuration.max_transaction_delay );
799
      return std::min(delay, max_delay);
A
arhag 已提交
800 801
   }

D
Daniel Larimer 已提交
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
   /*
   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 已提交
822
   signed_transaction get_on_block_transaction()
D
Daniel Larimer 已提交
823 824 825 826 827 828 829
   {
      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}};
      on_block_act.data = fc::raw::pack(head_block_header());

D
Daniel Larimer 已提交
830
      signed_transaction trx;
D
Daniel Larimer 已提交
831 832 833 834 835 836
      trx.actions.emplace_back(std::move(on_block_act));
      trx.set_reference_block(head_block_id());
      trx.expiration = head_block_time() + fc::seconds(1);
      return trx;
   }

837
}; /// controller_impl
D
Daniel Larimer 已提交
838

839
const resource_limits_manager&   controller::get_resource_limits_manager()const
D
Daniel Larimer 已提交
840 841 842
{
   return my->resource_limits;
}
843
resource_limits_manager&         controller::get_mutable_resource_limits_manager()
D
Daniel Larimer 已提交
844 845 846
{
   return my->resource_limits;
}
D
Daniel Larimer 已提交
847

848 849 850 851 852 853 854 855
const authorization_manager&   controller::get_authorization_manager()const
{
   return my->authorization;
}
authorization_manager&         controller::get_mutable_authorization_manager()
{
   return my->authorization;
}
D
Daniel Larimer 已提交
856 857 858 859 860 861 862 863 864 865 866

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

controller::~controller() {
}


void controller::startup() {
867
   my->init();
D
Daniel Larimer 已提交
868 869 870 871

   /*
   my->head = my->fork_db.head();
   if( !my->head ) {
D
Daniel Larimer 已提交
872
      elog( "No head block in fork db, perhaps we need to replay" );
D
Daniel Larimer 已提交
873 874 875 876
   }
   */
}

D
Daniel Larimer 已提交
877
chainbase::database& controller::db()const { return my->db; }
D
Daniel Larimer 已提交
878 879 880


void controller::start_block( block_timestamp_type when ) {
881
   my->start_block(when);
D
Daniel Larimer 已提交
882 883 884
}

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

888 889
void controller::sign_block( const std::function<signature_type( const digest_type& )>& signer_callback ) {
   my->sign_block( signer_callback );
D
Daniel Larimer 已提交
890 891 892
}

void controller::commit_block() {
D
Daniel Larimer 已提交
893
   my->commit_block(true);
D
Daniel Larimer 已提交
894 895
}

D
Daniel Larimer 已提交
896 897 898
block_state_ptr controller::head_block_state()const {
   return my->head;
}
899

D
Daniel Larimer 已提交
900 901 902 903
block_state_ptr controller::pending_block_state()const {
   if( my->pending ) return my->pending->_pending_block_state;
   return block_state_ptr();
}
D
Daniel Larimer 已提交
904

905 906
void controller::abort_block() {
   my->abort_block();
D
Daniel Larimer 已提交
907 908
}

D
Daniel Larimer 已提交
909
void controller::push_block( const signed_block_ptr& b ) {
910
   my->push_block( b );
D
Daniel Larimer 已提交
911 912 913
   if( !my->replaying ) {
      log_irreversible_blocks();
   }
D
Daniel Larimer 已提交
914 915
}

916 917 918 919
void controller::push_confirmation( const header_confirmation& c ) {
   my->push_confirmation( c );
}

D
Daniel Larimer 已提交
920 921 922
void controller::push_transaction( const transaction_metadata_ptr& trx, fc::time_point deadline ) {
   my->push_transaction(trx, deadline);
}
923 924 925

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

D
Daniel Larimer 已提交
928 929
transaction_trace_ptr controller::sync_push( const transaction_metadata_ptr& trx, time_point deadline ) {
   FC_ASSERT( deadline != fc::time_point() );
930
   transaction_trace_ptr trace;
931
   trx->on_result = [&]( const transaction_trace_ptr& t ){ trace = t; };
D
Daniel Larimer 已提交
932
   my->push_transaction( trx, deadline );
933
   return trace;
D
Daniel Larimer 已提交
934
}
D
Daniel Larimer 已提交
935

936
bool controller::push_next_scheduled_transaction( fc::time_point deadline ) {
D
Daniel Larimer 已提交
937
   const auto& idx = db().get_index<generated_transaction_multi_index,by_delay>();
938 939 940 941 942 943
   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 已提交
944
}
D
Daniel Larimer 已提交
945

946
void controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline ) {
D
Daniel Larimer 已提交
947 948 949 950
   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 已提交
951 952 953 954 955
}

uint32_t controller::head_block_num()const {
   return my->head->block_num;
}
D
Daniel Larimer 已提交
956 957 958
block_id_type controller::head_block_id()const {
   return my->head->id;
}
D
Daniel Larimer 已提交
959 960 961 962 963 964
account_name  controller::head_block_producer()const {
   return my->head->header.producer;
}
uint32_t controller::last_irreversible_block_num() const {
   return my->head->bft_irreversible_blocknum;
}
D
Daniel Larimer 已提交
965

D
Daniel Larimer 已提交
966
block_id_type controller::last_irreversible_block_id() const {
967
   //QUESTION/BUG: What if lib has not advanced for over 2^16 blocks?
D
Daniel Larimer 已提交
968 969 970 971
   const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)my->head->bft_irreversible_blocknum);
   return tapos_block_summary.block_id;
}

D
Daniel Larimer 已提交
972
time_point controller::head_block_time()const {
973 974 975 976 977 978
   return my->head_block_time();
}

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 已提交
979 980
}

D
Daniel Larimer 已提交
981 982 983
const dynamic_global_property_object& controller::get_dynamic_global_properties()const {
  return my->db.get<dynamic_global_property_object>();
}
D
Daniel Larimer 已提交
984 985 986
const global_property_object& controller::get_global_properties()const {
  return my->db.get<global_property_object>();
}
D
Daniel Larimer 已提交
987 988 989 990

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

D
Daniel Larimer 已提交
999 1000 1001 1002
   const auto& log_head = my->blog.head();
   auto lib = my->head->dpos_last_irreversible_blocknum;

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

D
Daniel Larimer 已提交
1025
signed_block_ptr controller::fetch_block_by_number( uint32_t block_num )const  { try {
1026
   auto blk_state = my->fork_db.get_block_in_current_chain_by_num( block_num );
D
Daniel Larimer 已提交
1027 1028 1029
   if( blk_state ) {
      return blk_state->block;
   }
1030

D
Daniel Larimer 已提交
1031
   ilog( "blog read by number ${n}", ("n", block_num) );
D
Daniel Larimer 已提交
1032
   return my->blog.read_block_by_num(block_num);
D
Daniel Larimer 已提交
1033
} FC_CAPTURE_AND_RETHROW( (block_num) ) }
D
Daniel Larimer 已提交
1034 1035

void controller::pop_block() {
1036
   my->pop_block();
D
Daniel Larimer 已提交
1037 1038
}

1039
bool controller::set_proposed_producers( vector<producer_key> producers ) {
1040 1041
   const auto& gpo = get_global_properties();
   auto cur_block_num = head_block_num() + 1;
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056

   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;

1057
   if( my->pending->_pending_block_state->pending_schedule.producers.size() == 0 ) {
1058 1059 1060 1061
      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;
1062
   } else {
1063 1064 1065 1066
      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;
1067
   }
1068 1069 1070 1071 1072 1073

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

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

1074 1075
   my->db.modify( gpo, [&]( auto& gp ) {
      gp.proposed_schedule_block_num = cur_block_num;
1076
      gp.proposed_schedule = std::move(sch);
1077
   });
1078
   return true;
D
Daniel Larimer 已提交
1079
}
1080 1081

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

1087
const producer_schedule_type&    controller::pending_producers()const {
D
Daniel Larimer 已提交
1088 1089 1090
   return my->pending->_pending_block_state->pending_schedule;
}

1091 1092 1093 1094 1095 1096 1097 1098 1099
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 已提交
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
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 已提交
1113

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

1119 1120 1121 1122
const map<digest_type, transaction_metadata_ptr>&  controller::unapplied_transactions()const {
   return my->unapplied_transactions;
}

A
arhag 已提交
1123 1124 1125
fc::microseconds controller::limit_delay( fc::microseconds delay )const {
   return my->limit_delay( delay );
}
1126 1127 1128 1129 1130 1131

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

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

1146 1147 1148 1149 1150
   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()));
1151 1152 1153 1154 1155 1156 1157 1158
   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 已提交
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
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

   uint32_t net_usage_limit = trx->trx.max_net_usage_words.value * 8UL; // overflow checked in validate_transaction_without_state
   EOS_ASSERT( net_usage_limit == 0 || actual_net_usage <= net_usage_limit, tx_resource_exhausted,
               "declared net usage limit of transaction is too low: ${actual_net_usage} > ${declared_limit}",
               ("actual_net_usage", actual_net_usage)("declared_limit",net_usage_limit) );

   return actual_net_usage;
}

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

1183

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