-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #148 from astroseger/fix-for-platform-contracts-v0…
….2.5 Fix for platform contracts v0.2.5
- Loading branch information
Showing
21 changed files
with
935 additions
and
539 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"dependencies": { | ||
"singularitynet-platform-contracts": "https://github.com/singnet/platform-contracts/releases/download/v0.2.4/singularitynet-platform-contracts-0.2.4.tgz", | ||
"singularitynet-platform-contracts": "https://github.com/singnet/platform-contracts/releases/download/v0.2.5/singularitynet-platform-contracts-0.2.5.tgz", | ||
"singularitynet-token-contracts": "2.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
from snet_cli.commands import BlockchainCommand | ||
from snet_cli.utils_agi2cogs import cogs2stragi | ||
|
||
|
||
class MPEAccountCommand(BlockchainCommand): | ||
|
||
def print_account(self): | ||
self._printout(self.ident.address) | ||
|
||
# print balance of ETH, AGI, and MPE wallet | ||
def print_agi_and_mpe_balances(self): | ||
if (self.args.account): | ||
account = self.args.account | ||
else: | ||
account = self.ident.address | ||
eth_wei = self.w3.eth.getBalance(account) | ||
agi_cogs = self.call_contract_command("SingularityNetToken", "balanceOf", [account]) | ||
mpe_cogs = self.call_contract_command("MultiPartyEscrow", "balances", [account]) | ||
|
||
# we cannot use _pprint here because it doesn't conserve order yet | ||
self._printout(" account: %s"%account) | ||
self._printout(" ETH: %s"%self.w3.fromWei(eth_wei, 'ether')) | ||
self._printout(" AGI: %s"%cogs2stragi(agi_cogs)) | ||
self._printout(" MPE: %s"%cogs2stragi(mpe_cogs)) | ||
|
||
def deposit_to_mpe(self): | ||
amount = self.args.amount | ||
mpe_address = self.get_mpe_address() | ||
|
||
already_approved = self.call_contract_command("SingularityNetToken", "allowance", [self.ident.address, mpe_address]) | ||
if (already_approved < amount): | ||
self.transact_contract_command("SingularityNetToken", "approve", [mpe_address, amount]) | ||
self.transact_contract_command("MultiPartyEscrow", "deposit", [amount]) | ||
|
||
def withdraw_from_mpe(self): | ||
self.transact_contract_command("MultiPartyEscrow", "withdraw", [self.args.amount]) | ||
|
||
def transfer_in_mpe(self): | ||
self.transact_contract_command("MultiPartyEscrow", "transfer", [self.args.receiver, self.args.amount]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
from snet_cli.mpe_service_command import MPEServiceCommand | ||
from snet_cli.utils import compile_proto | ||
import base64 | ||
from pathlib import Path | ||
import os | ||
from snet_cli.utils import get_contract_def, abi_get_element_by_name, abi_decode_struct_to_dict | ||
from snet_cli.mpe_service_metadata import load_mpe_service_metadata | ||
from snet_cli.utils_ipfs import safe_extract_proto_from_ipfs | ||
import shutil | ||
import tempfile | ||
from snet_cli.utils_agi2cogs import cogs2stragi | ||
import pickle | ||
from snet_cli.contract import Contract | ||
|
||
# we inherit MPEServiceCommand because we need _get_service_metadata_from_registry | ||
class MPEChannelCommand(MPEServiceCommand): | ||
|
||
# get persistent storage for mpe | ||
def _get_persistent_mpe_dir(self): | ||
return Path.home().joinpath(".snet", "mpe_client") | ||
|
||
# get persistent storage for the given channel (~/.snet/mpe_client/<mpe_address>/<channel-id>/) | ||
def _get_channel_dir(self, channel_id): | ||
mpe_address = self.get_mpe_address().lower() | ||
return self._get_persistent_mpe_dir().joinpath(mpe_address, str(channel_id)) | ||
|
||
def get_channel_dir(self): | ||
return self._get_channel_dir(self.args.channel_id) | ||
|
||
def _save_channel_info_dir(self, channel_dir, channel_info): | ||
fn = os.path.join(channel_dir, "channel_info.pickle") | ||
pickle.dump( channel_info, open( fn, "wb" ) ) | ||
|
||
def _read_channel_info(self, channel_id): | ||
fn = os.path.join(self._get_channel_dir(channel_id), "channel_info.pickle") | ||
return pickle.load( open( fn, "rb" ) ) | ||
|
||
# we make sure that MultiPartyEscrow address from metadata is correct | ||
def _check_mpe_address_metadata(self, metadata): | ||
mpe_address = self.get_mpe_address() | ||
if (str(mpe_address).lower() != str(metadata["mpe_address"]).lower()): | ||
raise Exception("MultiPartyEscrow contract address from metadata %s do not correspond to current MultiPartyEscrow address %s"%(metadata["mpe_address"], mpe_address)) | ||
|
||
def _init_channel_from_metadata(self, channel_dir, metadata, channel_info): | ||
self._check_mpe_address_metadata(metadata) | ||
if (os.path.exists(channel_dir)): | ||
raise Exception("Directory %s already exists"%channel_dir) | ||
|
||
os.makedirs(channel_dir, mode=0o700) | ||
try: | ||
spec_dir = os.path.join(channel_dir, "service_spec") | ||
os.makedirs(spec_dir, mode=0o700) | ||
safe_extract_proto_from_ipfs(self._get_ipfs_client(), metadata["model_ipfs_hash"], spec_dir) | ||
|
||
# compile .proto files | ||
if (not compile_proto(Path(spec_dir), channel_dir)): | ||
raise Exception("Fail to compile %s/*.proto"%spec_dir) | ||
|
||
# save service_metadata.json in channel_dir | ||
metadata.save_pretty(os.path.join(channel_dir, "service_metadata.json")) | ||
|
||
# save channel_info (we need sender and signer) | ||
self._save_channel_info_dir(channel_dir, channel_info) | ||
except: | ||
# it is secure to remove channel_dir, because we've created it | ||
shutil.rmtree(channel_dir) | ||
raise | ||
|
||
def _check_channel_is_mine(self, channel): | ||
if (channel["sender"].lower() != self.ident.address.lower() and | ||
channel["signer"].lower() != self.ident.address.lower()): | ||
raise Exception("Channel %i does not correspond to the current Ethereum identity "%channel_id + | ||
"(address=%s sender=%s signer=%s)"%(self.ident.address.lower(), channel["sender"].lower(), channel["signer"].lower())) | ||
|
||
def _try_init_channel_from_metadata(self, metadata): | ||
channel = self._get_channel_state_from_blockchain(self.args.channel_id) | ||
channel_id = self.args.channel_id | ||
if (channel["sender"].lower() != self.ident.address.lower() and | ||
channel["signer"].lower() != self.ident.address.lower()): | ||
raise Exception("Channel %i does not correspond to the current Ethereum identity "%channel_id + | ||
"(address=%s sender=%s signer=%s)"%(self.ident.address.lower(), channel["sender"].lower(), channel["signer"].lower())) | ||
group_name = metadata.get_group_by_group_id(channel["groupId"]) | ||
if (not group_name): | ||
group_id_base64 = base64.b64encode(channel["groupId"]).decode('ascii') | ||
raise Exception("Channel %i does not correspond to the given metadata.\n"%channel_id + | ||
"We canot find the following group_id in metadata: " + group_id_base64) | ||
self._printout("#group_name") | ||
self._printout(group_name["group_name"]) | ||
self._init_channel_from_metadata(self.get_channel_dir(), metadata, channel) | ||
|
||
def init_channel_from_metadata(self): | ||
metadata = load_mpe_service_metadata(self.args.metadata_file) | ||
self._try_init_channel_from_metadata(metadata) | ||
|
||
def init_channel_from_registry(self): | ||
metadata = self._get_service_metadata_from_registry() | ||
self._try_init_channel_from_metadata(metadata) | ||
|
||
def _open_channel_for_service(self, metadata): | ||
group_id = metadata.get_group_id(self.args.group_name) | ||
recipient = metadata.get_payment_address(self.args.group_name) | ||
|
||
if (self.args.signer): | ||
signer = self.args.signer | ||
else: | ||
signer = self.ident.address | ||
|
||
channel_info = {"sender": self.ident.address, "signer": signer, "recipient": recipient, "groupId" : group_id} | ||
params = [channel_info["signer"], channel_info["recipient"], channel_info["groupId"], self.args.amount, self.args.expiration] | ||
rez = self.transact_contract_command("MultiPartyEscrow", "openChannel", params) | ||
|
||
if (len(rez[1]) != 1 or rez[1][0]["event"] != "ChannelOpen"): | ||
raise Exception("We've expected only one ChannelOpen event after openChannel. Make sure that you use correct MultiPartyEscrow address") | ||
return rez[1][0]["args"]["channelId"], channel_info | ||
|
||
def _open_init_channel_from_metadata(self, metadata): | ||
# try to initilize channel without actually open it (we check metadata and we compile .proto files) | ||
tmp_dir = tempfile.mkdtemp() | ||
shutil.rmtree(tmp_dir) | ||
self._init_channel_from_metadata(tmp_dir, metadata, {}) | ||
shutil.rmtree(tmp_dir) | ||
|
||
# open payment channel | ||
channel_id, channel_info = self._open_channel_for_service(metadata) | ||
self._printout("#channel_id") | ||
self._printout(channel_id) | ||
|
||
# initilize new channel | ||
self._init_channel_from_metadata(self._get_channel_dir(channel_id), metadata, channel_info) | ||
|
||
def open_init_channel_from_metadata(self): | ||
metadata = load_mpe_service_metadata(self.args.metadata_file) | ||
self._open_init_channel_from_metadata(metadata) | ||
|
||
def open_init_channel_from_registry(self): | ||
metadata = self._get_service_metadata_from_registry() | ||
self._open_init_channel_from_metadata(metadata) | ||
|
||
def channel_claim_timeout(self): | ||
rez = self._get_channel_state_from_blockchain(self.args.channel_id) | ||
if (rez["value"] == 0): | ||
raise Exception("Channel has 0 value. There is nothing to claim") | ||
self.transact_contract_command("MultiPartyEscrow", "channelClaimTimeout", [self.args.channel_id]) | ||
|
||
def channel_extend_and_add_funds(self): | ||
self.transact_contract_command("MultiPartyEscrow", "channelExtendAndAddFunds", [self.args.channel_id, self.args.expiration, self.args.amount]) | ||
|
||
# return list of tuples (channel_id, channel_info) | ||
def _get_all_initilized_channels(self): | ||
channels = [] | ||
for channel_dir in self._get_channel_dir(0).parent.glob("*"): | ||
if (channel_dir.name.isdigit()): | ||
channel_id = int(channel_dir.name) | ||
channel_info = self._read_channel_info(channel_id) | ||
channels.append((channel_id, channel_info)) | ||
return channels | ||
|
||
def _get_channel_state_from_blockchain(self, channel_id): | ||
abi = get_contract_def("MultiPartyEscrow") | ||
channel_abi = abi_get_element_by_name(abi, "channels") | ||
channel = self.call_contract_command("MultiPartyEscrow", "channels", [channel_id]) | ||
channel = abi_decode_struct_to_dict(channel_abi, channel) | ||
return channel | ||
|
||
def _print_channels_from_blockchain(self, channels_ids): | ||
channels_ids = sorted(channels_ids) | ||
if (self.args.only_id): | ||
self._printout("#channelId") | ||
[self._printout(str(i)) for i in channels_ids] | ||
return | ||
self._printout("#channelId nonce recipient groupId(base64) value(AGI) expiration(blocks)") | ||
for i in channels_ids: | ||
channel = self._get_channel_state_from_blockchain(i) | ||
value_agi = cogs2stragi(channel["value"]) | ||
group_id_base64 = base64.b64encode(channel["groupId"]).decode("ascii") | ||
self._printout("%i %i %s %s %s %i"%(i, channel["nonce"], channel["recipient"], group_id_base64, | ||
value_agi, channel["expiration"])) | ||
|
||
def _filter_channels_sender_signer(self, channels): | ||
good_id = [] | ||
for channel_id, channel_info in channels: | ||
not_sender = channel_info["sender"] != self.ident.address | ||
not_signer = channel_info["signer"] != self.ident.address | ||
if (self.args.filter_sender and not_sender): | ||
continue | ||
if (self.args.filter_signer and not_signer): | ||
continue | ||
if (self.args.filter_my and not_sender and not_signer): | ||
continue | ||
good_id.append(channel_id) | ||
return good_id | ||
|
||
def print_initialized_channels(self): | ||
channels = self._get_all_initilized_channels() | ||
good_ids = self._filter_channels_sender_signer(channels) | ||
self._print_channels_from_blockchain(good_ids) | ||
|
||
def print_initialized_channels_filter_group(self): | ||
channels = self._get_all_initilized_channels() | ||
metadata = self._get_service_metadata_from_registry() | ||
group_id = metadata.get_group_id(self.args.group_name) | ||
|
||
# filter channels for specific group_id | ||
channels = [(cid, cinfo) for cid, cinfo in channels if (cinfo["groupId"] == group_id)] | ||
good_ids = self._filter_channels_sender_signer(channels) | ||
self._print_channels_from_blockchain(good_ids) | ||
|
||
# function for get all filtered chanels from blockchain logs | ||
def _get_all_filtered_channels(self, argument_filters, from_block): | ||
mpe_address = self.get_mpe_address() | ||
abi = get_contract_def("MultiPartyEscrow")["abi"] | ||
contract = Contract(self.w3, mpe_address, abi) | ||
contract = contract.contract | ||
filter = contract.events.ChannelOpen.createFilter(fromBlock=from_block, argument_filters=argument_filters) | ||
events = filter.get_all_entries() | ||
return [e["args"]["channelId"] for e in events] | ||
|
||
def print_all_channels_filter_sender(self): | ||
channels_ids = self._get_all_filtered_channels({"sender":self.ident.address}, self.args.from_block) | ||
self._print_channels_from_blockchain(channels_ids) | ||
|
||
def print_all_channels_filter_recipient(self): | ||
channels_ids = self._get_all_filtered_channels({"recipient":self.ident.address}, self.args.from_block) | ||
self._print_channels_from_blockchain(channels_ids) | ||
|
||
def print_all_channels_filter_group(self): | ||
metadata = self._get_service_metadata_from_registry() | ||
group_id = metadata.get_group_id(self.args.group_name) | ||
channels_ids = self._get_all_filtered_channels({"groupId": group_id}, self.args.from_block) | ||
self._print_channels_from_blockchain(channels_ids) | ||
|
||
def print_all_channels_filter_group_sender(self): | ||
metadata = self._get_service_metadata_from_registry() | ||
group_id = metadata.get_group_id(self.args.group_name) | ||
channels_ids = self._get_all_filtered_channels({"groupId": group_id, "sender": self.ident.address}, self.args.from_block) | ||
self._print_channels_from_blockchain(channels_ids) | ||
|
||
#Auxilary functions | ||
def print_block_number(self): | ||
self._printout(self.ident.w3.eth.blockNumber) |
Oops, something went wrong.