def sync(): Client(os.environ.get('SENTRY_DSN')) public_url = get_my_public_url() if public_url: click.echo(f"You have a public node url. ({public_url})") Node.broadcast(Node.post_node_endpoint, {'url': public_url}) Node.update() engine = db.engine if not engine.dialect.has_table(engine.connect(), Block.__tablename__): click.echo("You need to initialize. try `nekoyume init`.") return False while True: try: prev_id = Block.query.order_by(Block.id.desc()).first().id except AttributeError: prev_id = 0 Block.sync(click=click) try: if prev_id == Block.query.order_by(Block.id.desc()).first().id: click.echo("The blockchain is up to date.") time.sleep(15) except AttributeError: click.echo(("There is no well-connected node. " "please check you network.")) break
def init(seed): click.echo('Creating database...') db.create_all() click.echo(f'Updating node... (seed: {seed})') Node.update(Node(url=seed)) click.echo('Syncing blocks...') Block.sync(click=click)
def test_hack_and_slash_execute(fx_user, fx_novice_status): move = fx_user.create_novice(fx_novice_status) Block.create(fx_user, [move]) avatar = fx_user.avatar() avatar.hp = 0 move = fx_user.move(HackAndSlash()) Block.create(fx_user, [move]) with raises(InvalidMoveError): move.execute(avatar)
def post_block(): new_block = request.get_json() last_block = Block.query.order_by(Block.id.desc()).first() if not new_block: return jsonify(result='failed', message="empty block."), 400 if not last_block and new_block['id'] != 1: Block.sync(Node.query.order_by(Node.last_connected_at.desc()).first()) return jsonify(result='failed', message="new block isn't our next block."), 403 if (new_block['id'] > 1 and (new_block['id'] != last_block.id + 1 or new_block['prev_hash'] != last_block.hash)): if new_block['id'] > last_block.id + 1: Block.sync( Node.query.order_by(Node.last_connected_at.desc()).first()) return jsonify(result='failed', message="new block isn't our next block."), 403 block = Block.deserialize(new_block) for new_move in new_block['moves']: move = Move.query.get(new_move['id']) if not move: move = Move( id=new_move['id'], user=new_move['user'], name=new_move['name'], signature=new_move['signature'], tax=new_move['tax'], details=new_move['details'], created_at=datetime.datetime.strptime(new_move['created_at'], '%Y-%m-%d %H:%M:%S.%f'), block_id=block.id, ) if not move.valid: return jsonify(result='failed', message=f"move {move.id} isn't valid."), 400 block.moves.append(move) if not block.valid: return jsonify(result='failed', message="new block isn't valid."), 400 db.session.add(block) try: db.session.commit() except IntegrityError: return jsonify(result='failed', message="This node already has this block."), 400 sent_node = Node() if 'sent_node' in new_block: sent_node.url = new_block['sent_node'] block_broadcast.delay(block.id, sent_node_url=sent_node.url, my_node_url=f'{request.scheme}://{request.host}') return jsonify(result='success')
def init(seed, sync): click.echo('Creating database...') db.create_all() click.echo(f'Updating node... (seed: {seed})') if seed: Node.update(Node.get(url=seed)) else: Node.update() if sync: click.echo('Syncing blocks...') Block.sync(click=click)
def neko(private_key): app.app_context().push() while True: Block.sync() block = User(private_key).create_block( Move.query.filter_by(block=None).limit(20).all(), click=click, ) if block: block.broadcast() click.echo(block)
def add_block(new_block): block = Block() block.id = new_block['id'] block.creator = new_block['creator'] block.created_at = datetime.datetime.strptime(new_block['created_at'], '%Y-%m-%d %H:%M:%S.%f') block.prev_hash = new_block['prev_hash'] block.hash = new_block['hash'] block.difficulty = new_block['difficulty'] block.suffix = new_block['suffix'] block.root_hash = new_block['root_hash'] fx_session.add(block) return block
def init(seed, sync): echo('Creating database...') db.create_all() echo(f'Updating node... (seed: {seed})') if sync: Node.update(Node.get(url=seed)) echo('Syncing blocks...') Block.sync(echo=echo) echo('Compiling translations...') dir_path = os.path.abspath(os.path.dirname(__file__)) compile_command = compile_catalog() compile_command.directory = dir_path + '/translations' compile_command.finalize_options() compile_command.run()
def neko(private_key): app.app_context().push() Client(os.environ.get('SENTRY_DSN')) while True: Block.sync() block = User(private_key).create_block( [ m for m in Move.query.filter_by(block=None).limit(20).all() if m.valid ], click=click, ) if block: block.broadcast() click.echo(block)
def test_get_blocks(fx_test_client, fx_user): move = fx_user.sleep() rv = fx_test_client.get(f'/moves/{move.id}') assert rv.status == '200 OK' assert move.id.encode() in rv.data block = Block.create(fx_user, [move]) rv = fx_test_client.get(f'/blocks') assert rv.status == '200 OK' assert block.hash.encode() in rv.data assert move.id.encode() in rv.data rv = fx_test_client.get(f'/blocks/{block.id}') assert rv.status == '200 OK' assert block.hash.encode() in rv.data assert move.id.encode() in rv.data rv = fx_test_client.get(f'/blocks/{block.hash}') assert rv.status == '200 OK' assert block.hash.encode() in rv.data rv = fx_test_client.get(f'/blocks/last') assert rv.status == '200 OK' assert block.hash.encode() in rv.data
def test_block_validation(fx_user, fx_novice_status): move = fx_user.create_novice(fx_novice_status) block = Block.create(fx_user, [move]) assert block.valid move.id = ('00000000000000000000000000000000' '00000000000000000000000000000000') assert not block.valid
def sync(): public_url = get_my_public_url() if public_url: click.echo(f"You have a public node url. ({public_url})") Node.broadcast(Node.post_node_endpoint, {'url': public_url}) while True: try: prev_id = Block.query.order_by(Block.id.desc()).first().id except AttributeError: click.echo("You need to initialize. try `nekoyume init`.") break if not prev_id: click.echo("You need to initialize. try `nekoyume init`.") break Block.sync(click=click) if prev_id == Block.query.order_by(Block.id.desc()).first().id: click.echo("The blockchain is up to date.") time.sleep(15)
def test_prevent_hack_and_slash_when_dead( fx_test_client: FlaskClient, fx_session: Session, fx_user: User, fx_private_key: PrivateKey, fx_novice_status: typing.Dict[str, str], ): move = fx_user.create_novice(fx_novice_status) Block.create(fx_user, [move]) assert fx_user.avatar().dead is False while fx_user.avatar().hp > 0: move = fx_user.hack_and_slash() Block.create(fx_user, [move]) assert fx_user.avatar().dead is True response = fx_test_client.post('/session_moves', data={'name': 'hack_and_slash'}) assert response.status_code == 302
def test_sync(fx_user, fx_session, fx_other_user, fx_other_session, fx_server, fx_novice_status): assert fx_other_session.query(Block).count() == 0 assert fx_session.query(Block).count() == 0 Block.sync(Node(url=fx_server.url), fx_other_session) assert fx_other_session.query(Block).count() == 0 assert fx_session.query(Block).count() == 0 fx_other_user.create_block([]) Block.sync(Node(url=fx_server.url), fx_other_session) assert fx_other_session.query(Block).count() == 1 assert fx_session.query(Block).count() == 0 move = fx_user.create_novice(fx_novice_status) fx_user.create_block([move]) fx_user.create_block([]) fx_user.create_block([]) assert fx_other_session.query(Block).count() == 1 assert fx_other_session.query(Move).count() == 0 assert fx_session.query(Block).count() == 3 assert fx_session.query(Move).count() == 1 Block.sync(Node(url=fx_server.url), fx_other_session) assert fx_other_session.query(Block).count() == 3 assert fx_other_session.query(Move).count() == 1 assert fx_session.query(Block).count() == 3 assert fx_session.query(Move).count() == 1
def test_block_broadcast(fx_user, fx_session, fx_other_user, fx_other_session, fx_server): assert fx_other_session.query(Block).count() == 0 assert fx_session.query(Block).count() == 0 fx_other_session.add( Node(url=fx_server.url, last_connected_at=datetime.datetime.utcnow())) fx_other_session.commit() block = Block.create(fx_other_user, []) block.broadcast(session=fx_other_session) assert fx_other_session.query(Block).count() == 1 assert fx_session.query(Block).count() == 1
def test_avatar_basic_moves(fx_user, fx_novice_status): moves = [ CreateNovice(details=fx_novice_status), HackAndSlash(), Sleep(), Say(details={'content': 'hi'}), LevelUp(details={'new_status': 'strength'}), ] for move in moves: move = fx_user.move(move) block = Block.create(fx_user, [move]) assert move.valid assert move.confirmed assert block.valid assert fx_user.avatar(block.id)
def test_move_confirmed_and_validation(fx_user, fx_novice_status): move = Move() assert not move.confirmed assert not move.valid move = fx_user.create_novice(fx_novice_status) assert not move.confirmed assert move.valid block = Block.create(fx_user, [move]) assert move.block_id assert move.confirmed assert move.valid move.tax = 1 assert not move.valid assert not block.valid
def test_level_up(fx_user, fx_novice_status): move = fx_user.create_novice(fx_novice_status) Block.create(fx_user, [move]) while True: if fx_user.avatar().exp >= 8: break move = fx_user.hack_and_slash() Block.create(fx_user, [move]) if fx_user.avatar().hp <= 0: move = fx_user.sleep() Block.create(fx_user, [move]) assert fx_user.avatar().level >= 2
def test_move(fx_test_client, fx_session, fx_user, fx_private_key): rv = fx_test_client.post('/login', data={ 'private_key': fx_private_key.to_hex(), }, follow_redirects=True) rv = fx_test_client.post('/new') Block.create(fx_user, fx_session.query(Move).filter_by(block_id=None).all()) rv = fx_test_client.get('/') assert rv.status == '200 OK' assert fx_user.address.encode() in rv.data rv = fx_test_client.post('/session_moves', data={'name': 'hack_and_slash'}, follow_redirects=True) assert rv.status == '200 OK' Block.create(fx_user, fx_session.query(Move).filter_by(block_id=None).all()) rv = fx_test_client.post('/session_moves', data={'name': 'sleep'}, follow_redirects=True) assert rv.status == '200 OK' Block.create(fx_user, fx_session.query(Move).filter_by(block_id=None).all()) rv = fx_test_client.post('/session_moves', data={ 'name': 'say', 'content': 'hi!', }, follow_redirects=True) assert rv.status == '200 OK' Block.create(fx_user, fx_session.query(Move).filter_by(block_id=None).all())
def add_block(new_block): block = Block.deserialize(new_block) fx_session.add(block) return block
def test_flush_session_while_syncing(fx_user, fx_session, fx_other_session, fx_novice_status): # 1. block validation failure scenario # syncing without flushing can cause block validation failure move = fx_user.create_novice(fx_novice_status) invalid_block = Block.create(fx_user, [move]) fx_session.delete(invalid_block) # syncing valid blocks from another node new_blocks = [ { "created_at": "2018-04-13 11:36:17.920869", "creator": "ET8ngv45qwhkDiJS1ZrUxndcGTzHxjPZDs", "difficulty": 0, "hash": "da0182c494660af0d9dd288839ceb86498708f38c800363cd46ed1730013a4d8", # noqa "id": 1, "version": 2, "moves": [], "prev_hash": None, "root_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", # noqa "suffix": "00" }, { "created_at": "2018-04-13 11:36:17.935392", "creator": "ET8ngv45qwhkDiJS1ZrUxndcGTzHxjPZDs", "difficulty": 1, "hash": "014c44b9382a45c2a70d817c090e6b78af22b8f34b57fd7edb474344f25c439c", # noqa "id": 2, "version": 2, "moves": [], "prev_hash": "da0182c494660af0d9dd288839ceb86498708f38c800363cd46ed1730013a4d8", # noqa "root_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", # noqa "suffix": "0b" } ] def add_block(new_block): block = Block.deserialize(new_block) fx_session.add(block) return block valid_block1 = add_block(new_blocks[0]) valid_block2 = add_block(new_blocks[1]) assert invalid_block.hash == \ fx_session.query(Block).get(valid_block2.id - 1).hash assert valid_block2.valid is False fx_session.query(Block).delete() # 2. valid scenario # flush session after deleting the invalid block move = fx_user.create_novice(fx_novice_status) invalid_block = Block.create(fx_user, [move]) fx_session.delete(invalid_block) fx_session.flush() valid_block1 = add_block(new_blocks[0]) valid_block2 = add_block(new_blocks[1]) assert valid_block1.hash == \ fx_session.query(Block).get(valid_block2.id - 1).hash assert valid_block2.valid