void network_broadcast_api::broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction& trx) { trx.validate(); _callbacks[trx.id()] = cb; _callbacks_expirations[trx.expiration].push_back(trx.id()); _app.chain_database()->push_transaction(trx); _app.p2p_node()->broadcast_transaction(trx); }
void wallet::sign_transaction( signed_transaction& trx, const bts::address& addr ) { ilog( "Sign ${trx} ${addr}", ("trx",trx.id())("addr",addr)); auto priv_key_idx = my->_my_addresses.find(addr); FC_ASSERT( priv_key_idx != my->_my_addresses.end() ); trx.sign( my->_data.extra_keys[priv_key_idx->second] ); }
void transaction_evaluation_state::evaluate( const signed_transaction& trx_arg ) { try { reset(); auto trx_id = trx_arg.id(); otransaction_location current_loc = _current_state->get_transaction_location( trx_id ); if( !!current_loc ) fail( BTS_DUPLICATE_TRANSACTION, "transaction has already been processed" ); trx = trx_arg; auto digest = trx_arg.digest(); for( auto sig : trx.signatures ) { auto key = fc::ecc::public_key( sig, digest ).serialize(); signed_keys.insert( address(key) ); signed_keys.insert( address(pts_address(key,false,56) ) ); signed_keys.insert( address(pts_address(key,true,56) ) ); signed_keys.insert( address(pts_address(key,false,0) ) ); signed_keys.insert( address(pts_address(key,true,0) ) ); } for( auto op : trx.operations ) { evaluate_operation( op ); } post_evaluate(); validate_required_fee(); update_delegate_votes(); } FC_RETHROW_EXCEPTIONS( warn, "", ("trx",trx_arg) ) }
void client_impl::on_new_transaction(const signed_transaction& trx) { _chain_db->evaluate_transaction(trx); // throws exception if invalid trx. if (_pending_trxs.insert(std::make_pair(trx.id(), trx)).second) ilog("new transaction"); else wlog("duplicate transaction, ignoring"); }
/** * Stores a transaction and updates the spent status of all * outputs doing one last check to make sure they are unspent. */ void store( const signed_transaction& t, const trx_num& tn ) { //ilog( "trxid: ${id} ${tn}\n\n ${trx}\n\n", ("id",t.id())("tn",tn)("trx",t) ); trx_id2num.store( t.id(), tn ); meta_trxs.store( tn, meta_trx(t) ); for( uint16_t i = 0; i < t.inputs.size(); ++i ) { mark_spent( t.inputs[i].output_ref, tn, i ); } }
void transaction_evaluation_state::evaluate( const signed_transaction& trx_arg, bool skip_signature_check, bool enforce_canonical ) { try { _skip_signature_check = skip_signature_check; try { if( _current_state->now() >= trx_arg.expiration ) { if( _current_state->now() > trx_arg.expiration || _current_state->get_head_block_num() >= BTS_V0_4_21_FORK_BLOCK_NUM ) { const auto expired_by_sec = (_current_state->now() - trx_arg.expiration).to_seconds(); FC_CAPTURE_AND_THROW( expired_transaction, (trx_arg)(_current_state->now())(expired_by_sec) ); } } if( (_current_state->now() + BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC) < trx_arg.expiration ) FC_CAPTURE_AND_THROW( invalid_transaction_expiration, (trx_arg)(_current_state->now()) ); auto trx_id = trx_arg.id(); if( _current_state->is_known_transaction( trx_arg.expiration, trx_arg.digest( _chain_id ) ) ) if (_current_state->get_head_block_num() >= FORK_25) FC_CAPTURE_AND_THROW( duplicate_transaction, (trx_id) ); trx = trx_arg; if( !_skip_signature_check ) { auto digest = trx_arg.digest( _chain_id ); for( const auto& sig : trx.signatures ) { auto key = fc::ecc::public_key( sig, digest, enforce_canonical ).serialize(); signed_keys.insert( address(key) ); signed_keys.insert( address(pts_address(key,false,56) ) ); signed_keys.insert( address(pts_address(key,true,56) ) ); signed_keys.insert( address(pts_address(key,false,0) ) ); signed_keys.insert( address(pts_address(key,true,0) ) ); } } current_op_index = 0; for( const auto& op : trx.operations ) { evaluate_operation( op ); ++current_op_index; } post_evaluate(); validate_required_fee(); update_delegate_votes(); } catch ( const fc::exception& e ) { validation_error = e; throw; } } FC_RETHROW_EXCEPTIONS( warn, "", ("trx",trx_arg) ) }
wallet_transaction_record wallet_db::cache_transaction( const signed_transaction& trx, const asset& amount, share_type fees, const string& memo_message, const public_key_type& to, time_point_sec created, time_point_sec received, public_key_type from, const vector<address>& extra_addresses ) { try { auto trx_id = trx.id(); auto itr = transactions.find( trx_id ); wallet_transaction_record data; if( itr != transactions.end() ) data = itr->second; if( data.wallet_record_index == 0 ) data.wallet_record_index = new_wallet_record_index(); data.trx = trx; data.transaction_id = trx.id(); data.amount = amount; data.fees = fees; data.to_account = to; data.from_account = from; data.created_time = created; data.received_time = received; data.memo_message = memo_message; data.extra_addresses = extra_addresses; store_record( data ); transactions[trx_id] = data; return data; //transaction_data data } FC_RETHROW_EXCEPTIONS( warn, "", ("trx",trx) ("memo_message",memo_message) ("to",to) ) }
void transaction_evaluation_state::evaluate( const signed_transaction& trx_arg, bool skip_signature_check ) { try { reset(); _skip_signature_check = skip_signature_check; try { if( trx_arg.expiration < _current_state->now() ) { auto expired_by_sec = (trx_arg.expiration - _current_state->now()).to_seconds(); FC_CAPTURE_AND_THROW( expired_transaction, (trx_arg)(_current_state->now())(expired_by_sec) ); } if( trx_arg.expiration > (_current_state->now() + BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC) ) FC_CAPTURE_AND_THROW( invalid_transaction_expiration, (trx_arg)(_current_state->now()) ); auto trx_size = fc::raw::pack_size(trx_arg); if( trx_size > BTS_BLOCKCHAIN_MAX_TRANSACTION_SIZE ) FC_CAPTURE_AND_THROW( oversized_transaction, (trx_size ) ); auto trx_id = trx_arg.id(); if( _current_state->is_known_transaction( trx_id ) ) FC_CAPTURE_AND_THROW( duplicate_transaction, (trx_id) ); trx = trx_arg; if( !_skip_signature_check ) { auto digest = trx_arg.digest( _chain_id ); for( auto sig : trx.signatures ) { auto key = fc::ecc::public_key( sig, digest ).serialize(); signed_keys.insert( address(key) ); signed_keys.insert( address(pts_address(key,false,56) ) ); signed_keys.insert( address(pts_address(key,true,56) ) ); signed_keys.insert( address(pts_address(key,false,0) ) ); signed_keys.insert( address(pts_address(key,true,0) ) ); } } for( auto op : trx.operations ) { evaluate_operation( op ); } post_evaluate(); validate_required_fee(); update_delegate_votes(); } catch ( const fc::exception& e ) { validation_error = e; throw; } } FC_RETHROW_EXCEPTIONS( warn, "", ("trx",trx_arg) ) }
void apply(database &db, const signed_transaction &t, const options_type &opts) { auto undo_session = db.start_undo_session(!(opts & skip_undo_transaction)); db.pre_apply_transaction(t); db.create<transaction_object>([&](transaction_object &trx) { trx.trx_id = t.id(); trx.block_num = db.head_block().block_num; auto pack_size = fc::raw::pack_size(t); trx.packed_transaction.resize(pack_size); fc::datastream<char *> ds(trx.packed_transaction.data(), pack_size); fc::raw::pack(ds, t); }); for (const auto &op : t.operations) { apply(db, op, opts); } db.post_apply_transaction(t); undo_session.squash(); }
void transaction_evaluation_state::evaluate( const signed_transaction& trx_arg ) { try { reset(); try { if( trx_arg.expiration && *trx_arg.expiration < _current_state->now() ) FC_CAPTURE_AND_THROW( expired_transaction, (trx_arg)(_current_state->now()) ); auto trx_id = trx_arg.id(); ilog( "id: ${id}", ("id",trx_id) ); otransaction_record known_transaction= _current_state->get_transaction( trx_id ); if( known_transaction ) FC_CAPTURE_AND_THROW( duplicate_transaction, (known_transaction) ); trx = trx_arg; auto digest = trx_arg.digest( _chain_id ); for( auto sig : trx.signatures ) { auto key = fc::ecc::public_key( sig, digest ).serialize(); signed_keys.insert( address(key) ); signed_keys.insert( address(pts_address(key,false,56) ) ); signed_keys.insert( address(pts_address(key,true,56) ) ); signed_keys.insert( address(pts_address(key,false,0) ) ); signed_keys.insert( address(pts_address(key,true,0) ) ); } for( auto op : trx.operations ) { evaluate_operation( op ); } post_evaluate(); validate_required_fee(); update_delegate_votes(); } catch ( const fc::exception& e ) { validation_error = e; throw; } } FC_RETHROW_EXCEPTIONS( warn, "", ("trx",trx_arg) ) }
processed_transaction database::_apply_transaction(const signed_transaction& trx) { try { uint32_t skip = get_node_properties().skip_flags; if( true || !(skip&skip_validate) ) /* issue #505 explains why this skip_flag is disabled */ trx.validate(); auto& trx_idx = get_mutable_index_type<transaction_index>(); const chain_id_type& chain_id = get_chain_id(); auto trx_id = trx.id(); FC_ASSERT( (skip & skip_transaction_dupe_check) || trx_idx.indices().get<by_trx_id>().find(trx_id) == trx_idx.indices().get<by_trx_id>().end() ); transaction_evaluation_state eval_state(this); const chain_parameters& chain_parameters = get_global_properties().parameters; eval_state._trx = &trx; if( !(skip & (skip_transaction_signatures | skip_authority_check) ) ) { auto get_active = [&]( account_id_type id ) { return &id(*this).active; }; auto get_owner = [&]( account_id_type id ) { return &id(*this).owner; }; trx.verify_authority( chain_id, get_active, get_owner, get_global_properties().parameters.max_authority_depth ); } //Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is //expired, and TaPoS makes no sense as no blocks exist. if( BOOST_LIKELY(head_block_num() > 0) ) { if( !(skip & skip_tapos_check) ) { const auto& tapos_block_summary = block_summary_id_type( trx.ref_block_num )(*this); //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration FC_ASSERT( trx.ref_block_prefix == tapos_block_summary.block_id._hash[1] ); } fc::time_point_sec now = head_block_time(); FC_ASSERT( trx.expiration <= now + chain_parameters.maximum_time_until_expiration, "", ("trx.expiration",trx.expiration)("now",now)("max_til_exp",chain_parameters.maximum_time_until_expiration)); FC_ASSERT( now <= trx.expiration, "", ("now",now)("trx.exp",trx.expiration) ); } //Insert transaction into unique transactions database. if( !(skip & skip_transaction_dupe_check) ) { create<transaction_object>([&](transaction_object& transaction) { transaction.trx_id = trx_id; transaction.trx = trx; }); } eval_state.operation_results.reserve(trx.operations.size()); //Finally process the operations processed_transaction ptrx(trx); _current_op_in_trx = 0; for( const auto& op : ptrx.operations ) { eval_state.operation_results.emplace_back(apply_operation(eval_state, op)); ++_current_op_in_trx; } ptrx.operation_results = std::move(eval_state.operation_results); //Make sure the temp account has no non-zero balances const auto& index = get_index_type<account_balance_index>().indices().get<by_account_asset>(); auto range = index.equal_range( boost::make_tuple( GRAPHENE_TEMP_ACCOUNT ) ); std::for_each(range.first, range.second, [](const account_balance_object& b) { FC_ASSERT(b.balance == 0); }); return ptrx; } FC_CAPTURE_AND_RETHROW( (trx) ) }
transaction_metadata( const packed_transaction& ptrx ) :trx( ptrx.get_signed_transaction() ), packed_trx(ptrx) { id = trx.id(); //raw_packed = fc::raw::pack( static_cast<const transaction&>(trx) ); signed_id = digest_type::hash(packed_trx); }
transaction_metadata( const signed_transaction& t, packed_transaction::compression_type c = packed_transaction::none ) :trx(t),packed_trx(t, c) { id = trx.id(); //raw_packed = fc::raw::pack( static_cast<const transaction&>(trx) ); signed_id = digest_type::hash(packed_trx); }