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 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) ) }
bool signed_by( const address& a ) { if( !available_address_sigs ) { available_address_sigs = std::map<address,public_key_type>(); provided_address_sigs = std::map<address,public_key_type>(); for( auto& item : available_keys ) { (*available_address_sigs)[ address(pts_address(item, false, 56) ) ] = item; (*available_address_sigs)[ address(pts_address(item, true, 56) ) ] = item; (*available_address_sigs)[ address(pts_address(item, false, 0) ) ] = item; (*available_address_sigs)[ address(pts_address(item, true, 0) ) ] = item; (*available_address_sigs)[ address(item) ] = item; } for( auto& item : provided_signatures ) { (*provided_address_sigs)[ address(pts_address(item.first, false, 56) ) ] = item.first; (*provided_address_sigs)[ address(pts_address(item.first, true, 56) ) ] = item.first; (*provided_address_sigs)[ address(pts_address(item.first, false, 0) ) ] = item.first; (*provided_address_sigs)[ address(pts_address(item.first, true, 0) ) ] = item.first; (*provided_address_sigs)[ address(item.first) ] = item.first; } } auto itr = provided_address_sigs->find(a); if( itr == provided_address_sigs->end() ) { auto aitr = available_address_sigs->find(a); if( aitr != available_address_sigs->end() ) { auto pk = available_keys.find(aitr->second); if( pk != available_keys.end() ) return provided_signatures[aitr->second] = true; return false; } } return provided_signatures[itr->second] = true; }
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_result balance_claim_evaluator::do_evaluate(const balance_claim_operation& op) { database& d = db(); balance = &op.balance_to_claim(d); GRAPHENE_ASSERT( op.balance_owner_key == balance->owner || pts_address(op.balance_owner_key, false, 56) == balance->owner || pts_address(op.balance_owner_key, true, 56) == balance->owner || pts_address(op.balance_owner_key, false, 0) == balance->owner || pts_address(op.balance_owner_key, true, 0) == balance->owner, balance_claim_owner_mismatch, "Balance owner key was specified as '${op}' but balance's actual owner is '${bal}'", ("op", op.balance_owner_key) ("bal", balance->owner) ); if( !(d.get_node_properties().skip_flags & (database::skip_authority_check | database::skip_transaction_signatures)) ) FC_ASSERT(op.total_claimed.asset_id == balance->asset_type()); if( balance->is_vesting_balance() ) { GRAPHENE_ASSERT( balance->vesting_policy->is_withdraw_allowed( { balance->balance, d.head_block_time(), op.total_claimed } ), balance_claim_invalid_claim_amount, "Attempted to claim ${c} from a vesting balance with ${a} available", ("c", op.total_claimed)("a", balance->available(d.head_block_time())) ); GRAPHENE_ASSERT( d.head_block_time() - balance->last_claim_date >= fc::days(1), balance_claim_claimed_too_often, "Genesis vesting balances may not be claimed more than once per day." ); return {}; } FC_ASSERT(op.total_claimed == balance->balance); return {}; }
std::unordered_set<bts::pts_address> signed_transaction::get_signed_pts_addresses()const { auto dig = digest(); std::unordered_set<pts_address> r; // add both compressed and uncompressed forms... for( auto itr = sigs.begin(); itr != sigs.end(); ++itr ) { auto signed_key_data = fc::ecc::public_key( *itr, dig ).serialize(); auto signed_key_point = fc::ecc::public_key( *itr, dig ).serialize_ecc_point(); // note: 56 is the version bit of protoshares r.insert( pts_address(fc::ecc::public_key( signed_key_data),false,56) ); r.insert( pts_address(fc::ecc::public_key( signed_key_data ),true,56) ); // note: 5 comes from en.bitcoin.it/wiki/Vanitygen where version bit is 0 r.insert( pts_address(fc::ecc::public_key( signed_key_data ),false,0) ); r.insert( pts_address(fc::ecc::public_key( signed_key_data ),true,0) ); } ilog( "${signed_addr}", ("signed_addr",r) ); return r; }
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) ) }
void wallet_db::store_key( const key_data& key_to_store ) { auto key_itr = keys.find( key_to_store.get_address() ); if( key_itr != keys.end() ) { key_data& old_data = key_itr->second; old_data = key_to_store; if( key_to_store.has_private_key()) { auto oacct = lookup_account( key_to_store.account_address ); FC_ASSERT(oacct.valid(), "expecting an account to existing at this point"); oacct->is_my_account = true; store_record( *oacct ); cache_account( *oacct ); ilog( "WALLET: storing private key for ${key} under account '${account_name}' address: (${account})", ("key",key_to_store.public_key) ("account",key_to_store.account_address) ("account_name",get_account_name(key_to_store.account_address)) ); } else { /* ilog( "WALLET: storing public key ${key} under account named '${account_name}' address: (${account})", ("key",key_to_store.public_key) ("account",key_to_store.account_address) ("account_name",get_account_name(key_to_store.account_address)) ); */ } ilog( "storing key" ); store_record( key_itr->second, true ); } else { auto r = wallet_key_record( key_to_store, new_wallet_record_index() ); store_record( keys[key_to_store.get_address()] = r, true ); auto key = key_to_store.public_key; auto bts_addr = key_to_store.get_address(); btc_to_bts_address[ address(key) ] = bts_addr; btc_to_bts_address[ address(pts_address(key,false,56) )] = bts_addr; btc_to_bts_address[ address(pts_address(key,true,56) ) ] = bts_addr; btc_to_bts_address[ address(pts_address(key,false,0) ) ] = bts_addr; btc_to_bts_address[ address(pts_address(key,true,0) ) ] = bts_addr; ilog( "indexing key ${k}", ("k",address(pts_address(key,false,56) ) ) ); ilog( "indexing key ${k}", ("k",address(pts_address(key,true,56) ) ) ); } }
void wallet_db::repair_records( const fc::sha512& password ) { try { FC_ASSERT( is_open() ); vector<generic_wallet_record> records; for( auto iter = my->_records.begin(); iter.valid(); ++iter ) records.push_back( iter.value() ); // Repair key_data.account_address when possible uint32_t count = 0; for( generic_wallet_record& record : records ) { try { if( wallet_record_type_enum( record.type ) == account_record_type ) { std::cout << "\rRepairing account record " << std::to_string( ++count ) << std::flush; wallet_account_record account_record = record.as<wallet_account_record>(); store_account( account_record ); } } catch( const fc::exception& ) { } } // Repair key_data.public_key when I have the private key and remove if I don't have the private key count = 0; for( generic_wallet_record& record : records ) { try { if( wallet_record_type_enum( record.type ) == key_record_type ) { std::cout << "\rRepairing key record " << std::to_string( ++count ) << std::flush; wallet_key_record key_record = record.as<wallet_key_record>(); const address key_address = key_record.get_address(); if( key_record.has_private_key() ) { const private_key_type private_key = key_record.decrypt_private_key( password ); const public_key_type public_key = private_key.get_public_key(); if( key_record.public_key != public_key ) { keys.erase( key_address ); btc_to_bts_address.erase( key_address ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, false, 0 ) ) ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, true, 0 ) ) ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, false, 56 ) ) ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, true, 56 ) ) ); key_record.public_key = public_key; my->load_key_record( key_record ); } } else { keys.erase( key_address ); btc_to_bts_address.erase( key_address ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, false, 0 ) ) ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, true, 0 ) ) ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, false, 56 ) ) ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, true, 56 ) ) ); remove_item( key_record.wallet_record_index ); continue; } store_key( key_record ); } } catch( const fc::exception& ) { } } // Repair transaction_data.record_id count = 0; for( generic_wallet_record& record : records ) { try { if( wallet_record_type_enum( record.type ) == transaction_record_type ) { std::cout << "\rRepairing transaction record " << std::to_string( ++count ) << std::flush; wallet_transaction_record transaction_record = record.as<wallet_transaction_record>(); if( transaction_record.trx.id() != signed_transaction().id() ) { const transaction_id_type record_id = transaction_record.trx.id(); if( transaction_record.record_id != record_id ) { transactions.erase( transaction_record.record_id ); id_to_transaction_record_index.erase( transaction_record.record_id ); transaction_record.record_id = record_id; my->load_transaction_record( transaction_record ); } } store_transaction( transaction_record ); } } catch( const fc::exception& ) { } } std::cout << "\rWallet records repaired. " << std::flush << "\n"; } FC_CAPTURE_AND_RETHROW() }
void wallet_db::repair_records( const fc::sha512& password ) { try { FC_ASSERT( is_open() ); vector<generic_wallet_record> records; for( auto iter = my->_records.begin(); iter.valid(); ++iter ) records.push_back( iter.value() ); // Repair account_data.is_my_account and key_data.account_address for( generic_wallet_record& record : records ) { try { if( wallet_record_type_enum( record.type ) == account_record_type ) { wallet_account_record account_record = record.as<wallet_account_record>(); store_account( account_record ); } } catch( ... ) { } } // Repair key_data.public_key when I have the private key and // repair key_data.account_address and account_data.is_my_account for( generic_wallet_record& record : records ) { try { if( wallet_record_type_enum( record.type ) == key_record_type ) { wallet_key_record key_record = record.as<wallet_key_record>(); if( key_record.has_private_key() ) { const private_key_type private_key = key_record.decrypt_private_key( password ); const public_key_type public_key = private_key.get_public_key(); if( key_record.public_key != public_key ) { const address key_address = key_record.get_address(); keys.erase( key_address ); btc_to_bts_address.erase( key_address ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, false, 0 ) ) ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, true, 0 ) ) ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, false, 56 ) ) ); btc_to_bts_address.erase( address( pts_address( key_record.public_key, true, 56 ) ) ); key_record.public_key = public_key; my->load_key_record( key_record ); } } store_key( key_record ); } } catch( ... ) { } } // Repair transaction_data.record_id for( generic_wallet_record& record : records ) { try { if( wallet_record_type_enum( record.type ) == transaction_record_type ) { wallet_transaction_record transaction_record = record.as<wallet_transaction_record>(); if( transaction_record.trx.id() != signed_transaction().id() ) { const transaction_id_type record_id = transaction_record.trx.permanent_id(); if( transaction_record.record_id != record_id ) { transactions.erase( transaction_record.record_id ); id_to_transaction_record_index.erase( transaction_record.record_id ); transaction_record.record_id = record_id; my->load_transaction_record( transaction_record ); } } store_transaction( transaction_record ); } } catch( ... ) { } } } FC_CAPTURE_AND_RETHROW() }