void update_balance_vote_operation::evaluate( transaction_evaluation_state& eval_state )const { try { auto current_balance_record = eval_state.pending_state()->get_balance_record( this->balance_id ); FC_ASSERT( current_balance_record.valid(), "No such balance!" ); FC_ASSERT( current_balance_record->condition.asset_id == 0, "Only BTS balances can have restricted owners." ); FC_ASSERT( current_balance_record->condition.type == withdraw_signature_type, "Restricted owners not enabled for anything but basic balances" ); auto last_update_secs = current_balance_record->last_update.sec_since_epoch(); ilog("last_update_secs is: ${secs}", ("secs", last_update_secs) ); auto balance = current_balance_record->balance; auto fee = BTS_BLOCKCHAIN_PRECISION / 2; FC_ASSERT( balance > fee ); auto asset_rec = eval_state.pending_state()->get_asset_record( current_balance_record->condition.asset_id ); if( asset_rec->is_market_issued() ) FC_ASSERT( current_balance_record->condition.slate_id == 0 ); if( current_balance_record->condition.slate_id ) { eval_state.adjust_vote( current_balance_record->condition.slate_id, -balance ); } current_balance_record->balance -= balance; current_balance_record->last_update = eval_state.pending_state()->now(); ilog("I'm storing a balance record whose last update is: ${secs}", ("secs", current_balance_record->last_update) ); eval_state.pending_state()->store_balance_record( *current_balance_record ); auto new_restricted_owner = current_balance_record->restricted_owner; auto new_slate = current_balance_record->condition.slate_id; if( this->new_restricted_owner.valid() && (this->new_restricted_owner != new_restricted_owner) ) { ilog("@n new restricted owner specified and its not the existing one"); for( const auto& owner : current_balance_record->owners() ) //eventually maybe multisig can delegate vote { if( !eval_state.check_signature( owner ) ) FC_CAPTURE_AND_THROW( missing_signature, (owner) ); } new_restricted_owner = this->new_restricted_owner; new_slate = this->new_slate; } else // NOT this->new_restricted_owner.valid() || (this->new_restricted_owner == new_restricted_owner) { auto restricted_owner = current_balance_record->restricted_owner; /* FC_ASSERT( restricted_owner.valid(), "Didn't specify a new restricted owner, but one currently exists." ); */ ilog( "@n now: ${secs}", ("secs", eval_state.pending_state()->now().sec_since_epoch()) ); ilog( "@n last update: ${secs}", ("secs", last_update_secs ) ); FC_ASSERT( eval_state.pending_state()->now().sec_since_epoch() - last_update_secs >= BTS_BLOCKCHAIN_VOTE_UPDATE_PERIOD_SEC, "You cannot update your vote this frequently with only the voting key!" ); if( NOT eval_state.check_signature( *restricted_owner ) ) { const auto& owners = current_balance_record->owners(); for( const auto& owner : owners ) //eventually maybe multisig can delegate vote { if( NOT eval_state.check_signature( owner ) ) FC_CAPTURE_AND_THROW( missing_signature, (owner) ); } } new_slate = this->new_slate; } const auto owner = current_balance_record->owner(); FC_ASSERT( owner.valid() ); withdraw_condition new_condition( withdraw_with_signature( *owner ), 0, new_slate ); balance_record newer_balance_record( new_condition ); auto new_balance_record = eval_state.pending_state()->get_balance_record( newer_balance_record.id() ); if( !new_balance_record.valid() ) new_balance_record = current_balance_record; new_balance_record->condition = new_condition; if( new_balance_record->balance == 0 ) { new_balance_record->deposit_date = eval_state.pending_state()->now(); } else { fc::uint128 old_sec_since_epoch( current_balance_record->deposit_date.sec_since_epoch() ); fc::uint128 new_sec_since_epoch( eval_state.pending_state()->now().sec_since_epoch() ); fc::uint128 avg = (old_sec_since_epoch * new_balance_record->balance) + (new_sec_since_epoch * balance); avg /= (new_balance_record->balance + balance); new_balance_record->deposit_date = time_point_sec( avg.to_integer() ); } new_balance_record->last_update = eval_state.pending_state()->now(); new_balance_record->balance += (balance - fee); new_balance_record->restricted_owner = new_restricted_owner; eval_state.add_balance( asset(fee, 0) ); // update delegate vote on deposited account.. if( new_balance_record->condition.slate_id ) eval_state.adjust_vote( new_balance_record->condition.slate_id, (balance-fee) ); ilog("I'm storing a balance record whose last update is: ${secs}", ("secs", new_balance_record->last_update) ); eval_state.pending_state()->store_balance_record( *new_balance_record ); } FC_CAPTURE_AND_RETHROW( (*this) ) }
void deposit_operation::evaluate( transaction_evaluation_state& eval_state )const { try { if( this->amount <= 0 ) FC_CAPTURE_AND_THROW( negative_deposit, (amount) ); switch( withdraw_condition_types( this->condition.type ) ) { case withdraw_signature_type: case withdraw_multisig_type: case withdraw_escrow_type: break; default: FC_CAPTURE_AND_THROW( invalid_withdraw_condition, (*this) ); } const balance_id_type deposit_balance_id = this->balance_id(); obalance_record cur_record = eval_state.pending_state()->get_balance_record( deposit_balance_id ); if( !cur_record.valid() ) { cur_record = balance_record( this->condition ); if( this->condition.type == withdraw_escrow_type ) cur_record->meta_data = variant_object("creating_transaction_id", eval_state.trx.id() ); } if( cur_record->balance == 0 ) { cur_record->deposit_date = eval_state.pending_state()->now(); } else { fc::uint128 old_sec_since_epoch( cur_record->deposit_date.sec_since_epoch() ); fc::uint128 new_sec_since_epoch( eval_state.pending_state()->now().sec_since_epoch() ); fc::uint128 avg = (old_sec_since_epoch * cur_record->balance) + (new_sec_since_epoch * this->amount); avg /= (cur_record->balance + this->amount); cur_record->deposit_date = time_point_sec( avg.to_integer() ); } cur_record->balance += this->amount; eval_state.sub_balance( asset( this->amount, cur_record->asset_id() ) ); if( cur_record->condition.asset_id == 0 && cur_record->condition.slate_id ) eval_state.adjust_vote( cur_record->condition.slate_id, this->amount ); cur_record->last_update = eval_state.pending_state()->now(); const oasset_record asset_rec = eval_state.pending_state()->get_asset_record( cur_record->condition.asset_id ); FC_ASSERT( asset_rec.valid() ); if( asset_rec->is_market_issued() ) { FC_ASSERT( cur_record->condition.slate_id == 0 ); } const auto& owners = cur_record->owners(); for( const address& owner : owners ) { FC_ASSERT( asset_rec->address_is_whitelisted( owner ) ); } eval_state.pending_state()->store_balance_record( *cur_record ); } FC_CAPTURE_AND_RETHROW( (*this) ) }
void withdraw_operation::evaluate( transaction_evaluation_state& eval_state )const { try { if( this->amount <= 0 ) FC_CAPTURE_AND_THROW( negative_withdraw, (amount) ); obalance_record current_balance_record = eval_state.pending_state()->get_balance_record( this->balance_id ); if( !current_balance_record.valid() ) FC_CAPTURE_AND_THROW( unknown_balance_record, (balance_id) ); if( this->amount > current_balance_record->get_spendable_balance( eval_state.pending_state()->now() ).amount ) FC_CAPTURE_AND_THROW( insufficient_funds, (current_balance_record)(amount) ); auto asset_rec = eval_state.pending_state()->get_asset_record( current_balance_record->condition.asset_id ); FC_ASSERT( asset_rec.valid() ); const bool authority_is_retracting = asset_rec->flag_is_active( asset_record::retractable_balances ) && eval_state.verify_authority( asset_rec->authority ); if( !authority_is_retracting ) { FC_ASSERT( !asset_rec->flag_is_active( asset_record::halted_withdrawals ) ); switch( (withdraw_condition_types)current_balance_record->condition.type ) { case withdraw_signature_type: { const withdraw_with_signature condition = current_balance_record->condition.as<withdraw_with_signature>(); const address owner = condition.owner; if( !eval_state.check_signature( owner ) ) FC_CAPTURE_AND_THROW( missing_signature, (owner) ); break; } case withdraw_vesting_type: { const withdraw_vesting condition = current_balance_record->condition.as<withdraw_vesting>(); const address owner = condition.owner; if( !eval_state.check_signature( owner ) ) FC_CAPTURE_AND_THROW( missing_signature, (owner) ); break; } case withdraw_multisig_type: { auto multisig = current_balance_record->condition.as<withdraw_with_multisig>(); uint32_t valid_signatures = 0; for( const auto& sig : multisig.owners ) valid_signatures += eval_state.check_signature( sig ); if( valid_signatures < multisig.required ) FC_CAPTURE_AND_THROW( missing_signature, (valid_signatures)(multisig) ); break; } default: FC_CAPTURE_AND_THROW( invalid_withdraw_condition, (current_balance_record->condition) ); } } // update delegate vote on withdrawn account.. if( current_balance_record->condition.asset_id == 0 && current_balance_record->condition.slate_id ) eval_state.adjust_vote( current_balance_record->condition.slate_id, -this->amount ); if( asset_rec->is_market_issued() ) { auto yield = current_balance_record->calculate_yield( eval_state.pending_state()->now(), current_balance_record->balance, asset_rec->collected_fees, asset_rec->current_supply ); if( yield.amount > 0 ) { asset_rec->collected_fees -= yield.amount; current_balance_record->balance += yield.amount; current_balance_record->deposit_date = eval_state.pending_state()->now(); eval_state.yield_claimed[ current_balance_record->asset_id() ] += yield.amount; eval_state.pending_state()->store_asset_record( *asset_rec ); } } current_balance_record->balance -= this->amount; current_balance_record->last_update = eval_state.pending_state()->now(); eval_state.pending_state()->store_balance_record( *current_balance_record ); if( asset_rec->withdrawal_fee != 0 && !eval_state.verify_authority( asset_rec->authority ) ) eval_state.min_fees[ asset_rec->id ] = std::max( asset_rec->withdrawal_fee, eval_state.min_fees[ asset_rec->id ] ); eval_state.add_balance( asset( this->amount, current_balance_record->condition.asset_id ) ); } FC_CAPTURE_AND_RETHROW( (*this) ) }
void withdraw_operation::evaluate_v3( transaction_evaluation_state& eval_state ) { try { if( eval_state._current_state->get_head_block_num() < BTS_V0_4_15_FORK_BLOCK_NUM ) return evaluate_v2( eval_state ); if( this->amount <= 0 ) FC_CAPTURE_AND_THROW( negative_deposit, (amount) ); obalance_record current_balance_record = eval_state._current_state->get_balance_record( this->balance_id ); if( !current_balance_record ) FC_CAPTURE_AND_THROW( unknown_balance_record, (balance_id) ); if( this->amount > current_balance_record->balance ) // Some withdraw conditions require extra checks (e.g. vesting condition) FC_CAPTURE_AND_THROW( insufficient_funds, (current_balance_record) (amount) (current_balance_record->balance - amount) ); switch( (withdraw_condition_types)current_balance_record->condition.type ) { case withdraw_signature_type: { auto owner = current_balance_record->condition.as<withdraw_with_signature>().owner; if( !eval_state.check_signature( owner ) ) FC_CAPTURE_AND_THROW( missing_signature, (owner) ); break; } default: FC_CAPTURE_AND_THROW( invalid_withdraw_condition, (current_balance_record->condition) ); } // update delegate vote on withdrawn account.. if( current_balance_record->condition.asset_id == 0 && current_balance_record->condition.delegate_slate_id ) eval_state.adjust_vote( current_balance_record->condition.delegate_slate_id, -this->amount ); auto asset_rec = eval_state._current_state->get_asset_record( current_balance_record->condition.asset_id ); FC_ASSERT( asset_rec.valid() ); if( asset_rec->is_market_issued() ) { auto yield = current_balance_record->calculate_yield_v1( eval_state._current_state->now(), current_balance_record->balance, asset_rec->collected_fees, asset_rec->current_share_supply ); if( yield.amount > 0 ) { asset_rec->collected_fees -= yield.amount; current_balance_record->balance += yield.amount; current_balance_record->deposit_date = eval_state._current_state->now(); eval_state.yield[current_balance_record->condition.asset_id] += yield.amount; eval_state._current_state->store_asset_record( *asset_rec ); } } current_balance_record->balance -= this->amount; current_balance_record->last_update = eval_state._current_state->now(); eval_state._current_state->store_balance_record( *current_balance_record ); eval_state.add_balance( asset(this->amount, current_balance_record->condition.asset_id) ); } FC_CAPTURE_AND_RETHROW( (*this) ) }