feat: add interactive deployment and switch to poetry #2
@ -4,17 +4,19 @@ import logging
|
|||||||
import os
|
import os
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
# local imports
|
|
||||||
from cic import ContractProcessor, Proof
|
|
||||||
from cic.attachment import Attachment
|
|
||||||
from cic.meta import Meta, MetadataWriter
|
|
||||||
from cic.network import Network
|
|
||||||
from cic.writers import HTTPWriter, KeyedWriterFactory
|
|
||||||
from cic.token import Token
|
|
||||||
# external imports
|
# external imports
|
||||||
from cic_types.ext.metadata import MetadataRequestsHandler
|
from cic_types.ext.metadata import MetadataRequestsHandler
|
||||||
from cic_types.ext.metadata.signer import Signer as MetadataSigner
|
from cic_types.ext.metadata.signer import Signer as MetadataSigner
|
||||||
|
|
||||||
|
# local imports
|
||||||
|
from cic.contract.processor import ContractProcessor
|
||||||
|
from cic.contract.components.proof import Proof
|
||||||
|
from cic.contract.components.attachment import Attachment
|
||||||
|
from cic.contract.components.meta import Meta
|
||||||
|
from cic.contract.components.network import Network
|
||||||
|
from cic.contract.components.token import Token
|
||||||
|
from cic.writers import HTTPWriter, KeyedWriterFactory, MetadataWriter
|
||||||
|
|
||||||
logg = logging.getLogger(__name__)
|
logg = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import importlib
|
|||||||
# external imports
|
# external imports
|
||||||
from chainlib.chain import ChainSpec
|
from chainlib.chain import ChainSpec
|
||||||
# local imports
|
# local imports
|
||||||
from cic.network import Network
|
from cic.contract.components.network import Network
|
||||||
|
|
||||||
|
|
||||||
def process_args(argparser):
|
def process_args(argparser):
|
||||||
|
@ -3,11 +3,11 @@ import logging
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from cic import Proof
|
from cic.contract.components.proof import Proof
|
||||||
from cic.meta import Meta
|
from cic.contract.components.meta import Meta
|
||||||
from cic.attachment import Attachment
|
from cic.contract.components.attachment import Attachment
|
||||||
from cic.network import Network
|
from cic.contract.components.network import Network
|
||||||
from cic.token import Token
|
from cic.contract.components.token import Token
|
||||||
|
|
||||||
logg = logging.getLogger(__name__)
|
logg = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# local imports
|
# local imports
|
||||||
from cic import Proof
|
from cic.contract.components.proof import Proof
|
||||||
from cic.meta import Meta
|
from cic.contract.components.meta import Meta
|
||||||
from cic.attachment import Attachment
|
from cic.contract.components.attachment import Attachment
|
||||||
from cic.network import Network
|
from cic.contract.components.network import Network
|
||||||
from cic.token import Token
|
from cic.contract.components.token import Token
|
||||||
|
|
||||||
|
|
||||||
def process_args(argparser):
|
def process_args(argparser):
|
||||||
|
@ -13,13 +13,12 @@ import requests
|
|||||||
from chainlib.chain import ChainSpec
|
from chainlib.chain import ChainSpec
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from cic import Proof
|
from cic.contract.components.proof import Proof
|
||||||
from cic.actions.deploy import deploy
|
from cic.contract.components.attachment import Attachment
|
||||||
from cic.actions.types import Contract, Options
|
from cic.contract.components.meta import Meta
|
||||||
from cic.attachment import Attachment
|
from cic.contract.components.network import Network
|
||||||
from cic.meta import Meta
|
from cic.contract.components.token import Token
|
||||||
from cic.network import Network
|
from cic.contract.contract import generate_contract, load_contract, deploy_contract
|
||||||
from cic.token import Token
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from chainlib.cli.config import Config
|
from chainlib.cli.config import Config
|
||||||
@ -62,237 +61,8 @@ def validate_args(_args):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
CONTRACTS = [
|
|
||||||
{
|
|
||||||
"url": "https://gitlab.com/cicnet/eth-erc20/-/raw/master/python/giftable_erc20_token/data/GiftableToken",
|
|
||||||
"name": "Giftable Token",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://gitlab.com/cicnet/erc20-demurrage-token/-/raw/master/python/erc20_demurrage_token/data/DemurrageTokenSingleNocap",
|
|
||||||
"name": "Demurrage Token Single No Cap",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
# Download File from Url
|
def get_options(config: Config, eargs):
|
||||||
def download_file(url: str, directory: str, filename=None) -> (str, bytes):
|
|
||||||
os.makedirs(directory, exist_ok=True)
|
|
||||||
filename = filename if filename else url.split("/")[-1]
|
|
||||||
path = os.path.join(directory, filename)
|
|
||||||
if not os.path.exists(path):
|
|
||||||
log.debug(f"Downloading {filename}")
|
|
||||||
r = requests.get(url, allow_redirects=True)
|
|
||||||
open(path, "wb").write(r.content)
|
|
||||||
return path
|
|
||||||
return path
|
|
||||||
|
|
||||||
|
|
||||||
def get_contract_args(data: list):
|
|
||||||
for item in data:
|
|
||||||
if item["type"] == "constructor":
|
|
||||||
return item["inputs"]
|
|
||||||
raise Exception("No constructor found in contract")
|
|
||||||
|
|
||||||
|
|
||||||
def print_contract_args(json_path: str):
|
|
||||||
json_data = json.load(open(json_path, encoding="utf-8"))
|
|
||||||
print("Contract Args:")
|
|
||||||
for contract_arg in get_contract_args(json_data):
|
|
||||||
print(
|
|
||||||
f"\t{contract_arg.get('name', '<no name>')} - {contract_arg.get('type', '<no type>')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def select_contract():
|
|
||||||
print("Contracts:")
|
|
||||||
print("\t C - Custom (path/url to contract)")
|
|
||||||
for idx, contract in enumerate(CONTRACTS):
|
|
||||||
print(f"\t {idx} - {contract['name']}")
|
|
||||||
|
|
||||||
val = input("Select contract (C,0,1..): ")
|
|
||||||
if val.isdigit() and int(val) < len(CONTRACTS):
|
|
||||||
contract = CONTRACTS[int(val)]
|
|
||||||
directory = f"./contracts/{contract['name']}"
|
|
||||||
bin_path = os.path.abspath(download_file(contract["url"] + ".bin", directory))
|
|
||||||
json_path = download_file(contract["url"] + ".json", directory)
|
|
||||||
elif val == "C":
|
|
||||||
possible_bin_location = input("Enter path/url to contract: ")
|
|
||||||
# possible_bin_location is path
|
|
||||||
if possible_bin_location[0] == "." or possible_bin_location[0] == "/":
|
|
||||||
if os.path.exists(possible_bin_location):
|
|
||||||
bin_path = os.path.abspath(possible_bin_location)
|
|
||||||
else:
|
|
||||||
raise Exception(f"File {possible_bin_location} does not exist")
|
|
||||||
|
|
||||||
possible_json_path = val.replace(".bin", ".json")
|
|
||||||
if os.path.exists(possible_json_path):
|
|
||||||
json_path = possible_json_path
|
|
||||||
# possible_bin_location is url
|
|
||||||
else:
|
|
||||||
bin_path = download_file(possible_bin_location, directory)
|
|
||||||
else:
|
|
||||||
print("Invalid selection")
|
|
||||||
exit(1)
|
|
||||||
contract_extra_args = []
|
|
||||||
contract_extra_args_types = []
|
|
||||||
|
|
||||||
if os.path.exists(json_path):
|
|
||||||
json_data = json.load(open(json_path, encoding="utf-8"))
|
|
||||||
for contract_arg in get_contract_args(json_data):
|
|
||||||
arg_name = contract_arg.get("name")
|
|
||||||
arg_type = contract_arg.get("type")
|
|
||||||
if arg_name not in ["_decimals", "_name", "_symbol"]:
|
|
||||||
val = input(f"Enter value for {arg_name} ({arg_type}): ")
|
|
||||||
contract_extra_args.append(val)
|
|
||||||
if arg_type == "uint128":
|
|
||||||
contract_extra_args_types.append("uint256")
|
|
||||||
else:
|
|
||||||
contract_extra_args_types.append(arg_type)
|
|
||||||
|
|
||||||
return {
|
|
||||||
"bin_path": bin_path,
|
|
||||||
"json_path": json_path,
|
|
||||||
"extra_args": contract_extra_args,
|
|
||||||
"extra_args_types": contract_extra_args_types,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def init_token(directory: str, code=""):
|
|
||||||
contract = select_contract()
|
|
||||||
code = contract["bin_path"]
|
|
||||||
contract_extra_args = contract["extra_args"]
|
|
||||||
contract_extra_args_types = contract["extra_args_types"]
|
|
||||||
|
|
||||||
name = input("Enter Token Name (Foo Token): ") or "Foo Token"
|
|
||||||
symbol = input("Enter Token Symbol (FOO): ") or "FOO"
|
|
||||||
precision = input("Enter Token Precision (6): ") or 6
|
|
||||||
supply = input("Enter Token Supply (0): ") or 0
|
|
||||||
|
|
||||||
contract_token = Token(
|
|
||||||
directory,
|
|
||||||
name=name,
|
|
||||||
symbol=symbol,
|
|
||||||
precision=precision,
|
|
||||||
extra_args=contract_extra_args,
|
|
||||||
extra_args_types=contract_extra_args_types,
|
|
||||||
supply=supply,
|
|
||||||
code=code,
|
|
||||||
)
|
|
||||||
contract_token.start()
|
|
||||||
return contract_token
|
|
||||||
|
|
||||||
|
|
||||||
def init_proof(directory):
|
|
||||||
description = input("Enter Proof Description (None): ") or None
|
|
||||||
namespace = input("Enter Proof Namespace (ge): ") or "ge"
|
|
||||||
issuer = input("Enter Proof Issuer (None): ") or None
|
|
||||||
contract_proof = Proof(directory, description, namespace, issuer)
|
|
||||||
contract_proof.start()
|
|
||||||
return contract_proof
|
|
||||||
|
|
||||||
|
|
||||||
def init_meta(directory):
|
|
||||||
name = input("Enter Name (None): ") or ""
|
|
||||||
country_code = input("Enter Country Code (KE): ") or "KE"
|
|
||||||
location = input("Enter Location (None): ") or ""
|
|
||||||
adding_contact_info = True
|
|
||||||
contact = {}
|
|
||||||
while adding_contact_info:
|
|
||||||
value = input("Enter contact info (e.g 'phone: +254723522718'): ") or None
|
|
||||||
if value:
|
|
||||||
data = value.split(":")
|
|
||||||
if len(data) != 2:
|
|
||||||
print("Invalid contact info, you must enter in the format 'key: value'")
|
|
||||||
continue
|
|
||||||
contact[data[0].strip()] = data[1].strip()
|
|
||||||
else:
|
|
||||||
adding_contact_info = False
|
|
||||||
contract_meta = Meta(
|
|
||||||
directory,
|
|
||||||
name=name,
|
|
||||||
country_code=country_code,
|
|
||||||
location=location,
|
|
||||||
contact=contact,
|
|
||||||
)
|
|
||||||
contract_meta.start()
|
|
||||||
return contract_meta
|
|
||||||
|
|
||||||
|
|
||||||
def init_attachment(directory):
|
|
||||||
contract_attchment = Attachment(directory)
|
|
||||||
contract_attchment.start()
|
|
||||||
input(
|
|
||||||
f"Please add attachment files to '{os.path.abspath(os.path.join(directory,'attachments'))}' and then press ENTER to continue"
|
|
||||||
)
|
|
||||||
contract_attchment.load()
|
|
||||||
return contract_attchment
|
|
||||||
|
|
||||||
|
|
||||||
def load_contract(directory) -> Contract:
|
|
||||||
token = Token(path=directory)
|
|
||||||
proof = Proof(path=directory)
|
|
||||||
meta = Meta(path=directory)
|
|
||||||
attachment = Attachment(path=directory)
|
|
||||||
network = Network(directory)
|
|
||||||
|
|
||||||
token.load()
|
|
||||||
proof.load()
|
|
||||||
meta.load()
|
|
||||||
attachment.load()
|
|
||||||
network.load()
|
|
||||||
return Contract(
|
|
||||||
token=token, proof=proof, meta=meta, attachment=attachment, network=network
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def init_network(
|
|
||||||
directory,
|
|
||||||
options: Options,
|
|
||||||
targets: List[str],
|
|
||||||
):
|
|
||||||
contract_network = Network(directory, targets=targets)
|
|
||||||
contract_network.start()
|
|
||||||
|
|
||||||
for target in targets:
|
|
||||||
m = importlib.import_module(f"cic.ext.{target}.start")
|
|
||||||
m.extension_start(
|
|
||||||
contract_network,
|
|
||||||
registry_address=options.contract_registry,
|
|
||||||
chain_spec=options.chain_spec,
|
|
||||||
rpc_provider=options.rpc_provider,
|
|
||||||
key_account_address=options.key_account,
|
|
||||||
)
|
|
||||||
contract_network.load()
|
|
||||||
return contract_network
|
|
||||||
|
|
||||||
|
|
||||||
def generate(directory: str, target: str, options: Options) -> Contract:
|
|
||||||
if os.path.exists(directory):
|
|
||||||
contine = input(
|
|
||||||
"Directory already exists, Would you like to delete it? (y/n): "
|
|
||||||
)
|
|
||||||
if contine.lower() != "y":
|
|
||||||
print("Exiting")
|
|
||||||
exit(1)
|
|
||||||
else:
|
|
||||||
print(f"Deleted {directory}")
|
|
||||||
os.system(f"rm -rf {directory}")
|
|
||||||
os.makedirs(directory)
|
|
||||||
|
|
||||||
token = init_token(directory)
|
|
||||||
proof = init_proof(directory)
|
|
||||||
meta = init_meta(directory)
|
|
||||||
attachment = init_attachment(directory)
|
|
||||||
network = init_network(
|
|
||||||
directory,
|
|
||||||
options,
|
|
||||||
targets=[target],
|
|
||||||
)
|
|
||||||
return Contract(
|
|
||||||
token=token, proof=proof, meta=meta, attachment=attachment, network=network
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_options(config: Config, eargs) -> Options:
|
|
||||||
# Defaults
|
# Defaults
|
||||||
default_contract_registry = config.get(
|
default_contract_registry = config.get(
|
||||||
"CIC_REGISTRY_ADDRESS"
|
"CIC_REGISTRY_ADDRESS"
|
||||||
@ -333,7 +103,7 @@ def get_options(config: Config, eargs) -> Options:
|
|||||||
auth_keyfile_path = config.get("AUTH_KEYFILE_PATH")
|
auth_keyfile_path = config.get("AUTH_KEYFILE_PATH")
|
||||||
auth_db_path = config.get("AUTH_DB_PATH")
|
auth_db_path = config.get("AUTH_DB_PATH")
|
||||||
|
|
||||||
options = Options(
|
options = [
|
||||||
auth_db_path,
|
auth_db_path,
|
||||||
auth_keyfile_path,
|
auth_keyfile_path,
|
||||||
auth_passphrase,
|
auth_passphrase,
|
||||||
@ -344,14 +114,11 @@ def get_options(config: Config, eargs) -> Options:
|
|||||||
metadata_endpoint,
|
metadata_endpoint,
|
||||||
default_wallet_keyfile,
|
default_wallet_keyfile,
|
||||||
default_wallet_passphrase,
|
default_wallet_passphrase,
|
||||||
)
|
]
|
||||||
print(options)
|
print(options)
|
||||||
return options
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ExtraArgs = {"skip_gen": str, "skip_deploy": str, "target": str, "path": str, "p": str}
|
ExtraArgs = {"skip_gen": str, "skip_deploy": str, "target": str, "path": str, "p": str}
|
||||||
|
|
||||||
|
|
||||||
@ -362,22 +129,19 @@ def execute(config, eargs: ExtraArgs):
|
|||||||
skip_gen = eargs.skip_gen
|
skip_gen = eargs.skip_gen
|
||||||
skip_deploy = eargs.skip_deploy
|
skip_deploy = eargs.skip_deploy
|
||||||
|
|
||||||
options = get_options(config, eargs)
|
|
||||||
|
|
||||||
if not skip_gen:
|
if not skip_gen:
|
||||||
contract = generate(directory, target, options)
|
contract = generate_contract(directory, [target], config, interactive=True)
|
||||||
else:
|
else:
|
||||||
contract = load_contract(directory)
|
contract = load_contract(directory)
|
||||||
|
|
||||||
print_contract(contract)
|
print(contract)
|
||||||
|
|
||||||
if not skip_deploy:
|
if not skip_deploy:
|
||||||
ready_to_deploy = input("Ready to deploy? (y/n): ")
|
ready_to_deploy = input("Ready to deploy? (y/n): ")
|
||||||
if ready_to_deploy == "y":
|
if ready_to_deploy == "y":
|
||||||
deploy(
|
deploy_contract(
|
||||||
config=config,
|
config=config,
|
||||||
contract_directory=directory,
|
contract_directory=directory,
|
||||||
options=options,
|
|
||||||
target=target,
|
target=target,
|
||||||
)
|
)
|
||||||
print("Deployed")
|
print("Deployed")
|
||||||
|
@ -3,7 +3,7 @@ import os
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
|
|
||||||
mod_dir = os.path.dirname(os.path.realpath(__file__))
|
mod_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')
|
||||||
root_dir = os.path.join(mod_dir, '..')
|
root_dir = os.path.join(mod_dir, '..')
|
||||||
data_dir = os.path.join(mod_dir, 'data')
|
data_dir = os.path.join(mod_dir, 'data')
|
||||||
schema_dir = os.path.join(mod_dir, 'schema')
|
schema_dir = os.path.join(mod_dir, 'schema')
|
||||||
|
@ -4,8 +4,6 @@ from __future__ import annotations
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import base64
|
|
||||||
from typing import TYPE_CHECKING
|
|
||||||
|
|
||||||
# external imports
|
# external imports
|
||||||
from cic_types import MetadataPointer
|
from cic_types import MetadataPointer
|
||||||
@ -14,8 +12,6 @@ from hexathon import strip_0x
|
|||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from cic.contract.base import Data, data_dir
|
from cic.contract.base import Data, data_dir
|
||||||
from cic.writers import OutputWriter
|
|
||||||
from cic_types.ext.metadata import MetadataRequestsHandler
|
|
||||||
from cic.utils import object_to_str
|
from cic.utils import object_to_str
|
||||||
|
|
||||||
logg = logging.getLogger(__name__)
|
logg = logging.getLogger(__name__)
|
||||||
@ -139,25 +135,3 @@ class Meta(Data):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return object_to_str(self, ["name", "contact", "country_code", "location"])
|
return object_to_str(self, ["name", "contact", "country_code", "location"])
|
||||||
|
|
||||||
|
|
||||||
class MetadataWriter(OutputWriter):
|
|
||||||
"""Custom writer for publishing data under immutable content-addressed pointers in the cic-meta storage backend.
|
|
||||||
|
|
||||||
Data that is not utf-8 will be converted to base64 before publishing.
|
|
||||||
|
|
||||||
Implements cic.writers.OutputWriter
|
|
||||||
"""
|
|
||||||
|
|
||||||
def write(self, k, v):
|
|
||||||
rq = MetadataRequestsHandler(MetadataPointer.NONE, bytes.fromhex(k))
|
|
||||||
try:
|
|
||||||
v = v.decode("utf-8")
|
|
||||||
v = json.loads(v)
|
|
||||||
logg.debug(f"metadatawriter bindecode {k} {v}")
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
v = base64.b64encode(v).decode("utf-8")
|
|
||||||
v = json.loads(json.dumps(v, separators=(",", ":")))
|
|
||||||
logg.debug(f"metadatawriter b64encode {k} {v}")
|
|
||||||
r = rq.create(v)
|
|
||||||
logg.info(f"metadata submitted at {k}")
|
|
||||||
return r
|
|
||||||
|
@ -7,7 +7,7 @@ import logging
|
|||||||
from chainlib.chain import ChainSpec
|
from chainlib.chain import ChainSpec
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from cic.contract.components.base import Data, data_dir
|
from cic.contract.base import Data, data_dir
|
||||||
|
|
||||||
logg = logging.getLogger(__name__)
|
logg = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -35,9 +35,8 @@ class Network(Data):
|
|||||||
"""
|
"""
|
||||||
super(Network, self).load()
|
super(Network, self).load()
|
||||||
|
|
||||||
f = open(self.network_path, 'r')
|
with open(self.network_path, 'r', encoding='utf-8') as f:
|
||||||
o = json.load(f)
|
o = json.load(f)
|
||||||
f.close()
|
|
||||||
|
|
||||||
self.resources = o['resources']
|
self.resources = o['resources']
|
||||||
|
|
||||||
@ -53,9 +52,8 @@ class Network(Data):
|
|||||||
|
|
||||||
network_template_file_path = os.path.join(data_dir, f'network_template_v{self.version()}.json')
|
network_template_file_path = os.path.join(data_dir, f'network_template_v{self.version()}.json')
|
||||||
|
|
||||||
f = open(network_template_file_path)
|
with open(network_template_file_path, encoding='utf-8') as f:
|
||||||
o_part = json.load(f)
|
o_part = json.load(f)
|
||||||
f.close()
|
|
||||||
|
|
||||||
self.resources = {}
|
self.resources = {}
|
||||||
for v in self.targets:
|
for v in self.targets:
|
||||||
@ -67,11 +65,10 @@ class Network(Data):
|
|||||||
def save(self):
|
def save(self):
|
||||||
"""Save network settings to file.
|
"""Save network settings to file.
|
||||||
"""
|
"""
|
||||||
f = open(self.network_path, 'w')
|
with open(self.network_path, 'w', encoding='utf-8') as f:
|
||||||
json.dump({
|
json.dump({
|
||||||
'resources': self.resources,
|
'resources': self.resources,
|
||||||
}, f, sort_keys=True, indent="\t")
|
}, f, sort_keys=True, indent="\t")
|
||||||
f.close()
|
|
||||||
|
|
||||||
|
|
||||||
def resource(self, k):
|
def resource(self, k):
|
||||||
@ -83,8 +80,8 @@ class Network(Data):
|
|||||||
:return: Extension settings
|
:return: Extension settings
|
||||||
"""
|
"""
|
||||||
v = self.resources.get(k)
|
v = self.resources.get(k)
|
||||||
if v == None:
|
if v is None:
|
||||||
raise AttributeError('no defined reference for {}'.format(k))
|
raise AttributeError(f'No defined reference for {k}')
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
||||||
@ -129,7 +126,7 @@ class Network(Data):
|
|||||||
"""
|
"""
|
||||||
chain_spec_dict = chain_spec.asdict()
|
chain_spec_dict = chain_spec.asdict()
|
||||||
for k in chain_spec_dict.keys():
|
for k in chain_spec_dict.keys():
|
||||||
logg.debug('resources {}'.format(self.resources))
|
logg.debug(f'resources: {self.resources}')
|
||||||
self.resources[resource_key]['chain_spec'][k] = chain_spec_dict[k]
|
self.resources[resource_key]['chain_spec'][k] = chain_spec_dict[k]
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,16 +10,16 @@ import requests
|
|||||||
from cic_types.ext.metadata import MetadataRequestsHandler
|
from cic_types.ext.metadata import MetadataRequestsHandler
|
||||||
from cic_types.ext.metadata.signer import Signer as MetadataSigner
|
from cic_types.ext.metadata.signer import Signer as MetadataSigner
|
||||||
from chainlib.cli.config import Config
|
from chainlib.cli.config import Config
|
||||||
|
from chainlib.chain import ChainSpec
|
||||||
# Local Modules
|
# Local Modules
|
||||||
from cic.contract import ContractProcessor
|
from cic.contract.processor import ContractProcessor
|
||||||
from cic.contract.components.attachment import Attachment
|
from cic.contract.components.attachment import Attachment
|
||||||
from cic.contract.components.meta import Meta
|
from cic.contract.components.meta import Meta
|
||||||
from cic.contract.components.network import Network
|
from cic.contract.components.network import Network
|
||||||
from cic.contract.components.proof import Proof
|
from cic.contract.components.proof import Proof
|
||||||
from cic.contract.components.token import Token
|
from cic.contract.components.token import Token
|
||||||
from cic.contract.helpers import init_writers_from_config
|
from cic.contract.helpers import init_writers_from_config
|
||||||
from cic.writers import HTTPWriter, KeyedWriterFactory, OutputWriter
|
from cic.writers import HTTPWriter, KeyedWriterFactory, OutputWriter, MetadataWriter
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -78,35 +78,45 @@ def generate_contract(
|
|||||||
"Directory already exists, Would you like to delete it? (y/n): "
|
"Directory already exists, Would you like to delete it? (y/n): "
|
||||||
)
|
)
|
||||||
if contine.lower() != "y":
|
if contine.lower() != "y":
|
||||||
print("Exiting")
|
print("Trying to load existing contract")
|
||||||
exit(1)
|
return load_contract(directory)
|
||||||
else:
|
else:
|
||||||
print(f"Deleted {directory}")
|
print(f"Deleted {directory}")
|
||||||
os.system(f"rm -rf {directory}")
|
os.system(f"rm -rf {directory}")
|
||||||
os.makedirs(directory)
|
os.makedirs(directory)
|
||||||
|
log.debug("Generating token")
|
||||||
token = Token(directory, interactive=interactive)
|
token = Token(directory, interactive=interactive)
|
||||||
token.start()
|
token.start()
|
||||||
|
|
||||||
|
log.debug("Generating proof")
|
||||||
proof = Proof(directory, interactive=interactive)
|
proof = Proof(directory, interactive=interactive)
|
||||||
proof.start()
|
proof.start()
|
||||||
|
|
||||||
|
log.debug("Generating meta")
|
||||||
meta = Meta(directory, interactive=interactive)
|
meta = Meta(directory, interactive=interactive)
|
||||||
meta.start()
|
meta.start()
|
||||||
|
|
||||||
|
log.debug("Generating attachment")
|
||||||
attachment = Attachment(directory, interactive=interactive)
|
attachment = Attachment(directory, interactive=interactive)
|
||||||
|
|
||||||
|
log.debug("Generating network")
|
||||||
network = Network(directory, targets=targets)
|
network = Network(directory, targets=targets)
|
||||||
network.start()
|
network.start()
|
||||||
|
|
||||||
|
log.debug(f"""Populating infomation from network:
|
||||||
|
CIC_REGISTRY_ADDRESS: {config.get("CIC_REGISTRY_ADDRESS")}
|
||||||
|
CHAIN_SPEC: {config.get("CHAIN_SPEC")}
|
||||||
|
RPC_PROVIDER: {config.get("RPC_PROVIDER")}
|
||||||
|
AUTH_KEY: {config.get("AUTH_KEY")}
|
||||||
|
""")
|
||||||
for target in targets:
|
for target in targets:
|
||||||
m = importlib.import_module(f"cic.ext.{target}.start")
|
m = importlib.import_module(f"cic.ext.{target}.start")
|
||||||
m.extension_start(
|
m.extension_start(
|
||||||
network,
|
network,
|
||||||
registry_address=config.get("CIC_REGISTRY_ADDRESS"),
|
registry_address=config.get("CIC_REGISTRY_ADDRESS"),
|
||||||
chain_spec=config.get("CHAIN_SPEC"),
|
chain_spec=ChainSpec.from_chain_str(config.get("CHAIN_SPEC")),
|
||||||
rpc_provider=config.get("RPC_PROVIDER"),
|
rpc_provider=config.get("RPC_PROVIDER"),
|
||||||
key_account_address=config.get("RPC_PROVIDER"),
|
key_account_address=config.get("AUTH_KEY"), # TODO this should come from the wallet keystore
|
||||||
)
|
)
|
||||||
network.load()
|
network.load()
|
||||||
|
|
||||||
@ -115,7 +125,7 @@ def generate_contract(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def deploy(
|
def deploy_contract(
|
||||||
config: Config,
|
config: Config,
|
||||||
target: str,
|
target: str,
|
||||||
contract_directory: str,
|
contract_directory: str,
|
||||||
@ -133,7 +143,7 @@ def deploy(
|
|||||||
if metadata_endpoint is not None:
|
if metadata_endpoint is not None:
|
||||||
MetadataRequestsHandler.base_url = metadata_endpoint
|
MetadataRequestsHandler.base_url = metadata_endpoint
|
||||||
MetadataSigner.gpg_path = "/tmp"
|
MetadataSigner.gpg_path = "/tmp"
|
||||||
MetadataSigner.key_file_path = config.get("AUTH_KEYFILE")
|
MetadataSigner.key_file_path = config.get("AUTH_KEYFILE_PATH")
|
||||||
MetadataSigner.gpg_passphrase = config.get("AUTH_PASSPHRASE")
|
MetadataSigner.gpg_passphrase = config.get("AUTH_PASSPHRASE")
|
||||||
writers["proof"] = KeyedWriterFactory(MetadataWriter, HTTPWriter).new
|
writers["proof"] = KeyedWriterFactory(MetadataWriter, HTTPWriter).new
|
||||||
writers["attachment"] = KeyedWriterFactory(None, HTTPWriter).new
|
writers["attachment"] = KeyedWriterFactory(None, HTTPWriter).new
|
||||||
@ -169,6 +179,8 @@ def deploy(
|
|||||||
chain_spec = cn.chain_spec
|
chain_spec = cn.chain_spec
|
||||||
config.add(chain_spec, "CHAIN_SPEC", exists_ok=True)
|
config.add(chain_spec, "CHAIN_SPEC", exists_ok=True)
|
||||||
log.debug(f"using CHAIN_SPEC: {str(chain_spec)} from network")
|
log.debug(f"using CHAIN_SPEC: {str(chain_spec)} from network")
|
||||||
|
print(chain_spec)
|
||||||
|
|
||||||
signer_hint = config.get("WALLET_KEY_FILE")
|
signer_hint = config.get("WALLET_KEY_FILE")
|
||||||
(rpc, signer) = cmd_mod.parse_adapter(config, signer_hint)
|
(rpc, signer) = cmd_mod.parse_adapter(config, signer_hint)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
|
import importlib
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
from cic.writers import OutputWriter
|
from cic.writers import OutputWriter
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
# standard imports
|
# standard imports
|
||||||
|
import base64
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from cic_types.ext.metadata import MetadataRequestsHandler
|
||||||
|
|
||||||
|
|
||||||
logg = logging.getLogger(__name__)
|
logg = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class OutputWriter:
|
class OutputWriter:
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -17,13 +21,11 @@ class OutputWriter:
|
|||||||
|
|
||||||
|
|
||||||
class StdoutWriter(OutputWriter):
|
class StdoutWriter(OutputWriter):
|
||||||
|
|
||||||
def write(self, k, v):
|
def write(self, k, v):
|
||||||
sys.stdout.write('{}\t{}\n'.format(k, v))
|
sys.stdout.write("{}\t{}\n".format(k, v))
|
||||||
|
|
||||||
|
|
||||||
class KVWriter(OutputWriter):
|
class KVWriter(OutputWriter):
|
||||||
|
|
||||||
def __init__(self, path=None, *args, **kwargs):
|
def __init__(self, path=None, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
os.stat(path)
|
os.stat(path)
|
||||||
@ -31,43 +33,38 @@ class KVWriter(OutputWriter):
|
|||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
|
|
||||||
def write(self, k, v):
|
def write(self, k, v):
|
||||||
fp = os.path.join(self.path, str(k))
|
fp = os.path.join(self.path, str(k))
|
||||||
logg.debug('path write {} {}'.format(fp, str(v)))
|
logg.debug("path write {} {}".format(fp, str(v)))
|
||||||
f = open(fp, 'wb')
|
f = open(fp, "wb")
|
||||||
f.write(v)
|
f.write(v)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
class HTTPWriter(OutputWriter):
|
class HTTPWriter(OutputWriter):
|
||||||
|
|
||||||
def __init__(self, path=None, *args, **kwargs):
|
def __init__(self, path=None, *args, **kwargs):
|
||||||
super(HTTPWriter, self).__init__(*args, **kwargs)
|
super(HTTPWriter, self).__init__(*args, **kwargs)
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
|
|
||||||
def write(self, k, v):
|
def write(self, k, v):
|
||||||
path = self.path
|
path = self.path
|
||||||
if k != None:
|
if k != None:
|
||||||
path = os.path.join(path, k)
|
path = os.path.join(path, k)
|
||||||
logg.debug(f'http writer post {path} \n key: {k}, value: {v}')
|
logg.debug(f"http writer post {path} \n key: {k}, value: {v}")
|
||||||
rq = urllib.request.Request(path, method='POST', data=v)
|
rq = urllib.request.Request(path, method="POST", data=v)
|
||||||
r = urllib.request.urlopen(rq)
|
r = urllib.request.urlopen(rq)
|
||||||
logg.info('http writer submitted at {}'.format(r.read()))
|
logg.info("http writer submitted at {}".format(r.read()))
|
||||||
|
|
||||||
|
|
||||||
class KeyedWriter(OutputWriter):
|
class KeyedWriter(OutputWriter):
|
||||||
|
|
||||||
def __init__(self, writer_keyed, writer_immutable):
|
def __init__(self, writer_keyed, writer_immutable):
|
||||||
self.writer_keyed = writer_keyed
|
self.writer_keyed = writer_keyed
|
||||||
self.writer_immutable = writer_immutable
|
self.writer_immutable = writer_immutable
|
||||||
|
|
||||||
|
|
||||||
def write(self, key, value):
|
def write(self, key, value):
|
||||||
logg.debug(f'writing keywriter key: {key} value: {value}')
|
logg.debug(f"writing keywriter key: {key} value: {value}")
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
value = value.encode('utf-8')
|
value = value.encode("utf-8")
|
||||||
if self.writer_keyed != None:
|
if self.writer_keyed != None:
|
||||||
self.writer_keyed.write(key, value)
|
self.writer_keyed.write(key, value)
|
||||||
if self.writer_immutable != None:
|
if self.writer_immutable != None:
|
||||||
@ -75,15 +72,15 @@ class KeyedWriter(OutputWriter):
|
|||||||
|
|
||||||
|
|
||||||
class KeyedWriterFactory:
|
class KeyedWriterFactory:
|
||||||
|
def __init__(
|
||||||
def __init__(self, key_writer_constructor, immutable_writer_constructor, *args, **kwargs):
|
self, key_writer_constructor, immutable_writer_constructor, *args, **kwargs
|
||||||
|
):
|
||||||
self.key_writer_constructor = key_writer_constructor
|
self.key_writer_constructor = key_writer_constructor
|
||||||
self.immutable_writer_constructor = immutable_writer_constructor
|
self.immutable_writer_constructor = immutable_writer_constructor
|
||||||
self.x = {}
|
self.x = {}
|
||||||
for k in kwargs.keys():
|
for k in kwargs.keys():
|
||||||
logg.debug('adding key {} t keyed writer factory'.format(k))
|
logg.debug("adding key {} t keyed writer factory".format(k))
|
||||||
self.x[k] = kwargs[k]
|
self.x[k] = kwargs[k]
|
||||||
|
|
||||||
|
|
||||||
def new(self, path=None, *args, **kwargs):
|
def new(self, path=None, *args, **kwargs):
|
||||||
writer_keyed = None
|
writer_keyed = None
|
||||||
@ -93,3 +90,26 @@ class KeyedWriterFactory:
|
|||||||
if self.immutable_writer_constructor != None:
|
if self.immutable_writer_constructor != None:
|
||||||
writer_immutable = self.immutable_writer_constructor(path, **self.x)
|
writer_immutable = self.immutable_writer_constructor(path, **self.x)
|
||||||
return KeyedWriter(writer_keyed, writer_immutable)
|
return KeyedWriter(writer_keyed, writer_immutable)
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataWriter(OutputWriter):
|
||||||
|
"""Custom writer for publishing data under immutable content-addressed pointers in the cic-meta storage backend.
|
||||||
|
|
||||||
|
Data that is not utf-8 will be converted to base64 before publishing.
|
||||||
|
|
||||||
|
Implements cic.writers.OutputWriter
|
||||||
|
"""
|
||||||
|
|
||||||
|
def write(self, k, v):
|
||||||
|
rq = MetadataRequestsHandler(MetadataPointer.NONE, bytes.fromhex(k))
|
||||||
|
try:
|
||||||
|
v = v.decode("utf-8")
|
||||||
|
v = json.loads(v)
|
||||||
|
logg.debug(f"metadatawriter bindecode {k} {v}")
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
v = base64.b64encode(v).decode("utf-8")
|
||||||
|
v = json.loads(json.dumps(v, separators=(",", ":")))
|
||||||
|
logg.debug(f"metadatawriter b64encode {k} {v}")
|
||||||
|
r = rq.create(v)
|
||||||
|
logg.info(f"metadata submitted at {k}")
|
||||||
|
return r
|
||||||
|
@ -16,13 +16,13 @@ provider = http://localhost:63545
|
|||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
type = gnupg
|
type = gnupg
|
||||||
db_path = ~/.local/share/cic/clicada
|
db_path = /home/will/.local/share/cic/clicada
|
||||||
key = eb3907ecad74a0013c259d5874ae7f22dcbcc95c
|
key = eb3907ecad74a0013c259d5874ae7f22dcbcc95c
|
||||||
keyfile_path = ~/grassroots/cic-internal-integration/apps/cic-ussd/tests/data/pgp/privatekeys_meta.asc
|
keyfile_path = /home/will/grassroots/cic-internal-integration/apps/cic-ussd/tests/data/pgp/privatekeys_meta.asc
|
||||||
passphrase = merman
|
passphrase = merman
|
||||||
|
|
||||||
[wallet]
|
[wallet]
|
||||||
key_file = ~/grassroots/cic-internal-integration/apps/contract-migration/keystore/UTC
|
key_file = /home/will/grassroots/cic-internal-integration/apps/contract-migration/keystore
|
||||||
passphrase =
|
passphrase =
|
||||||
|
|
||||||
[chain]
|
[chain]
|
||||||
|
@ -16,9 +16,9 @@ provider = https://rpc.grassecon.net
|
|||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
type = gnupg
|
type = gnupg
|
||||||
db_path = ~/.local/share/cic/clicada
|
db_path = /home/will/.local/share/cic/clicada
|
||||||
key = CCE2E1D2D0E36ADE0405E2D0995BB21816313BD5
|
key = CCE2E1D2D0E36ADE0405E2D0995BB21816313BD5
|
||||||
keyfile_path = ~/.config/cic/staff-client/user.asc
|
keyfile_path = /home/will/.config/cic/staff-client/user.asc
|
||||||
passphrase = queenmarlena
|
passphrase = queenmarlena
|
||||||
|
|
||||||
[wallet]
|
[wallet]
|
||||||
|
Loading…
Reference in New Issue
Block a user