hippius 0.2.50__tar.gz → 0.2.52__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {hippius-0.2.50 → hippius-0.2.52}/PKG-INFO +1 -1
  2. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/__init__.py +1 -1
  3. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli.py +30 -0
  4. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli_handlers.py +408 -0
  5. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli_parser.py +123 -0
  6. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/ipfs.py +15 -17
  7. {hippius-0.2.50 → hippius-0.2.52}/pyproject.toml +1 -1
  8. {hippius-0.2.50 → hippius-0.2.52}/README.md +0 -0
  9. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli_assets.py +0 -0
  10. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli_rich.py +0 -0
  11. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/client.py +0 -0
  12. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/config.py +0 -0
  13. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/README.md +0 -0
  14. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/env.db.template +0 -0
  15. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/migrations/20241201000001_create_key_storage_tables.sql +0 -0
  16. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/migrations/20241202000001_switch_to_subaccount_encryption.sql +0 -0
  17. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/setup_database.sh +0 -0
  18. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db_utils.py +0 -0
  19. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/errors.py +0 -0
  20. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/incentives.py +0 -0
  21. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/ipfs_core.py +0 -0
  22. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/key_storage.py +0 -0
  23. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/substrate.py +0 -0
  24. {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hippius
3
- Version: 0.2.50
3
+ Version: 0.2.52
4
4
  Summary: Python SDK and CLI for Hippius blockchain storage
5
5
  Home-page: https://github.com/thenervelab/hippius-sdk
6
6
  Author: Dubs
@@ -26,7 +26,7 @@ from hippius_sdk.config import (
26
26
  from hippius_sdk.ipfs import IPFSClient, S3PublishResult, S3DownloadResult
27
27
  from hippius_sdk.utils import format_cid, format_size, hex_to_ipfs_cid
28
28
 
29
- __version__ = "0.2.50"
29
+ __version__ = "0.2.52"
30
30
  __all__ = [
31
31
  "HippiusClient",
32
32
  "IPFSClient",
@@ -446,6 +446,36 @@ def main():
446
446
  nonce_hex=getattr(args, "nonce_hex", None),
447
447
  dry_run=getattr(args, "dry_run", False),
448
448
  )
449
+ elif args.miner_action == "verify-node":
450
+ return run_async_handler(
451
+ cli_handlers.handle_verify_node,
452
+ client,
453
+ args.node_id,
454
+ args.node_priv_hex,
455
+ ipfs_config=getattr(args, "ipfs_config", None),
456
+ ipfs_priv_b64=getattr(args, "ipfs_priv_b64", None),
457
+ ipfs_peer_id=getattr(args, "ipfs_peer_id", None),
458
+ expires_in=getattr(args, "expires_in", 10),
459
+ block_width=getattr(args, "block_width", "u32"),
460
+ domain=getattr(args, "domain", "HIPPIUS::REGISTER::v1"),
461
+ nonce_hex=getattr(args, "nonce_hex", None),
462
+ dry_run=getattr(args, "dry_run", False),
463
+ )
464
+ elif args.miner_action == "verify-coldkey-node":
465
+ return run_async_handler(
466
+ cli_handlers.handle_verify_coldkey_node,
467
+ client,
468
+ args.node_id,
469
+ args.node_priv_hex,
470
+ ipfs_config=getattr(args, "ipfs_config", None),
471
+ ipfs_priv_b64=getattr(args, "ipfs_priv_b64", None),
472
+ ipfs_peer_id=getattr(args, "ipfs_peer_id", None),
473
+ expires_in=getattr(args, "expires_in", 10),
474
+ block_width=getattr(args, "block_width", "u32"),
475
+ domain=getattr(args, "domain", "HIPPIUS::REGISTER::v1"),
476
+ nonce_hex=getattr(args, "nonce_hex", None),
477
+ dry_run=getattr(args, "dry_run", False),
478
+ )
449
479
  else:
450
480
  # Display the Hippius logo banner with Rich formatting
451
481
  console.print(HERO_TITLE, style="bold cyan")
@@ -3462,6 +3462,7 @@ def handle_register_coldkey(
3462
3462
 
3463
3463
  # Get keypair for signing
3464
3464
  from hippius_sdk.config import get_seed_phrase
3465
+
3465
3466
  seed_phrase = get_seed_phrase()
3466
3467
  if not seed_phrase:
3467
3468
  error("No seed phrase available for signing transaction")
@@ -3471,6 +3472,7 @@ def handle_register_coldkey(
3471
3472
 
3472
3473
  # Submit transaction
3473
3474
  log("Submitting registration transaction...")
3475
+ log(f"Using module: [bold cyan]Registration[/bold cyan]")
3474
3476
  call = substrate.compose_call(
3475
3477
  call_module="Registration",
3476
3478
  call_function="register_node_with_coldkey",
@@ -3678,6 +3680,7 @@ def handle_register_hotkey(
3678
3680
 
3679
3681
  # Get keypair for signing
3680
3682
  from hippius_sdk.config import get_seed_phrase
3683
+
3681
3684
  seed_phrase = get_seed_phrase()
3682
3685
  if not seed_phrase:
3683
3686
  error("No seed phrase available for signing transaction")
@@ -3687,6 +3690,7 @@ def handle_register_hotkey(
3687
3690
 
3688
3691
  # Submit transaction
3689
3692
  log("Submitting registration transaction...")
3693
+ log(f"Using module: [bold cyan]Registration[/bold cyan]")
3690
3694
  call = substrate.compose_call(
3691
3695
  call_module="Registration",
3692
3696
  call_function="register_node_with_hotkey",
@@ -3720,3 +3724,407 @@ def handle_register_hotkey(
3720
3724
 
3721
3725
  traceback.print_exc()
3722
3726
  return 1
3727
+
3728
+
3729
+ def handle_verify_node(
3730
+ client: HippiusClient,
3731
+ node_id: str,
3732
+ node_priv_hex: str,
3733
+ ipfs_config: str = None,
3734
+ ipfs_priv_b64: str = None,
3735
+ ipfs_peer_id: str = None,
3736
+ expires_in: int = 10,
3737
+ block_width: str = "u32",
3738
+ domain: str = "HIPPIUS::REGISTER::v1",
3739
+ nonce_hex: str = None,
3740
+ dry_run: bool = False,
3741
+ ) -> int:
3742
+ """Handle miner verify-node command"""
3743
+ try:
3744
+ # Get current account info
3745
+ account = get_active_account()
3746
+ if not account:
3747
+ error(
3748
+ "No active account. Please set up an account first with 'hippius account create' or 'hippius seed set'"
3749
+ )
3750
+ return 1
3751
+
3752
+ account_address = get_account_address(account)
3753
+ if not account_address:
3754
+ error(f"Could not get address for account '{account}'")
3755
+ return 1
3756
+
3757
+ info(
3758
+ f"Verifying existing node using account: [bold cyan]{account}[/bold cyan] ({account_address})"
3759
+ )
3760
+
3761
+ # Import and use incentives.py functionality
3762
+ from hippius_sdk.incentives import (
3763
+ load_ipfs_seed,
3764
+ load_main_seed,
3765
+ encode_account_id,
3766
+ verify_peer_id,
3767
+ blake2_256,
3768
+ manual_encode_challenge,
3769
+ )
3770
+ from substrateinterface import SubstrateInterface, Keypair
3771
+ from nacl.signing import SigningKey
3772
+ import base58
3773
+ import secrets
3774
+ from binascii import hexlify
3775
+
3776
+ # Initialize SubstrateInterface
3777
+ substrate = SubstrateInterface(url=client.substrate_client.url)
3778
+
3779
+ # Get genesis hash and current block
3780
+ genesis_hash_hex = substrate.get_block_hash(0)
3781
+ genesis_hash = bytes.fromhex(genesis_hash_hex[2:])
3782
+ current_block_number = substrate.get_block_number(None)
3783
+
3784
+ log(f"Current block number: {current_block_number}")
3785
+
3786
+ # Process node_id
3787
+ if node_id.startswith("0x"):
3788
+ node_id_bytes = bytes.fromhex(node_id[2:])
3789
+ else:
3790
+ node_id_bytes = base58.b58decode(node_id)
3791
+
3792
+ # Load IPFS and main seeds
3793
+ ipfs_seed, peerid_from_config = load_ipfs_seed(ipfs_config, ipfs_priv_b64)
3794
+ main_seed = load_main_seed(node_priv_hex)
3795
+
3796
+ # Create signing keys
3797
+ main_sk = SigningKey(main_seed)
3798
+ main_pk = bytes(main_sk.verify_key)
3799
+ ipfs_sk = SigningKey(ipfs_seed)
3800
+ ipfs_pk = bytes(ipfs_sk.verify_key)
3801
+
3802
+ # Handle IPFS peer ID
3803
+ if ipfs_peer_id:
3804
+ ipfs_peer_id_bytes = base58.b58decode(ipfs_peer_id)
3805
+ elif peerid_from_config:
3806
+ ipfs_peer_id_bytes = base58.b58decode(peerid_from_config)
3807
+ else:
3808
+ # For verification, IPFS peer ID might not be required for all node types
3809
+ ipfs_peer_id_bytes = b""
3810
+
3811
+ # Verify keys match node IDs
3812
+ if not verify_peer_id(main_pk, node_id_bytes, "Ed25519"):
3813
+ error("Main public key does not match node ID")
3814
+ return 1
3815
+
3816
+ if ipfs_peer_id_bytes and not verify_peer_id(
3817
+ ipfs_pk, ipfs_peer_id_bytes, "Ed25519"
3818
+ ):
3819
+ error("IPFS public key does not match peer ID")
3820
+ return 1
3821
+
3822
+ # Create challenge data
3823
+ domain_bytes = domain.encode()
3824
+ domain24 = b"HIPPIUS::REGISTER::v1" + b"\x00" * 3
3825
+ node_id_hash = blake2_256(node_id_bytes)
3826
+ ipfs_peer_id_hash = blake2_256(ipfs_peer_id_bytes)
3827
+
3828
+ nonce = (
3829
+ bytes.fromhex(nonce_hex[2:])
3830
+ if nonce_hex and nonce_hex.startswith("0x")
3831
+ else bytes.fromhex(nonce_hex)
3832
+ if nonce_hex
3833
+ else secrets.token_bytes(32)
3834
+ )
3835
+
3836
+ expires_at_block = current_block_number + expires_in
3837
+ account_bytes = encode_account_id(account_address)
3838
+
3839
+ challenge_data = {
3840
+ "domain": domain24,
3841
+ "genesis_hash": genesis_hash,
3842
+ "account": account_bytes,
3843
+ "node_id_hash": node_id_hash,
3844
+ "ipfs_peer_id_hash": ipfs_peer_id_hash,
3845
+ "block_number": current_block_number,
3846
+ "nonce": nonce,
3847
+ "expires_at": expires_at_block,
3848
+ }
3849
+
3850
+ challenge_bytes = manual_encode_challenge(challenge_data, block_width)
3851
+
3852
+ # Sign challenge
3853
+ main_sig = main_sk.sign(challenge_bytes).signature
3854
+ ipfs_sig = ipfs_sk.sign(challenge_bytes).signature
3855
+
3856
+ # Build call parameters for verify_existing_node
3857
+ call_params = {
3858
+ "node_id": node_id,
3859
+ "node_id_hex": "0x" + hexlify(node_id_bytes).decode(),
3860
+ "ipfs_id_hex": "0x" + hexlify(ipfs_peer_id_bytes).decode(),
3861
+ "main_key_type": "Ed25519",
3862
+ "main_public_key": "0x" + main_pk.hex(),
3863
+ "main_sig": "0x" + main_sig.hex(),
3864
+ "ipfs_key_type": "Ed25519",
3865
+ "ipfs_public_key": "0x" + ipfs_pk.hex(),
3866
+ "ipfs_sig": "0x" + ipfs_sig.hex(),
3867
+ "challenge_bytes": "0x" + challenge_bytes.hex(),
3868
+ }
3869
+
3870
+ if dry_run:
3871
+ log("Dry run mode - printing payload without submitting")
3872
+ payload = {
3873
+ "genesis_hash_hex": "0x" + genesis_hash.hex(),
3874
+ "current_block_number": current_block_number,
3875
+ "challenge_bytes_hex": "0x" + challenge_bytes.hex(),
3876
+ "call_module": "Registration",
3877
+ "call_function": "verify_existing_node",
3878
+ "call_params": call_params,
3879
+ }
3880
+ console.print(json.dumps(payload, indent=2))
3881
+ return 0
3882
+
3883
+ # Get keypair for signing
3884
+ from hippius_sdk.config import get_seed_phrase
3885
+
3886
+ seed_phrase = get_seed_phrase()
3887
+ if not seed_phrase:
3888
+ error("No seed phrase available for signing transaction")
3889
+ return 1
3890
+
3891
+ kp = Keypair.create_from_uri(seed_phrase)
3892
+
3893
+ # Submit transaction
3894
+ log("Submitting node verification transaction...")
3895
+ log(f"Using module: [bold cyan]Registration[/bold cyan]")
3896
+ call = substrate.compose_call(
3897
+ call_module="Registration",
3898
+ call_function="verify_existing_node",
3899
+ call_params=call_params,
3900
+ )
3901
+ extrinsic = substrate.create_signed_extrinsic(call=call, keypair=kp)
3902
+ receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)
3903
+
3904
+ result = {
3905
+ "extrinsic_hash": receipt.extrinsic_hash,
3906
+ "is_success": receipt.is_success,
3907
+ "error_message": receipt.error_message,
3908
+ "triggered_events": [str(event) for event in receipt.triggered_events],
3909
+ }
3910
+
3911
+ if receipt.is_success:
3912
+ success(f"Node verification successful!")
3913
+ success(f"Transaction hash: {receipt.extrinsic_hash}")
3914
+ else:
3915
+ error(f"Node verification failed: {receipt.error_message}")
3916
+
3917
+ log("Full result:")
3918
+ console.print(json.dumps(result, indent=2))
3919
+
3920
+ return 0 if receipt.is_success else 1
3921
+
3922
+ except Exception as e:
3923
+ error(f"Error verifying node: {e}")
3924
+ if hasattr(e, "__traceback__"):
3925
+ import traceback
3926
+
3927
+ traceback.print_exc()
3928
+ return 1
3929
+
3930
+
3931
+ def handle_verify_coldkey_node(
3932
+ client: HippiusClient,
3933
+ node_id: str,
3934
+ node_priv_hex: str,
3935
+ ipfs_config: str = None,
3936
+ ipfs_priv_b64: str = None,
3937
+ ipfs_peer_id: str = None,
3938
+ expires_in: int = 10,
3939
+ block_width: str = "u32",
3940
+ domain: str = "HIPPIUS::REGISTER::v1",
3941
+ nonce_hex: str = None,
3942
+ dry_run: bool = False,
3943
+ ) -> int:
3944
+ """Handle miner verify-coldkey-node command"""
3945
+ try:
3946
+ # Get current account info
3947
+ account = get_active_account()
3948
+ if not account:
3949
+ error(
3950
+ "No active account. Please set up an account first with 'hippius account create' or 'hippius seed set'"
3951
+ )
3952
+ return 1
3953
+
3954
+ account_address = get_account_address(account)
3955
+ if not account_address:
3956
+ error(f"Could not get address for account '{account}'")
3957
+ return 1
3958
+
3959
+ info(
3960
+ f"Verifying existing coldkey node using account: [bold cyan]{account}[/bold cyan] ({account_address})"
3961
+ )
3962
+
3963
+ # Import and use incentives.py functionality
3964
+ from hippius_sdk.incentives import (
3965
+ load_ipfs_seed,
3966
+ load_main_seed,
3967
+ encode_account_id,
3968
+ verify_peer_id,
3969
+ blake2_256,
3970
+ manual_encode_challenge,
3971
+ )
3972
+ from substrateinterface import SubstrateInterface, Keypair
3973
+ from nacl.signing import SigningKey
3974
+ import base58
3975
+ import secrets
3976
+ from binascii import hexlify
3977
+
3978
+ # Initialize SubstrateInterface
3979
+ substrate = SubstrateInterface(url=client.substrate_client.url)
3980
+
3981
+ # Get genesis hash and current block
3982
+ genesis_hash_hex = substrate.get_block_hash(0)
3983
+ genesis_hash = bytes.fromhex(genesis_hash_hex[2:])
3984
+ current_block_number = substrate.get_block_number(None)
3985
+
3986
+ log(f"Current block number: {current_block_number}")
3987
+
3988
+ # Process node_id
3989
+ if node_id.startswith("0x"):
3990
+ node_id_bytes = bytes.fromhex(node_id[2:])
3991
+ else:
3992
+ node_id_bytes = base58.b58decode(node_id)
3993
+
3994
+ # Load IPFS and main seeds
3995
+ ipfs_seed, peerid_from_config = load_ipfs_seed(ipfs_config, ipfs_priv_b64)
3996
+ main_seed = load_main_seed(node_priv_hex)
3997
+
3998
+ # Create signing keys
3999
+ main_sk = SigningKey(main_seed)
4000
+ main_pk = bytes(main_sk.verify_key)
4001
+ ipfs_sk = SigningKey(ipfs_seed)
4002
+ ipfs_pk = bytes(ipfs_sk.verify_key)
4003
+
4004
+ # Handle IPFS peer ID
4005
+ if ipfs_peer_id:
4006
+ ipfs_peer_id_bytes = base58.b58decode(ipfs_peer_id)
4007
+ elif peerid_from_config:
4008
+ ipfs_peer_id_bytes = base58.b58decode(peerid_from_config)
4009
+ else:
4010
+ # For verification, IPFS peer ID might not be required for all node types
4011
+ ipfs_peer_id_bytes = b""
4012
+
4013
+ # Verify keys match node IDs
4014
+ if not verify_peer_id(main_pk, node_id_bytes, "Ed25519"):
4015
+ error("Main public key does not match node ID")
4016
+ return 1
4017
+
4018
+ if ipfs_peer_id_bytes and not verify_peer_id(
4019
+ ipfs_pk, ipfs_peer_id_bytes, "Ed25519"
4020
+ ):
4021
+ error("IPFS public key does not match peer ID")
4022
+ return 1
4023
+
4024
+ # Create challenge data
4025
+ domain_bytes = domain.encode()
4026
+ domain24 = b"HIPPIUS::REGISTER::v1" + b"\x00" * 3
4027
+ node_id_hash = blake2_256(node_id_bytes)
4028
+ ipfs_peer_id_hash = blake2_256(ipfs_peer_id_bytes)
4029
+
4030
+ nonce = (
4031
+ bytes.fromhex(nonce_hex[2:])
4032
+ if nonce_hex and nonce_hex.startswith("0x")
4033
+ else bytes.fromhex(nonce_hex)
4034
+ if nonce_hex
4035
+ else secrets.token_bytes(32)
4036
+ )
4037
+
4038
+ expires_at_block = current_block_number + expires_in
4039
+ account_bytes = encode_account_id(account_address)
4040
+
4041
+ challenge_data = {
4042
+ "domain": domain24,
4043
+ "genesis_hash": genesis_hash,
4044
+ "account": account_bytes,
4045
+ "node_id_hash": node_id_hash,
4046
+ "ipfs_peer_id_hash": ipfs_peer_id_hash,
4047
+ "block_number": current_block_number,
4048
+ "nonce": nonce,
4049
+ "expires_at": expires_at_block,
4050
+ }
4051
+
4052
+ challenge_bytes = manual_encode_challenge(challenge_data, block_width)
4053
+
4054
+ # Sign challenge
4055
+ main_sig = main_sk.sign(challenge_bytes).signature
4056
+ ipfs_sig = ipfs_sk.sign(challenge_bytes).signature
4057
+
4058
+ # Build call parameters for verify_existing_coldkey_node
4059
+ call_params = {
4060
+ "node_id": node_id,
4061
+ "node_id_hex": "0x" + hexlify(node_id_bytes).decode(),
4062
+ "ipfs_id_hex": "0x" + hexlify(ipfs_peer_id_bytes).decode(),
4063
+ "main_key_type": "Ed25519",
4064
+ "main_public_key": "0x" + main_pk.hex(),
4065
+ "main_sig": "0x" + main_sig.hex(),
4066
+ "ipfs_key_type": "Ed25519",
4067
+ "ipfs_public_key": "0x" + ipfs_pk.hex(),
4068
+ "ipfs_sig": "0x" + ipfs_sig.hex(),
4069
+ "challenge_bytes": "0x" + challenge_bytes.hex(),
4070
+ }
4071
+
4072
+ if dry_run:
4073
+ log("Dry run mode - printing payload without submitting")
4074
+ payload = {
4075
+ "genesis_hash_hex": "0x" + genesis_hash.hex(),
4076
+ "current_block_number": current_block_number,
4077
+ "challenge_bytes_hex": "0x" + challenge_bytes.hex(),
4078
+ "call_module": "Registration",
4079
+ "call_function": "verify_existing_coldkey_node",
4080
+ "call_params": call_params,
4081
+ }
4082
+ console.print(json.dumps(payload, indent=2))
4083
+ return 0
4084
+
4085
+ # Get keypair for signing
4086
+ from hippius_sdk.config import get_seed_phrase
4087
+
4088
+ seed_phrase = get_seed_phrase()
4089
+ if not seed_phrase:
4090
+ error("No seed phrase available for signing transaction")
4091
+ return 1
4092
+
4093
+ kp = Keypair.create_from_uri(seed_phrase)
4094
+
4095
+ # Submit transaction
4096
+ log("Submitting coldkey node verification transaction...")
4097
+ log(f"Using module: [bold cyan]Registration[/bold cyan]")
4098
+ call = substrate.compose_call(
4099
+ call_module="Registration",
4100
+ call_function="verify_existing_coldkey_node",
4101
+ call_params=call_params,
4102
+ )
4103
+ extrinsic = substrate.create_signed_extrinsic(call=call, keypair=kp)
4104
+ receipt = substrate.submit_extrinsic(extrinsic, wait_for_inclusion=True)
4105
+
4106
+ result = {
4107
+ "extrinsic_hash": receipt.extrinsic_hash,
4108
+ "is_success": receipt.is_success,
4109
+ "error_message": receipt.error_message,
4110
+ "triggered_events": [str(event) for event in receipt.triggered_events],
4111
+ }
4112
+
4113
+ if receipt.is_success:
4114
+ success(f"Coldkey node verification successful!")
4115
+ success(f"Transaction hash: {receipt.extrinsic_hash}")
4116
+ else:
4117
+ error(f"Coldkey node verification failed: {receipt.error_message}")
4118
+
4119
+ log("Full result:")
4120
+ console.print(json.dumps(result, indent=2))
4121
+
4122
+ return 0 if receipt.is_success else 1
4123
+
4124
+ except Exception as e:
4125
+ error(f"Error verifying coldkey node: {e}")
4126
+ if hasattr(e, "__traceback__"):
4127
+ import traceback
4128
+
4129
+ traceback.print_exc()
4130
+ return 1
@@ -800,6 +800,129 @@ def add_miner_commands(subparsers):
800
800
  help="Do not submit extrinsic; just print payload",
801
801
  )
802
802
 
803
+ # Verify node command
804
+ verify_node_parser = miner_subparsers.add_parser(
805
+ "verify-node", help="Verify an existing registered node (proves key ownership)"
806
+ )
807
+
808
+ # Required arguments for verify-node
809
+ verify_node_parser.add_argument(
810
+ "--node-id", required=True, help="Your main node_id (libp2p peer ID)"
811
+ )
812
+ verify_node_parser.add_argument(
813
+ "--node-priv-hex",
814
+ required=True,
815
+ help="Main libp2p ed25519 private key hex (32/64B)",
816
+ )
817
+
818
+ # IPFS configuration (one required)
819
+ ipfs_group_verify = verify_node_parser.add_mutually_exclusive_group(required=True)
820
+ ipfs_group_verify.add_argument(
821
+ "--ipfs-config", help="Path to IPFS config file (e.g. ~/.ipfs/config)"
822
+ )
823
+ ipfs_group_verify.add_argument(
824
+ "--ipfs-priv-b64",
825
+ help="IPFS Identity.PrivKey base64 if not using --ipfs-config",
826
+ )
827
+
828
+ # Optional arguments
829
+ verify_node_parser.add_argument(
830
+ "--ipfs-peer-id", help="Optional override IPFS PeerID"
831
+ )
832
+ verify_node_parser.add_argument(
833
+ "--expires-in",
834
+ type=int,
835
+ default=10,
836
+ help="Challenge expiration in blocks (default: 10)",
837
+ )
838
+ verify_node_parser.add_argument(
839
+ "--block-width",
840
+ choices=["u32", "u64"],
841
+ default="u32",
842
+ help="Block number width (default: u32)",
843
+ )
844
+ verify_node_parser.add_argument(
845
+ "--domain",
846
+ default="HIPPIUS::REGISTER::v1",
847
+ help="Domain for challenge (default: HIPPIUS::REGISTER::v1)",
848
+ )
849
+ verify_node_parser.add_argument(
850
+ "--nonce-hex", help="32-byte hex nonce (optional, random if not provided)"
851
+ )
852
+ verify_node_parser.add_argument(
853
+ "--module",
854
+ default="Registration",
855
+ help="Blockchain pallet/module name (default: Registration)",
856
+ )
857
+ verify_node_parser.add_argument(
858
+ "--dry-run",
859
+ action="store_true",
860
+ help="Do not submit extrinsic; just print payload",
861
+ )
862
+
863
+ # Verify coldkey node command
864
+ verify_coldkey_node_parser = miner_subparsers.add_parser(
865
+ "verify-coldkey-node",
866
+ help="Verify an existing coldkey-registered node (proves key ownership)",
867
+ )
868
+
869
+ # Required arguments for verify-coldkey-node
870
+ verify_coldkey_node_parser.add_argument(
871
+ "--node-id", required=True, help="Your main node_id (libp2p peer ID)"
872
+ )
873
+ verify_coldkey_node_parser.add_argument(
874
+ "--node-priv-hex",
875
+ required=True,
876
+ help="Main libp2p ed25519 private key hex (32/64B)",
877
+ )
878
+
879
+ # IPFS configuration (one required)
880
+ ipfs_group_verify_coldkey = verify_coldkey_node_parser.add_mutually_exclusive_group(
881
+ required=True
882
+ )
883
+ ipfs_group_verify_coldkey.add_argument(
884
+ "--ipfs-config", help="Path to IPFS config file (e.g. ~/.ipfs/config)"
885
+ )
886
+ ipfs_group_verify_coldkey.add_argument(
887
+ "--ipfs-priv-b64",
888
+ help="IPFS Identity.PrivKey base64 if not using --ipfs-config",
889
+ )
890
+
891
+ # Optional arguments
892
+ verify_coldkey_node_parser.add_argument(
893
+ "--ipfs-peer-id", help="Optional override IPFS PeerID"
894
+ )
895
+ verify_coldkey_node_parser.add_argument(
896
+ "--expires-in",
897
+ type=int,
898
+ default=10,
899
+ help="Challenge expiration in blocks (default: 10)",
900
+ )
901
+ verify_coldkey_node_parser.add_argument(
902
+ "--block-width",
903
+ choices=["u32", "u64"],
904
+ default="u32",
905
+ help="Block number width (default: u32)",
906
+ )
907
+ verify_coldkey_node_parser.add_argument(
908
+ "--domain",
909
+ default="HIPPIUS::REGISTER::v1",
910
+ help="Domain for challenge (default: HIPPIUS::REGISTER::v1)",
911
+ )
912
+ verify_coldkey_node_parser.add_argument(
913
+ "--nonce-hex", help="32-byte hex nonce (optional, random if not provided)"
914
+ )
915
+ verify_coldkey_node_parser.add_argument(
916
+ "--module",
917
+ default="Registration",
918
+ help="Blockchain pallet/module name (default: Registration)",
919
+ )
920
+ verify_coldkey_node_parser.add_argument(
921
+ "--dry-run",
922
+ action="store_true",
923
+ help="Do not submit extrinsic; just print payload",
924
+ )
925
+
803
926
 
804
927
  def get_subparser(command: str) -> argparse.ArgumentParser:
805
928
  """Get a subparser for a specific command.
@@ -2294,9 +2294,6 @@ class IPFSClient:
2294
2294
  encrypted_data += chunk
2295
2295
  return encrypted_data
2296
2296
 
2297
- # Stream and decrypt the content using hybrid buffered approach
2298
- import nacl.secret
2299
-
2300
2297
  # Collect all encrypted data first
2301
2298
  logger.debug("Buffering encrypted content for decryption")
2302
2299
  encrypted_data = b""
@@ -2344,16 +2341,16 @@ class IPFSClient:
2344
2341
  os.path.dirname(os.path.abspath(output_path)), exist_ok=True
2345
2342
  )
2346
2343
 
2347
- download_client = AsyncIPFSClient(api_url=download_node)
2348
-
2349
- download_url = f"{download_node.rstrip('/')}/api/v0/cat?arg={cid}"
2344
+ # Use gateway style instead of cat API for better HTTP semantics
2345
+ download_url = f"{download_node.rstrip('/')}/ipfs/{cid}"
2350
2346
 
2351
2347
  # Download file into memory
2352
2348
  file_data = bytearray()
2353
- async with download_client.client.stream("POST", download_url) as response:
2354
- response.raise_for_status()
2355
- async for chunk in response.aiter_bytes(chunk_size=8192):
2356
- file_data.extend(chunk)
2349
+ async with httpx.AsyncClient() as client:
2350
+ async with client.stream("GET", download_url) as response:
2351
+ response.raise_for_status()
2352
+ async for chunk in response.aiter_bytes(chunk_size=8192):
2353
+ file_data.extend(chunk)
2357
2354
 
2358
2355
  # Convert to bytes for consistency
2359
2356
  file_data = bytes(file_data)
@@ -2523,15 +2520,16 @@ class IPFSClient:
2523
2520
  HippiusIPFSError: If IPFS stream fails
2524
2521
  """
2525
2522
  try:
2526
- download_client = AsyncIPFSClient(api_url=download_node)
2527
- download_url = f"{download_node.rstrip('/')}/api/v0/cat?arg={cid}"
2523
+ # Use gateway style instead of cat API for better HTTP semantics
2524
+ download_url = f"{download_node.rstrip('/')}/ipfs/{cid}"
2528
2525
 
2529
- async with download_client.client.stream("POST", download_url) as response:
2530
- response.raise_for_status()
2531
- logger.info(f"Started streaming from {download_node} for CID: {cid}")
2526
+ async with httpx.AsyncClient() as client:
2527
+ async with client.stream("GET", download_url) as response:
2528
+ response.raise_for_status()
2529
+ logger.info(f"Started streaming from {download_node} for CID: {cid}")
2532
2530
 
2533
- async for chunk in response.aiter_bytes(chunk_size=8192):
2534
- yield chunk
2531
+ async for chunk in response.aiter_bytes(chunk_size=8192):
2532
+ yield chunk
2535
2533
 
2536
2534
  except Exception as e:
2537
2535
  raise HippiusIPFSError(f"Failed to stream from {download_node}: {str(e)}")
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "hippius"
3
- version = "0.2.50"
3
+ version = "0.2.52"
4
4
  description = "Python SDK and CLI for Hippius blockchain storage"
5
5
  authors = ["Dubs <dubs@dubs.rs>"]
6
6
  readme = "README.md"
File without changes
File without changes
File without changes
File without changes
File without changes