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.
- {hippius-0.2.50 → hippius-0.2.52}/PKG-INFO +1 -1
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/__init__.py +1 -1
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli.py +30 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli_handlers.py +408 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli_parser.py +123 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/ipfs.py +15 -17
- {hippius-0.2.50 → hippius-0.2.52}/pyproject.toml +1 -1
- {hippius-0.2.50 → hippius-0.2.52}/README.md +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli_assets.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/cli_rich.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/client.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/config.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/README.md +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/env.db.template +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/migrations/20241201000001_create_key_storage_tables.sql +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/migrations/20241202000001_switch_to_subaccount_encryption.sql +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db/setup_database.sh +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/db_utils.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/errors.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/incentives.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/ipfs_core.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/key_storage.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/substrate.py +0 -0
- {hippius-0.2.50 → hippius-0.2.52}/hippius_sdk/utils.py +0 -0
@@ -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.
|
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
|
-
|
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
|
2354
|
-
|
2355
|
-
|
2356
|
-
|
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
|
-
|
2527
|
-
download_url = f"{download_node.rstrip('/')}/
|
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
|
2530
|
-
|
2531
|
-
|
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
|
-
|
2534
|
-
|
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)}")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|