def test_same_message_after_init(): node_id_1 = 'n1' node_id_2 = 'n2' node_id_3 = 'n3' blockchain1 = simple_blockchain_factory( node_id_1, 'http://localhost:5001', 100, [node_id_2, node_id_3], ) node2 = node_factory(node_id_2, Endpoint.from_uri('http://localhost:5002')) node3 = node_factory(node_id_3, Endpoint.from_uri('http://localhost:5003')) blockchain1.consensus.add_to_validator_connected(node2) blockchain1.consensus.add_to_validator_connected(node3) message = Message.new('message') ballot1 = Ballot.new(node_id_1, message, IsaacState.INIT, BallotVotingResult.agree) ballot2 = copy_ballot(ballot1, node_id_2, IsaacState.INIT) ballot3 = copy_ballot(ballot1, node_id_3, IsaacState.INIT) blockchain1.receive_ballots(ballot1, ballot2, ballot3) assert blockchain1.consensus.slot.get_ballot_state(ballot1) == IsaacState.SIGN existing_ballot_ids = set( map(lambda x: x.ballot_id, filter(lambda x: x is not None, blockchain1.consensus.slot.get_all_ballots()))) # send same message in new ballot, which has previous state new_ballot1 = Ballot.new(node_id_1, message, IsaacState.INIT, BallotVotingResult.agree) assert new_ballot1.ballot_id != ballot1.ballot_id ballot1 = copy_ballot(new_ballot1, node_id_1, IsaacState.INIT) ballot2 = copy_ballot(new_ballot1, node_id_2, IsaacState.INIT) ballot3 = copy_ballot(new_ballot1, node_id_3, IsaacState.INIT) blockchain1.receive_ballots(ballot1, ballot2, ballot3) # node doesn't have ballot1, so ballot1 in node state is NONE assert blockchain1.consensus.slot.get_ballot_state(ballot1) == IsaacState.NONE list(filter( lambda x: x.ballot_id == ballot1.ballot_id, blockchain1.consensus.slot.get_validator_ballots(ballot1).values() )) assert len([]) < 1 current_ballot_ids = set( map(lambda x: x.ballot_id, filter(lambda x: x is not None, blockchain1.consensus.slot.get_all_ballots()))) assert existing_ballot_ids == current_ballot_ids return
def blockchain_factory(name, address, threshold, validator_endpoint_uris, slot_size): node = node_factory(name, Endpoint.from_uri(address)) validators = list() for uri in validator_endpoint_uris: validators.append(node_factory(uri, Endpoint.from_uri(uri)), ) consensus = IsaacConsensus(node, threshold, validators, slot_size) consensus._check_slot_time = check_slot_time_stub Blockchain.receive_ballot = receive_copy_ballot return Blockchain(consensus, StubTransport())
def simple_blockchain_factory(name, address, threshold, validator_endpoint_uris): node = node_factory(name, Endpoint.from_uri(address)) validators = list() for uri in validator_endpoint_uris: validators.append(node_factory(uri, Endpoint(uri, uri, 0)), ) consensus = Consensus(node, threshold, validators) transport = StubTransport(bind=('0.0.0.0', 5001)) return SimpleBlockchain(consensus, transport)
def test_isaac_consensus(): node = node_factory('n1', Endpoint.from_uri('http://localhost:5001')) validator_uris = ('http://localhost:5002', 'http://localhost:5003') validators = list() for uri in validator_uris: validators.append(node_factory(uri, Endpoint.from_uri(uri)), ) consensus = IsaacConsensus(node, 100, validators) assert consensus.minimum == 3 assert consensus.threshold == 100 uris = list(map(lambda x: x.endpoint.uri, consensus.validator_candidates)) assert set(validator_uris) == set(uris)
def blockchain_factory(Consensus, name, address, threshold, validators, slot_size, queue_size): node = node_factory(name, Endpoint.from_uri(address)) consensus = Consensus(node, threshold, validators, slot_size) transport = network_module.Transport(node, loop) return Blockchain(consensus, transport)
def main(options): config = collections.namedtuple( 'Config', ('node_name', 'port', 'threshold', 'validators', 'faulty_percent'), )(uuid.uuid1().hex, 8001, 51, [], 0) if not pathlib.Path(options.conf).exists(): parser.error('conf file, `%s` does not exists.' % options.conf) if not pathlib.Path(options.conf).is_file(): parser.error('conf file, `%s` is not valid file.' % options.conf) conf = configparser.ConfigParser() conf.read(options.conf) log.info('conf file, `%s` was loaded', options.conf) config = config._replace(node_name=conf['node']['name']) config = config._replace(port=int(conf['node']['port'])) config = config._replace(threshold=int(conf['node']['threshold_percent'])) if conf.has_option('faulty', 'faulty_percent'): config = config._replace( faulty_percent=int(conf['faulty']['faulty_percent'])) log.debug('loaded conf: %s', config) validator_list = [] for i in filter(lambda x: len(x.strip()) > 0, conf['node']['validator_list'].split(',')): validator_list.append(Endpoint.from_uri(i.strip())) config = config._replace(validators=validator_list) log.debug('Validators: %s' % config.validators) node = node_factory( config.node_name, Endpoint(NETWORK_MODULE.SCHEME, get_local_ipaddress(), config.port), config.faulty_percent) consensus_module = get_fba_module('isaac') consensus = consensus_module.IsaacConsensus( node, config.threshold, tuple(map(lambda x: Node(x.extras['name'], x), config.validators)), ) log.metric(node=node.name, data=node.to_dict()) transport = NETWORK_MODULE.Transport(bind=('0.0.0.0', config.port)) blockchain = Blockchain(consensus, transport) base_server = BaseServer(blockchain) base_server.start() return
def test_confirm_stuck_ballot(): node_name_1 = 'http://localhost:5001' node_name_2 = 'http://localhost:5002' node_name_3 = 'http://localhost:5003' bc1 = simple_blockchain_factory( node_name_1, 'http://localhost:5001', 100, [node_name_2, node_name_3], ) node2 = node_factory(node_name_2, Endpoint.from_uri('http://localhost:5002')) node3 = node_factory(node_name_3, Endpoint.from_uri('http://localhost:5003')) bc1.consensus.add_to_validator_connected(node2) bc1.consensus.add_to_validator_connected(node3) message = Message.new('message') ballot_init_1 = Ballot.new(node_name_1, message, IsaacState.INIT, BallotVotingResult.agree) ballot_id = ballot_init_1.ballot_id ballot_init_2 = Ballot(ballot_id, node_name_2, message, IsaacState.INIT, BallotVotingResult.agree, ballot_init_1.timestamp) ballot_init_3 = Ballot(ballot_id, node_name_3, message, IsaacState.INIT, BallotVotingResult.agree, ballot_init_1.timestamp) bc1.receive_ballot(ballot_init_1) bc1.receive_ballot(ballot_init_2) bc1.receive_ballot(ballot_init_3) assert bc1.consensus.slot.get_ballot_state( ballot_init_1) == IsaacState.SIGN time.sleep(LIMIT_TIME + 0.1) assert bc1.consensus.slot.get_ballot_state( ballot_init_1) == IsaacState.NONE return
def generate_blockchains(Consensus, node_names, node_endpoints, threshold, slot_size=5, queue_size=100): blockchains = list() nodes = list() for i in range(len(node_names)): nodes.append( node_factory(node_names[i], Endpoint.from_uri(node_endpoints[i]))) for i in range(len(node_names)): validators = copy.deepcopy(nodes) del validators[i] blockchain = blockchain_factory(Consensus, node_names[i], node_endpoints[i], 100, validators, slot_size, queue_size) blockchains.append(blockchain) return blockchains
def test_same_message_after_allconfirm(): node_id_1 = 'n1' node_id_2 = 'n2' node_id_3 = 'n3' blockchain1 = simple_blockchain_factory( node_id_1, 'http://localhost:5001', 100, [node_id_2, node_id_3], ) node2 = node_factory(node_id_2, Endpoint.from_uri('http://localhost:5002')) node3 = node_factory(node_id_3, Endpoint.from_uri('http://localhost:5003')) blockchain1.consensus.add_to_validator_connected(node2) blockchain1.consensus.add_to_validator_connected(node3) message = Message.new('message') ballot1 = Ballot.new(node_id_1, message, IsaacState.INIT, BallotVotingResult.agree) ballot2 = copy_ballot(ballot1, node_id_2, IsaacState.INIT) ballot3 = copy_ballot(ballot1, node_id_3, IsaacState.INIT) blockchain1.receive_ballots(ballot1, ballot2, ballot3) assert blockchain1.consensus.slot.get_ballot_state(ballot1) == IsaacState.SIGN ballot1 = copy_ballot(ballot1, node_id_1, IsaacState.SIGN) ballot2 = copy_ballot(ballot1, node_id_2, IsaacState.SIGN) ballot3 = copy_ballot(ballot1, node_id_3, IsaacState.SIGN) blockchain1.receive_ballots(ballot1, ballot2, ballot3) assert blockchain1.consensus.slot.get_ballot_state(ballot1) == IsaacState.ACCEPT ballot1 = copy_ballot(ballot1, node_id_1, IsaacState.ACCEPT) ballot2 = copy_ballot(ballot1, node_id_2, IsaacState.ACCEPT) ballot3 = copy_ballot(ballot1, node_id_3, IsaacState.ACCEPT) blockchain1.receive_ballots(ballot1, ballot2, ballot3) assert message in blockchain1.consensus.messages # send same message in new ballot new_ballot1 = Ballot.new(node_id_1, message, IsaacState.INIT, BallotVotingResult.agree) assert new_ballot1.ballot_id != ballot1.ballot_id ballot1 = copy_ballot(new_ballot1, node_id_1, IsaacState.INIT) ballot2 = copy_ballot(new_ballot1, node_id_2, IsaacState.INIT) ballot3 = copy_ballot(new_ballot1, node_id_3, IsaacState.INIT) blockchain1.receive_ballots(ballot1, ballot2, ballot3) # node state still remains the previous state assert message in blockchain1.consensus.messages ballots = blockchain1.consensus.slot.get_validator_ballots(new_ballot1).values() assert not ballots return
def test_use_fake(): node = node_factory('n1', Endpoint.from_uri('http://localhost:5001')) consensus = FakeConsensus(node) assert consensus.node_name == 'n1'
def load_design(filename): design = None with open(filename) as f: if filename.split('.')[-1] == 'yml': design = convert_dict_to_namedtuple(yaml.load(f.read())) elif filename.split('.')[-1] == 'json': temp_design = convert_json_config(json.load(f)) design = convert_dict_to_namedtuple(temp_design) else: print( '# error: \"file `%s` is not valid file. yml or json type is needed\"' % filename) sys.exit(1) defined_ports = list() for name, config in design.nodes._asdict().items(): port = getattr(config, 'port', None) if port is None: continue defined_ports.append(port) faulty_nodes = dict() nodes = dict() for name, config in design.nodes._asdict().items(): port = getattr(config, 'port', None) if port is None: port = get_free_port(defined_ports) endpoint = Endpoint(NETWORK_MODULE.SCHEME, get_local_ipaddress(), port, name=name) node = node_factory(name, endpoint, 0) if hasattr(config.quorum, 'threshold'): threshold = config.quorum.threshold else: threshold = design.common.threshold nodes[name] = dict(node=node, quorum=dict(validators=list(), threshold=threshold)) faulties = list() faulty = getattr(getattr(design, 'faulties', None), name, None) if faulty is not None: for case in faulty: kind = FaultyNodeKind.get_from_name(case.case.kind) if kind in (FaultyNodeKind.Unknown, ): continue dict_case = convert_namedtuple_to_dict(case.case) dict_case['kind'] = kind faulties.append(dict_case) if len(faulties) > 0: faulty_nodes[name] = faulties for name, config in design.nodes._asdict().items(): for node_name in config.quorum.validators: nodes[name]['quorum']['validators'].append( nodes[node_name]['node']) design_dict = convert_namedtuple_to_dict(design) if 'audit_waiting' not in design_dict['common']: design_dict['common']['audit_waiting'] = 1 if 'audit_time_limit' not in design_dict['common']: design_dict['common']['audit_time_limit'] = 2 design_dict['common']['network_module'] = NETWORK_MODULE design_dict['nodes'] = list(nodes.values()) design_dict['nodes_by_name'] = nodes design_dict['faulties'] = faulty_nodes return convert_dict_to_namedtuple(design_dict)