Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Merge pull request #7667 from EOSIO/kayan_sign_key2
Browse files Browse the repository at this point in the history
fix 7600 double confirm after changing sign key
  • Loading branch information
arhag authored Jul 19, 2019
2 parents 3884ecb + 1575ea7 commit 81ccc42
Show file tree
Hide file tree
Showing 6 changed files with 302 additions and 30 deletions.
34 changes: 11 additions & 23 deletions plugins/producer_plugin/producer_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,28 +265,13 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin
}
} ) );

// since the watermark has to be set before a block is created, we are looking into the future to
// determine the new schedule to identify producers that have become active
chain::controller& chain = chain_plug->chain();
const auto hbn = bsp->block_num;
auto new_pbhs = bsp->next(bsp->header.timestamp.next(), 0);

// for newly installed producers we can set their watermarks to the block they became active
if( bsp->active_schedule.version != new_pbhs.active_schedule.version ) {
flat_set<account_name> new_producers;
new_producers.reserve(new_pbhs.active_schedule.producers.size());
for( const auto& p: new_pbhs.active_schedule.producers) {
if (_producers.count(p.producer_name) > 0)
new_producers.insert(p.producer_name);
}

for( const auto& p: bsp->active_schedule.producers) {
new_producers.erase(p.producer_name);
}

for (const auto& new_producer: new_producers) {
_producer_watermarks[new_producer] = hbn;
}
// simplify handling of watermark in on_block
auto block_producer = bsp->header.producer;
auto watermark_itr = _producer_watermarks.find( block_producer );
if( watermark_itr != _producer_watermarks.end() ) {
watermark_itr->second = bsp->block_num;
} else if( _producers.count( block_producer ) > 0 ) {
_producer_watermarks.emplace( block_producer, bsp->block_num );
}
}

Expand Down Expand Up @@ -1391,9 +1376,12 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() {
if (currrent_watermark_itr != _producer_watermarks.end()) {
auto watermark = currrent_watermark_itr->second;
if (watermark < hbs->block_num) {
blocks_to_confirm = std::min<uint16_t>(std::numeric_limits<uint16_t>::max(), (uint16_t)(hbs->block_num - watermark));
blocks_to_confirm = (uint16_t)(std::min<uint32_t>(std::numeric_limits<uint16_t>::max(), (uint32_t)(hbs->block_num - watermark)));
}
}

// can not confirm irreversible blocks
blocks_to_confirm = (uint16_t)(std::min<uint32_t>(blocks_to_confirm, (uint32_t)(hbs->block_num - hbs->dpos_irreversible_blocknum)));
}

_unapplied_transactions.add_aborted( chain.abort_block() );
Expand Down
20 changes: 17 additions & 3 deletions programs/eosio-launcher/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ enum allowed_connection : char {

class producer_names {
public:
static string producer_name(unsigned int producer_number);
static string producer_name(unsigned int producer_number, bool shared_producer = false);
private:
static const int total_chars = 12;
static const char slot_chars[];
Expand All @@ -358,8 +358,9 @@ const char producer_names::valid_char_range = sizeof(producer_names::slot_chars)

// for 26 or fewer total producers create "defproducera" .. "defproducerz"
// above 26 produce "defproducera" .. "defproducerz", "defproduceaa" .. "defproducerb", etc.
string producer_names::producer_name(unsigned int producer_number) {
string producer_names::producer_name(unsigned int producer_number, bool shared_producer) {
// keeping legacy "defproducer[a-z]", but if greater than valid_char_range, will use "defpraaaaaaa"
// shared_producer will appear in all nodes' config
char prod_name[] = "defproducera";
if (producer_number > valid_char_range) {
for (int current_char_loc = 5; current_char_loc < total_chars; ++current_char_loc) {
Expand All @@ -380,6 +381,12 @@ string producer_names::producer_name(unsigned int producer_number) {
// make sure we haven't cycled back to the first 26 names (some time after 26^6)
if (string(prod_name) == "defproducera" && producer_number != 0)
throw std::runtime_error( "launcher not designed to handle numbers this large " );

if (shared_producer) {
prod_name[0] = 's';
prod_name[1] = 'h';
prod_name[2] = 'r';
}
return prod_name;
}

Expand All @@ -389,6 +396,7 @@ struct launcher_def {
size_t unstarted_nodes;
size_t prod_nodes;
size_t producers;
size_t shared_producers;
size_t next_node;
string shape;
allowed_connection allowed_connections = PC_NONE;
Expand Down Expand Up @@ -479,7 +487,8 @@ launcher_def::set_options (bpo::options_description &cfg) {
("nodes,n",bpo::value<size_t>(&total_nodes)->default_value(1),"total number of nodes to configure and launch")
("unstarted-nodes",bpo::value<size_t>(&unstarted_nodes)->default_value(0),"total number of nodes to configure, but not launch")
("pnodes,p",bpo::value<size_t>(&prod_nodes)->default_value(1),"number of nodes that contain one or more producers")
("producers",bpo::value<size_t>(&producers)->default_value(21),"total number of non-bios producer instances in this network")
("producers",bpo::value<size_t>(&producers)->default_value(21),"total number of non-bios and non-shared producer instances in this network")
("shared-producers",bpo::value<size_t>(&shared_producers)->default_value(0),"total number of shared producers on each non-bios nodes")
("mode,m",bpo::value<vector<string>>()->multitoken()->default_value({"any"}, "any"),"connection mode, combination of \"any\", \"producers\", \"specified\", \"none\"")
("shape,s",bpo::value<string>(&shape)->default_value("star"),"network topology, use \"star\" \"mesh\" or give a filename for custom")
("genesis,g",bpo::value<string>()->default_value("./genesis.json"),"set the path to genesis.json")
Expand Down Expand Up @@ -901,6 +910,11 @@ launcher_def::bind_nodes () {
producer_set.schedule.push_back({prodname,pubkey});
++producer_number;
}
for (unsigned j = 0; j < shared_producers; ++j) {
const auto prodname = producer_names::producer_name(j, true);
node.producers.push_back(prodname);
producer_set.schedule.push_back({prodname,pubkey});
}
}
node.dont_start = i >= to_not_start_node;
}
Expand Down
5 changes: 5 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/launcher_test.py ${CMAKE_CURRENT_BINA
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/db_modes_test.py ${CMAKE_CURRENT_BINARY_DIR}/db_modes_test.py COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/prod_preactivation_test.py ${CMAKE_CURRENT_BINARY_DIR}/prod_preactivation_test.py COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version-label.sh ${CMAKE_CURRENT_BINARY_DIR}/version-label.sh COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/nodeos_producer_watermark_test.py ${CMAKE_CURRENT_BINARY_DIR}/nodeos_producer_watermark_test.py COPYONLY)

#To run plugin_test with all log from blockchain displayed, put --verbose after --, i.e. plugin_test -- --verbose
add_test(NAME plugin_test COMMAND plugin_test --report_level=detailed --color_output)
Expand Down Expand Up @@ -132,6 +133,10 @@ add_test(NAME nodeos_multiple_version_protocol_feature_mv_test COMMAND tests/nod
-v --clean-run --dump-error-detail --alternate-version-labels-file ${ALTERNATE_VERSION_LABELS_FILE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST nodeos_multiple_version_protocol_feature_mv_test PROPERTY LABELS mixed_version_tests)

add_test(NAME nodeos_producer_watermark_lr_test COMMAND tests/nodeos_producer_watermark_test.py -v --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
set_property(TEST nodeos_producer_watermark_lr_test PROPERTY LABELS long_running_tests)


if(ENABLE_COVERAGE_TESTING)

set(Coverage_NAME ${PROJECT_NAME}_coverage)
Expand Down
7 changes: 5 additions & 2 deletions tests/Cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def setAlternateVersionLabels(self, file):
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements
def launch(self, pnodes=1, unstartedNodes=0, totalNodes=1, prodCount=1, topo="mesh", delay=1, onlyBios=False, dontBootstrap=False,
totalProducers=None, extraNodeosArgs=None, useBiosBootFile=True, specificExtraNodeosArgs=None, onlySetProds=False,
totalProducers=None, sharedProducers=0, extraNodeosArgs=None, useBiosBootFile=True, specificExtraNodeosArgs=None, onlySetProds=False,
pfSetupPolicy=PFSetupPolicy.FULL, alternateVersionLabelsFile=None, associatedNodeLabels=None, loadSystemContract=True):
"""Launch cluster.
pnodes: producer nodes count
Expand Down Expand Up @@ -200,6 +200,9 @@ def launch(self, pnodes=1, unstartedNodes=0, totalNodes=1, prodCount=1, topo="me
assert(isinstance(totalProducers, (str,int)))
producerFlag="--producers %s" % (totalProducers)

if sharedProducers > 0:
producerFlag += (" --shared-producers %d" % (sharedProducers))

self.setAlternateVersionLabels(alternateVersionLabelsFile)

tries = 30
Expand Down Expand Up @@ -431,7 +434,7 @@ def connectGroup(group, producerNodes, bridgeNodes) :
if not loadSystemContract:
useBiosBootFile=False #ensure we use Cluster.bootstrap
if onlyBios or not useBiosBootFile:
self.biosNode=self.bootstrap(biosNode, startedNodes, prodCount, totalProducers, pfSetupPolicy, onlyBios, onlySetProds, loadSystemContract)
self.biosNode=self.bootstrap(biosNode, startedNodes, prodCount + sharedProducers, totalProducers, pfSetupPolicy, onlyBios, onlySetProds, loadSystemContract)
if self.biosNode is None:
Utils.Print("ERROR: Bootstrap failed.")
return False
Expand Down
9 changes: 7 additions & 2 deletions tests/Node.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def __init__(self, host, port, pid=None, cmd=None, walletMgr=None, enableMongo=F
self.infoValid=None
self.lastRetrievedHeadBlockNum=None
self.lastRetrievedLIB=None
self.lastRetrievedHeadBlockProducer=""
self.transCache={}
self.walletMgr=walletMgr
self.missingTransaction=False
Expand Down Expand Up @@ -1169,6 +1170,7 @@ def getInfo(self, silentErrors=False, exitOnError=False):
self.infoValid=True
self.lastRetrievedHeadBlockNum=int(info["head_block_num"])
self.lastRetrievedLIB=int(info["last_irreversible_block_num"])
self.lastRetrievedHeadBlockProducer=info["head_block_producer"]
return info

def getBlockFromDb(self, idx):
Expand Down Expand Up @@ -1313,9 +1315,12 @@ def getBlockProducer(self, timeout=None, waitForBlock=True, exitOnError=True, bl
return blockProducer

def getNextCleanProductionCycle(self, trans):
transId=Node.getTransId(trans)
rounds=21*12*2 # max time to ensure that at least 2/3+1 of producers x blocks per producer x at least 2 times
self.waitForTransFinalization(transId, timeout=rounds/2)
if trans is not None:
transId=Node.getTransId(trans)
self.waitForTransFinalization(transId, timeout=rounds/2)
else:
transId="Null"
irreversibleBlockNum=self.getIrreversibleBlockNum()

# The voted schedule should be promoted now, then need to wait for that to become irreversible
Expand Down
Loading

0 comments on commit 81ccc42

Please sign in to comment.