diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 58ce0b7a..92fa0335 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include #include @@ -183,7 +185,10 @@ void database::update_active_witnesses() } // Update witness authority - modify( get(GRAPHENE_WITNESS_ACCOUNT), [&]( account_object& a ) { + modify( get(GRAPHENE_WITNESS_ACCOUNT), [&]( account_object& a ) + { + if( head_block_time() < HARDFORK_533_TIME ) + { uint64_t total_votes = 0; map weights; a.active.weight_threshold = 0; @@ -208,7 +213,15 @@ void database::update_active_witnesses() a.active.weight_threshold /= 2; a.active.weight_threshold += 1; - }); + } + else + { + vote_counter vc; + for( const witness_object& wit : wits ) + vc.add( wit.witness_account, _vote_tally_buffer[wit.vote_id] ); + vc.finish( a.active ); + } + } ); modify(gpo, [&]( global_property_object& gp ){ gp.active_witnesses.clear(); @@ -256,7 +269,10 @@ void database::update_active_committee_members() // Update committee authorities if( !committee_members.empty() ) { - modify(get(GRAPHENE_COMMITTEE_ACCOUNT), [&](account_object& a) { + modify(get(GRAPHENE_COMMITTEE_ACCOUNT), [&](account_object& a) + { + if( head_block_time() < HARDFORK_533_TIME ) + { uint64_t total_votes = 0; map weights; a.active.weight_threshold = 0; @@ -281,7 +297,15 @@ void database::update_active_committee_members() a.active.weight_threshold /= 2; a.active.weight_threshold += 1; - }); + } + else + { + vote_counter vc; + for( const committee_member_object& cm : committee_members ) + vc.add( cm.committee_member_account, _vote_tally_buffer[cm.vote_id] ); + vc.finish( a.active ); + } + } ); modify(get(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT), [&](account_object& a) { a.active = get(GRAPHENE_COMMITTEE_ACCOUNT).active; }); diff --git a/libraries/chain/hardfork.d/533.hf b/libraries/chain/hardfork.d/533.hf new file mode 100644 index 00000000..3830028b --- /dev/null +++ b/libraries/chain/hardfork.d/533.hf @@ -0,0 +1,4 @@ +// #533 Improve vote counting implementation +#ifndef HARDFORK_533_TIME +#define HARDFORK_533_TIME (fc::time_point_sec( 1455127200 )) +#endif diff --git a/libraries/chain/include/graphene/chain/vote_count.hpp b/libraries/chain/include/graphene/chain/vote_count.hpp new file mode 100644 index 00000000..ad14e22d --- /dev/null +++ b/libraries/chain/include/graphene/chain/vote_count.hpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015 Cryptonomex, Inc., and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include + +namespace graphene { namespace chain { + +/** + * Keep track of vote totals in internal authority object. See #533. + */ +struct vote_counter +{ + template< typename Component > + void add( Component who, uint64_t votes ) + { + assert( votes <= last_votes ); + last_votes = votes; + if( bitshift == -1 ) + bitshift = std::max(int(boost::multiprecision::detail::find_msb( votes )) - 15, 0); + uint64_t scaled_votes = std::max( votes >> bitshift, uint64_t(1) ); + assert( scaled_votes <= std::numeric_limits::max() ); + total_votes += scaled_votes; + assert( total_votes <= std::numeric_limits::max() ); + auth.add_authority( who, weight_type( scaled_votes ) ); + } + + /** + * Write into out_auth, but only if we have at least one member. + */ + void finish( authority& out_auth ) + { + if( total_votes == 0 ) + return; + assert( total_votes <= std::numeric_limits::max() ); + uint32_t weight = uint32_t( total_votes ); + weight = (weight >> 1)+1; + auth.weight_threshold = weight; + out_auth = auth; + } + + uint64_t last_votes = std::numeric_limits::max(); + uint64_t total_votes = 0; + int8_t bitshift = -1; + authority auth; +}; + +} } // graphene::chain