Skip to content

Commit 53a28d7

Browse files
authored
Merge pull request #513 from singnet/development
Added FileCoin storage provider for services metadata and files
2 parents 3d6be71 + e8f3f59 commit 53a28d7

11 files changed

Lines changed: 348 additions & 148 deletions

File tree

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ eth-account==0.9.0
2020
trezor==0.13.8
2121
ledgerblue==0.1.48
2222
snet.contracts==0.1.1
23+
lighthouseweb3==0.1.4

snet/cli/arguments.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import os
33
import re
44
import sys
5+
from email.policy import default
6+
from random import choices
57

68
from snet.contracts import get_all_abi_contract_files, get_contract_def
79

@@ -258,6 +260,15 @@ def add_metadatafile_argument_for_org(p):
258260
help="Service metadata json file (default organization_metadata.json)")
259261

260262

263+
def add_p_storage_param(_p):
264+
_p.add_argument(
265+
"--storage",
266+
default="ipfs",
267+
choices=['ipfs', 'filecoin'],
268+
help="Choose storage for uploading metadata/protobuf file (defaults to 'ipfs')",
269+
)
270+
271+
261272
def add_organization_options(parser):
262273
parser.set_defaults(cmd=OrganizationCommand)
263274

@@ -390,8 +401,9 @@ def add_organization_options(parser):
390401
add_metadatafile_argument_for_org(p)
391402
p.add_argument("--members", help="List of members to be added to the organization", metavar="ORG_MEMBERS[]")
392403
add_organization_arguments(p)
404+
add_p_storage_param(p)
393405

394-
p = subparsers.add_parser("update-metadata", help="Create an Organization")
406+
p = subparsers.add_parser("update-metadata", help="Update metadata for an Organization")
395407
p.add_argument("org_id", help="Unique Organization Id", metavar="ORG_ID")
396408
p.set_defaults(fn="update_metadata")
397409
add_metadatafile_argument_for_org(p)
@@ -400,6 +412,7 @@ def add_organization_options(parser):
400412
help="List of members to be added to the organization",
401413
metavar="ORG_MEMBERS[]")
402414
add_organization_arguments(p)
415+
add_p_storage_param(p)
403416

404417
p = subparsers.add_parser("change-owner", help="Change Organization's owner")
405418
p.set_defaults(fn="change_owner")
@@ -936,7 +949,7 @@ def add_mpe_service_options(parser):
936949
add_p_metadata_file_opt(p)
937950

938951
p = subparsers.add_parser("metadata-init",
939-
help="Init metadata file with providing protobuf directory (which we publish in IPFS) and display_name (optionally encoding, service_type and payment_expiration_threshold)")
952+
help="Init metadata file with providing protobuf directory (which we publish in IPFS or FileCoin) and display_name (optionally encoding, service_type and payment_expiration_threshold)")
940953
p.set_defaults(fn="publish_proto_metadata_init")
941954
p.add_argument("protodir",
942955
help="Directory which contains protobuf files",
@@ -965,14 +978,16 @@ def add_mpe_service_options(parser):
965978
default="grpc",
966979
choices=['grpc', 'http', 'jsonrpc', 'process'],
967980
help="Service type")
981+
add_p_storage_param(p)
968982

969-
p = subparsers.add_parser("metadata-set-model",
970-
help="Publish protobuf model in ipfs and update existed metadata file")
983+
p = subparsers.add_parser("metadata-set-api",
984+
help="Publish protobuf model in ipfs or filecoin and update existed metadata file")
971985
p.set_defaults(fn="publish_proto_metadata_update")
972986
p.add_argument("protodir",
973987
help="Directory which contains protobuf files",
974988
metavar="PROTO_DIR")
975989
add_p_metadata_file_opt(p)
990+
add_p_storage_param(p)
976991

977992
p = subparsers.add_parser("metadata-set-fixed-price",
978993
help="Set pricing model as fixed price for all methods")
@@ -1199,6 +1214,7 @@ def add_p_publish_params(_p):
11991214
_p.add_argument("--update-mpe-address",
12001215
action='store_true',
12011216
help="Update mpe_address in metadata before publishing them")
1217+
add_p_storage_param(p)
12021218
add_p_mpe_address_opt(_p)
12031219

12041220
p = subparsers.add_parser("publish",
@@ -1214,9 +1230,15 @@ def add_p_publish_params(_p):
12141230
add_p_publish_params(p)
12151231
add_transaction_arguments(p)
12161232

1233+
p = subparsers.add_parser("publish-in-filecoin",
1234+
help="Publish metadata only in FileCoin, without publishing in Registry")
1235+
p.set_defaults(fn="publish_metadata_in_filecoin")
1236+
add_p_publish_params(p)
1237+
add_transaction_arguments(p)
1238+
12171239
p = subparsers.add_parser("update-metadata",
1218-
help="Publish metadata in IPFS and update existed service")
1219-
p.set_defaults(fn="publish_metadata_in_ipfs_and_update_registration")
1240+
help="Publish metadata in IPFS or FileCoin and update existed service")
1241+
p.set_defaults(fn="publish_metadata_in_storage_and_update_registration")
12201242
add_p_publish_params(p)
12211243
add_p_service_in_registry(p)
12221244
add_transaction_arguments(p)
@@ -1286,7 +1308,7 @@ def add_p_protodir_to_extract(_p):
12861308
metavar="PROTO_DIR")
12871309

12881310
p = subparsers.add_parser("get-api-metadata",
1289-
help="Extract service api (model) to the given protodir. Get model_ipfs_hash from metadata")
1311+
help="Extract service api (model) to the given protodir. Get existed metadata")
12901312
p.set_defaults(fn="extract_service_api_from_metadata")
12911313
add_p_protodir_to_extract(p)
12921314
add_p_metadata_file_opt(p)

snet/cli/commands/commands.py

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from urllib.parse import urljoin
88

99
import ipfshttpclient
10+
from lighthouseweb3 import Lighthouse
1011
import yaml
1112
from rfc3986 import urlparse
1213
import web3
@@ -18,10 +19,10 @@
1819
from snet.cli.metadata.organization import OrganizationMetadata, PaymentStorageClient, Payment, Group
1920
from snet.cli.utils.config import get_contract_address, get_field_from_args_or_session, \
2021
read_default_contract_address
21-
from snet.cli.utils.ipfs_utils import bytesuri_to_hash, get_from_ipfs_and_checkhash, \
22-
hash_to_bytesuri, publish_file_in_ipfs
22+
from snet.cli.utils.ipfs_utils import get_from_ipfs_and_checkhash, \
23+
hash_to_bytesuri, publish_file_in_ipfs, publish_file_in_filecoin
2324
from snet.cli.utils.utils import DefaultAttributeObject, get_web3, is_valid_url, serializable, type_converter, \
24-
get_cli_version, bytes32_to_str
25+
get_cli_version, bytes32_to_str, bytesuri_to_hash, get_file_from_filecoin
2526

2627

2728
class Command(object):
@@ -79,6 +80,10 @@ def _get_ipfs_client(self):
7980
ipfs_endpoint = self.config.get_ipfs_endpoint()
8081
return ipfshttpclient.connect(ipfs_endpoint)
8182

83+
def _get_filecoin_client(self):
84+
lighthouse_token = self.config.get_filecoin_key()
85+
return Lighthouse(token=lighthouse_token)
86+
8287

8388
class VersionCommand(Command):
8489
def show(self):
@@ -489,9 +494,11 @@ def _get_organization_registration(self, org_id):
489494

490495
def _get_organization_metadata_from_registry(self, org_id):
491496
rez = self._get_organization_registration(org_id)
492-
metadata_hash = bytesuri_to_hash(rez["orgMetadataURI"])
493-
metadata = get_from_ipfs_and_checkhash(
494-
self._get_ipfs_client(), metadata_hash)
497+
storage_type, metadata_hash = bytesuri_to_hash(rez["orgMetadataURI"])
498+
if storage_type == "ipfs":
499+
metadata = get_from_ipfs_and_checkhash(self._get_ipfs_client(), metadata_hash)
500+
else:
501+
metadata = get_file_from_filecoin(metadata_hash)
495502
metadata = metadata.decode("utf-8")
496503
return OrganizationMetadata.from_json(json.loads(metadata))
497504

@@ -589,10 +596,17 @@ def create(self):
589596

590597
members = self.get_members_from_args()
591598

592-
ipfs_metadata_uri = publish_file_in_ipfs(
593-
self._get_ipfs_client(), metadata_file, False)
594-
params = [type_converter("bytes32")(
595-
org_id), hash_to_bytesuri(ipfs_metadata_uri), members]
599+
storage = self.args.storage
600+
if not storage or storage == "ipfs":
601+
metadata_uri = publish_file_in_ipfs(self._get_ipfs_client(), metadata_file, False)
602+
elif storage == "filecoin":
603+
# upload to Filecoin via Lighthouse SDK
604+
metadata_uri = publish_file_in_filecoin(self._get_filecoin_client(), metadata_file)
605+
else:
606+
raise ValueError(f"Unsupported storage option: {storage}. Use --storage <ipfs or filecoin>")
607+
608+
params = [type_converter("bytes32")(org_id),
609+
hash_to_bytesuri(metadata_uri, storage), members]
596610
self._printout("Creating transaction to create organization name={} id={}\n".format(
597611
org_metadata.org_name, org_id))
598612
self.transact_contract_command(
@@ -622,31 +636,34 @@ def update_metadata(self):
622636
with open(metadata_file, 'r') as f:
623637
org_metadata = OrganizationMetadata.from_json(json.load(f))
624638
except Exception as e:
625-
print(
626-
"Organization metadata json file not found ,Please check --metadata-file path ")
639+
print("Organization metadata JSON file not found. Please check --metadata-file path.")
627640
raise e
628-
# validate the metadata before updating
629641

642+
# Validate the metadata before updating
630643
org_id = self.args.org_id
631-
existing_registry_org_metadata = self._get_organization_metadata_from_registry(
632-
org_id)
644+
existing_registry_org_metadata = self._get_organization_metadata_from_registry(org_id)
633645
org_metadata.validate(existing_registry_org_metadata)
634646

635647
# Check if Organization already exists
636648
found = self._get_organization_by_id(org_id)[0]
637649
if not found:
638-
raise Exception(
639-
"\nOrganization with id={} does not exists!\n".format(org_id))
650+
raise Exception("\nOrganization with id={} does not exist!\n".format(org_id))
651+
652+
storage = self.args.storage
653+
if not storage or storage == "ipfs":
654+
metadata_uri = publish_file_in_ipfs(self._get_ipfs_client(), metadata_file, False)
655+
elif storage == "filecoin":
656+
# upload to Filecoin via Lighthouse SDK
657+
metadata_uri = publish_file_in_filecoin(self._get_filecoin_client(), metadata_file)
658+
else:
659+
raise ValueError(f"Unsupported storage option: {storage}. Use --storage <ipfs or filecoin>")
640660

641-
ipfs_metadata_uri = publish_file_in_ipfs(
642-
self._get_ipfs_client(), metadata_file, False)
643-
params = [type_converter("bytes32")(
644-
org_id), hash_to_bytesuri(ipfs_metadata_uri)]
661+
params = [type_converter("bytes32")(org_id), hash_to_bytesuri(metadata_uri, storage)]
645662
self._printout(
646-
"Creating transaction to create organization name={} id={}\n".format(org_metadata.org_name, org_id))
647-
self.transact_contract_command(
648-
"Registry", "changeOrganizationMetadataURI", params)
649-
self._printout("id:\n%s" % org_id)
663+
"Creating transaction to update organization metadata for org name={} id={}\n".format(org_metadata.org_name,
664+
org_id))
665+
self.transact_contract_command("Registry", "changeOrganizationMetadataURI", params)
666+
self._printout("Organization updated successfully with id:\n%s" % org_id)
650667

651668
def list_services(self):
652669
org_id = self.args.org_id

snet/cli/commands/mpe_channel.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import shutil
55
import tempfile
66
from collections import defaultdict
7+
from importlib.metadata import metadata
78
from pathlib import Path
89

910
from eth_abi.codec import ABICodec
@@ -15,9 +16,9 @@
1516
from snet.cli.metadata.service import mpe_service_metadata_from_json, load_mpe_service_metadata
1617
from snet.cli.metadata.organization import OrganizationMetadata
1718
from snet.cli.utils.agix2cogs import cogs2stragix
18-
from snet.cli.utils.ipfs_utils import bytesuri_to_hash, get_from_ipfs_and_checkhash, safe_extract_proto_from_ipfs
19+
from snet.cli.utils.ipfs_utils import get_from_ipfs_and_checkhash
1920
from snet.cli.utils.utils import abi_decode_struct_to_dict, abi_get_element_by_name, \
20-
compile_proto, type_converter
21+
compile_proto, type_converter, bytesuri_to_hash, get_file_from_filecoin, download_and_safe_extract_proto
2122

2223

2324
# we inherit MPEServiceCommand because we need _get_service_metadata_from_registry
@@ -577,12 +578,14 @@ def _get_service_registration(self):
577578

578579
def _get_service_metadata_from_registry(self):
579580
response = self._get_service_registration()
580-
metadata_hash = bytesuri_to_hash(response["metadataURI"])
581-
metadata = get_from_ipfs_and_checkhash(
582-
self._get_ipfs_client(), metadata_hash)
583-
metadata = metadata.decode("utf-8")
584-
metadata = mpe_service_metadata_from_json(metadata)
585-
return metadata
581+
storage_type, metadata_hash = bytesuri_to_hash(response["metadataURI"])
582+
if storage_type == "ipfs":
583+
service_metadata = get_from_ipfs_and_checkhash(self._get_ipfs_client(), metadata_hash)
584+
else:
585+
service_metadata = get_file_from_filecoin(metadata_hash)
586+
service_metadata = service_metadata.decode("utf-8")
587+
service_metadata = mpe_service_metadata_from_json(service_metadata)
588+
return service_metadata
586589

587590
def _init_or_update_service_if_needed(self, metadata, service_registration):
588591
# if service was already initialized and metadataURI hasn't changed we do nothing
@@ -609,8 +612,8 @@ def _init_or_update_service_if_needed(self, metadata, service_registration):
609612
try:
610613
spec_dir = os.path.join(service_dir, "service_spec")
611614
os.makedirs(spec_dir, mode=0o700)
612-
safe_extract_proto_from_ipfs(
613-
self._get_ipfs_client(), metadata["model_ipfs_hash"], spec_dir)
615+
service_api_source = metadata.get("service_api_source") or metadata.get("model_ipfs_hash")
616+
download_and_safe_extract_proto(service_api_source, spec_dir, self._get_ipfs_client())
614617

615618
# compile .proto files
616619
if not compile_proto(Path(spec_dir), service_dir):

0 commit comments

Comments
 (0)