Skip to content

Commit b9ae8db

Browse files
committed
Allow users to specify different private keys for the mpe state channel
signer and for blockchain transactions (fund, deposit, extend, etc)
1 parent f1ad43c commit b9ae8db

File tree

3 files changed

+79
-13
lines changed

3 files changed

+79
-13
lines changed

blockchain/package-lock.json

Lines changed: 43 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

snet_sdk/__init__.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ class _ClientCallDetails(
5757
"eth_rpc_endpoint": "https://kovan.infura.io",
5858
"ipfs_rpc_endpoint": "http://ipfs.singularitynet.io:80",
5959
"private_key": None,
60+
"signer_private_key": None,
6061
"account_index": 0,
6162
"default_gas": 1000000,
6263
"mpe_address": None,
63-
"token_address": None
64+
"token_address": None,
65+
"allow_transactions": False
6466
}
6567

6668

@@ -73,10 +75,12 @@ def __init__(
7375
eth_rpc_endpoint=snet_sdk_defaults["eth_rpc_endpoint"],
7476
ipfs_rpc_endpoint=snet_sdk_defaults["ipfs_rpc_endpoint"],
7577
private_key=snet_sdk_defaults["private_key"],
78+
signer_private_key=snet_sdk_defaults["signer_private_key"],
7679
account_index=snet_sdk_defaults["account_index"],
7780
default_gas=snet_sdk_defaults["default_gas"],
7881
mpe_address=snet_sdk_defaults["mpe_address"],
79-
token_address=snet_sdk_defaults["token_address"]
82+
token_address=snet_sdk_defaults["token_address"],
83+
allow_transactions=snet_sdk_defaults["allow_transactions"]
8084
):
8185
self.libraries_base_path = libraries_base_path
8286
self.default_gas = default_gas
@@ -96,6 +100,19 @@ def __init__(
96100
else: # Working with an unlocked account, for example
97101
self.address = web3.Web3.toChecksumAddress(web3.eth.accounts[account_index])
98102

103+
104+
if self.private_key is not None and signer_private_key is None:
105+
self.signer_private_key = self.private_key
106+
else:
107+
self.signer_private_key = signer_private_key
108+
109+
signer_public_key = ecdsa.SigningKey.from_string(string=self.private_key,
110+
curve=ecdsa.SECP256k1,
111+
hashfunc=hashlib.sha256).get_verifying_key()
112+
113+
self.signer_address = web3.Web3.toChecksumAddress("0x" + web3.Web3.sha3(hexstr=signer_public_key.to_string().hex())[12:].hex())
114+
115+
99116
# Instantiate Ethereum client
100117
provider = web3.HTTPProvider(eth_rpc_endpoint)
101118
self.web3 = web3.Web3(provider)
@@ -172,9 +189,9 @@ def _get_channels(self, recipient_address=None):
172189
self.logs = self.web3.eth.getLogs({"fromBlock" : self._get_contract_deployment_block("MultiPartyEscrow.json"), "address": self.mpe_contract.address, "topics": topics})
173190
event_abi = {'anonymous': False, 'inputs': [{'indexed': False, 'name': 'channelId', 'type': 'uint256'}, {'indexed': False, 'name': 'nonce', 'type': 'uint256'}, {'indexed': True, 'name': 'sender', 'type': 'address'}, {'indexed': False, 'name': 'signer', 'type': 'address'}, {'indexed': True, 'name': 'recipient', 'type': 'address'}, {'indexed': True, 'name': 'groupId', 'type': 'bytes32'}, {'indexed': False, 'name': 'amount', 'type': 'uint256'}, {'indexed': False, 'name': 'expiration', 'type': 'uint256'}], 'name': 'ChannelOpen', 'type': 'event'}
174191
if recipient_address is None:
175-
channels = list(filter(lambda channel: channel.sender == self.address, [web3.utils.events.get_event_data(event_abi, l)["args"] for l in self.logs]))
192+
channels = list(filter(lambda channel: channel.sender == self.address and channel.signer == self.signer_address, [web3.utils.events.get_event_data(event_abi, l)["args"] for l in self.logs]))
176193
else:
177-
channels = list(filter(lambda channel: channel.sender == self.address and channel.recipient == recipient_address, [web3.utils.events.get_event_data(event_abi, l)["args"] for l in self.logs]))
194+
channels = list(filter(lambda channel: channel.sender == self.address and channel.signer == self.signer_address and channel.recipient == recipient_address, [web3.utils.events.get_event_data(event_abi, l)["args"] for l in self.logs]))
178195
return channels
179196

180197

@@ -197,13 +214,13 @@ def mpe_withdraw(self, value):
197214

198215

199216
def mpe_open_channel(self, recipient_address, group_id, value, expiration):
200-
receipt = self._send_transaction(self.mpe_contract.functions.openChannel, self.address, recipient_address, group_id, value, expiration)
217+
receipt = self._send_transaction(self.mpe_contract.functions.openChannel, self.signer_address, recipient_address, group_id, value, expiration)
201218
return self._parse_receipt(receipt, self.mpe_contract.events.ChannelOpen, encoder=ChannelOpenEncoder)
202219

203220

204221
def mpe_deposit_and_open_channel(self, recipient_address, group_id, value, expiration):
205222
self._token_approve_transfer(value)
206-
receipt = self._send_transaction(self.mpe_contract.functions.depositAndOpenChannel, self.address, recipient_address, group_id, value, expiration)
223+
receipt = self._send_transaction(self.mpe_contract.functions.depositAndOpenChannel, self.signer_address, recipient_address, group_id, value, expiration)
207224
return self._parse_receipt(receipt, self.mpe_contract.events.ChannelOpen, encoder=ChannelOpenEncoder)
208225

209226

@@ -279,7 +296,7 @@ def client(self, *args, org_id=None, service_id=None, channel_id=None):
279296
default_group = web3.utils.datastructures.AttributeDict(client.metadata.groups[0])
280297
client.default_payment_address = default_group["payment_address"]
281298
default_channel_value = client.metadata.pricing["price_in_cogs"]*100
282-
default_channel_expiration = self.web3.eth.getBlock("latest").number + client.metadata.payment_expiration_threshold + (3600*24*7/self.average_block_time)
299+
default_channel_expiration = int(self.web3.eth.getBlock("latest").number + client.metadata.payment_expiration_threshold + (3600*24*7/self.average_block_time))
283300
service_endpoint = None
284301
for endpoint in client.metadata["endpoints"]:
285302
if (endpoint["group_name"] == default_group["group_name"]):
@@ -300,7 +317,7 @@ def client(self, *args, org_id=None, service_id=None, channel_id=None):
300317
def _get_channel_state(channel_id):
301318
stub = _state_service_pb2_grpc.PaymentChannelStateServiceStub(grpc_channel)
302319
message = web3.Web3.soliditySha3(["uint256"], [channel_id])
303-
signature = self.web3.eth.account.signHash(defunct_hash_message(message), self.private_key).signature
320+
signature = self.web3.eth.account.signHash(defunct_hash_message(message), self.signer_private_key).signature
304321
request = _state_service_pb2.ChannelStateRequest(channel_id=web3.Web3.toBytes(channel_id), signature=bytes(signature))
305322
response = stub.GetChannelState(request)
306323
return {
@@ -315,10 +332,16 @@ def _get_channel_states():
315332

316333
def _get_funded_channel():
317334
channel_states = _get_channel_states()
318-
if len(channel_states) != 0:
319-
return next(iter(channel_states), lambda state: state.initial_amount - state.current_signed_amount >= int(client.metadata.pricing["price_in_cogs"]))["channel_id"]
320-
else:
321-
raise RuntimeError("No usable state channel found. Please open a new channel or fund/extend an existing one")
335+
336+
if len(channel_states) == 0:
337+
if allow_transactions is False:
338+
raise RuntimeError('No state channel found. Please open a new channel or set configuration parameter "allow_transactions=True" when creating Snet class instance')
339+
else:
340+
_client_open_channel(default_channel_value, default_channel_expiration)
341+
channel_states = _get_channel_states()
342+
343+
chosen_channel = next(filter(lambda state: state["initial_amount"] - state["current_signed_amount"] >= int(client.metadata.pricing["price_in_cogs"]), iter(channel_states)), None)
344+
return chosen_channel["channel_id"]
322345

323346

324347
if _channel_id is None:
@@ -367,7 +390,7 @@ def _get_service_call_metadata(channel_id):
367390
["address", "uint256", "uint256", "uint256"],
368391
[self.mpe_contract.address, channel_id, state["current_nonce"], amount]
369392
)
370-
signature = bytes(self.web3.eth.account.signHash(defunct_hash_message(message), self.private_key).signature)
393+
signature = bytes(self.web3.eth.account.signHash(defunct_hash_message(message), self.signer_private_key).signature)
371394
metadata = [
372395
("snet-payment-type", "escrow"),
373396
("snet-payment-channel-id", str(channel_id)),

snet_sdk/resources/contracts/placeholder.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)