Skip to content

Commit

Permalink
console
Browse files Browse the repository at this point in the history
  • Loading branch information
youwenbusi committed Jul 28, 2020
1 parent 2ff25c4 commit 0a95beb
Show file tree
Hide file tree
Showing 10 changed files with 604 additions and 52 deletions.
2 changes: 1 addition & 1 deletion commands/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
#INSTANCE_FILE_DEFAULT = "zeth-instance.json"
#ETH_ADDRESS_DEFAULT = "eth-address"

WALLET_DIR_DEFAULT = "./wallet"
WALLET_DIR_DEFAULT = "wallet"
WALLET_USERNAME = "zbac"
USER_DIR = "user"
136 changes: 136 additions & 0 deletions commands/event_sync.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import sys
from python_web3.client.bcosclient import BcosClient
from python_web3.client.datatype_parser import DatatypeParser
from python_web3.client.contractnote import ContractNote
import json
import time
from python_web3.client.channel_push_dispatcher import ChannelPushHandler
from python_web3.client.event_callback import BcosEventCallback
from python_web3.client.event_callback import EventCallbackHandler
from click import command, argument, option, pass_context, ClickException, Context
from zeth.contracts import _event_args_to_mix_result
import os
from commands.constants import WALLET_USERNAME, FISCO_ADDRESS_FILE, USER_DIR, ADDRESS_FILE_DEFAULT, WALLET_DIR_DEFAULT
from click import command, argument, option, pass_context, ClickException, Context
from zeth.wallet import Wallet, ZethNoteDescription
from commands.utils import load_zeth_address
from typing import List
'''
def usage():
usagetext = '\nUsage:\nparams: contractname address event_name indexed\n' \
'\t1. contractname :\t合约的文件名,不需要带sol后缀,默认在当前目录的contracts目录下\n' \
'\t2. address :\t十六进制的合约地址,或者可以为:last,表示采用bin/contract.ini里的记录\n' \
'\t3. event_name :\t可选,如不设置监听所有事件 \n' \
'\t4. indexed :\t可选,根据event定义里的indexed字段,作为过滤条件)\n\n'
usagetext = usagetext + "\teg: for contract sample [contracts/HelloEvent.sol], use cmdline:\n\n"
usagetext = usagetext + "\tpython demo_event_callback.py HelloEvent last \n"
usagetext = usagetext + "\t--listen all event at all indexed : \n\n"
usagetext = usagetext + "\tpython demo_event_callback.py HelloEvent last on_set \n"
usagetext = usagetext + "\t--listen event on_set(string newname) (no indexed): \n\n"
usagetext = usagetext + \
"\tpython demo_event_callback.py HelloEvent last on_number 5\n"
usagetext = usagetext + \
"\t--listen event on_number(string name,int indexed age), age ONLY 5 : \n"
usagetext = usagetext + "\n...(and other events)"
print(usagetext)
'''

class LogMixEvent(object):
def __init__(
self,
root: bytes,
nullifiers: bytes(2),
commitments: bytes(2),
ciphertexts: bytes(2)):
self.root = root
self.nullifiers = nullifiers
self.commitments = commitments
self.ciphertexts = ciphertexts

def make_wallet() -> List[Wallet]:
'''
Return all the wallet in local server
'''
wallet_list = []
for username in os.listdir(USER_DIR):
wallet_dir = "{}/{}/{}".format(USER_DIR, username, WALLET_DIR_DEFAULT)
if os.path.exists(wallet_dir) is False:
raise ClickException(f"invalid wallet_dir: {wallet_dir}")
zeth_address = load_zeth_address(username)
wallet_list.append(Wallet(None, username, wallet_dir, zeth_address.addr_sk))
return wallet_list

class EventCallbackImpl(EventCallbackHandler):
"""sample event push handler for application level,
user can make a class base on "ChannelPushHandler" ,implement the on_push interface
handle the message from nodes,message in ChannelPack type #see client/channelpack.py
EVENT_LOG_PUSH type is 0x1002
message in pack.data decode by utf-8
EVENT_LOG format see https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/sdk/java_sdk.html#id19
"""
abiparser: DatatypeParser = None

def on_event(self, eventdata):
logresult = self.abiparser.parse_event_logs(eventdata["logs"])
print("--------------------EventCallbackImpl--------------------\n")
logMix = logresult[0]['eventdata']
logMixEvent = LogMixEvent(logMix[0],logMix[1], logMix[2], logMix[3])
mix_result = _event_args_to_mix_result(logMixEvent)
new_merkle_root = mix_result.new_merkle_root
print("new_merkle_root in log: ", new_merkle_root)
for wallet in make_wallet():
received_notes = wallet.receive_notes(mix_result.output_events)
print(f"{wallet.username} received notes: {received_notes}")
wallet.update_and_save_state()
update_merkle_root = wallet.merkle_tree.get_root()
print(f"The update_merkle_root in wallet of {wallet.username} is {update_merkle_root}")


@command()
@option("--mixer-addr", help="The Groth16Mixer contract address you want to listen")
def event_sync(mixer_addr: str):

indexed_value = None
try:
bcos_event = BcosEventCallback()
bcos_event.setclient(BcosClient())
print(bcos_event.client.getinfo())
'''
print("usage input {},{},{},{}".format(contractname, address, event_name, indexed_value))
if address == "last":
cn = ContractNote()
address = cn.get_last(contractname)
print("hex address :", address)
'''
abifile = "contract/Groth16Mixer.abi"
abiparser = DatatypeParser(abifile)
eventcallback = EventCallbackImpl()
eventcallback.abiparser = abiparser

result = bcos_event.register_eventlog_filter(
eventcallback, abiparser, [mixer_addr], "LogMix", indexed_value)
#result = bcos_event.register_eventlog_filter(eventcallback02,abiparser, [address], "on_number")

print(
"after register LogMix,result:{},all:{}".format(
result['result'], result))

while True:
print("waiting event...")
time.sleep(10)
except Exception as e:
print("Exception!")
import traceback
traceback.print_exc()
finally:
print("event callback finished!")
if bcos_event.client is not None:
bcos_event.client.finish()
sys.exit(-1)


if __name__ == "__main__":
event_sync()
56 changes: 27 additions & 29 deletions commands/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# SPDX-License-Identifier: LGPL-3.0+

from __future__ import annotations
from commands.constants import WALLET_USERNAME
from commands.constants import WALLET_USERNAME, FISCO_ADDRESS_FILE, USER_DIR, ADDRESS_FILE_DEFAULT, WALLET_DIR_DEFAULT
from zeth.zeth_address import ZethAddressPub, ZethAddressPriv, ZethAddress
from zeth.contracts import \
get_mix_results
Expand All @@ -18,7 +18,7 @@
#from web3 import Web3 # type: ignore
from contract.Groth16Mixer import Groth16Mixer
from contract.ERC20Mintable import ERC20Mintable

from python_web3.eth_account.account import Account
from python_web3.client.bcoskeypair import BcosKeyPair #todo


Expand Down Expand Up @@ -111,15 +111,16 @@ def load_mixer_description_from_ctx(ctx: ClientConfig) -> MixerDescription:
return load_mixer_description(ctx.instance_file)
'''

def get_zeth_address_file(ctx: ClientConfig) -> str:
return ctx.address_file
def get_zeth_address_file(username: str) -> str:
addr_file = "{}/{}/{}".format(USER_DIR, username, ADDRESS_FILE_DEFAULT)
return addr_file


def load_zeth_address_public(ctx: ClientConfig) -> ZethAddressPub:
def load_zeth_address_public(username: str) -> ZethAddressPub:
"""
Load a ZethAddressPub from a key file.
"""
secret_key_file = get_zeth_address_file(ctx)
secret_key_file = get_zeth_address_file(username)
pub_addr_file = pub_address_file(secret_key_file)
with open(pub_addr_file, "r") as pub_addr_f:
return ZethAddressPub.parse(pub_addr_f.read())
Expand All @@ -134,11 +135,11 @@ def write_zeth_address_public(
pub_addr_f.write(str(pub_addr))


def load_zeth_address_secret(ctx: ClientConfig) -> ZethAddressPriv:
def load_zeth_address_secret(username: str) -> ZethAddressPriv:
"""
Read ZethAddressPriv
"""
addr_file = get_zeth_address_file(ctx)
addr_file = get_zeth_address_file(username)
with open(addr_file, "r") as addr_f:
return ZethAddressPriv.from_json(addr_f.read())

Expand All @@ -152,32 +153,31 @@ def write_zeth_address_secret(
addr_f.write(secret_addr.to_json())


def load_zeth_address(ctx: ClientConfig) -> ZethAddress:
def load_zeth_address(username: str) -> ZethAddress:
"""
Load a ZethAddress secret from a file, and the associated public address,
and return as a ZethAddress.
"""
return ZethAddress.from_secret_public(
load_zeth_address_secret(ctx),
load_zeth_address_public(ctx))
load_zeth_address_secret(username),
load_zeth_address_public(username))


def open_wallet(
mixer_instance: Any,
js_secret: ZethAddressPriv,
ctx: ClientConfig) -> Wallet:
username: str
) -> Wallet:
"""
Load a wallet using a secret key.
"""
wallet_dir = ctx.wallet_dir
wallet_dir = "{}/{}/{}".format(USER_DIR, username, WALLET_DIR_DEFAULT)
return Wallet(mixer_instance, WALLET_USERNAME, wallet_dir, js_secret)


def do_sync(
#web3: Any,
wallet: Wallet,
receipt: Any,
#wait_tx: Optional[str],
callback: Optional[Callable[[ZethNoteDescription], None]] = None) -> int:
"""
Implementation of sync, reused by several commands. Returns the
Expand All @@ -192,16 +192,15 @@ def _do_sync() -> int:

#print(f"SYNCHING blocks ({wallet_next_block} - {chain_block_number})")
mixer_instance = wallet.mixer_instance
for mix_result in get_mix_results(
mixer_instance, receipt):
new_merkle_root = mix_result.new_merkle_root
for note_desc in wallet.receive_notes(mix_result.output_events):
if callback:
callback(note_desc)
mix_result = get_mix_results(mixer_instance, receipt)
new_merkle_root = mix_result.new_merkle_root
for note_desc in wallet.receive_notes(mix_result.output_events):
if callback:
callback(note_desc)

spent_commits = wallet.mark_nullifiers_used(mix_result.nullifiers)
for commit in spent_commits:
print(f" SPENT: {commit}")
spent_commits = wallet.mark_nullifiers_used(mix_result.nullifiers)
for commit in spent_commits:
print(f" SPENT: {commit}")

wallet.update_and_save_state()

Expand Down Expand Up @@ -258,16 +257,15 @@ def create_mixer_client(ctx: ClientConfig) -> MixerClient:
'''

def create_zeth_client_and_mixer_desc(
ctx: ClientConfig, mixer_addr: str, password: str) -> Tuple[MixerClient, MixerDescription]:
prover_server_endpoint: str, mixer_addr: str, username: str, password: str) -> Tuple[MixerClient, MixerDescription]:
"""
Create a MixerClient and MixerDescription object, for an existing deployment.
"""
#web3 = open_web3_from_ctx(ctx)
#mixer_desc = load_mixer_description_from_ctx(ctx)
mixer_instance = Groth16Mixer(mixer_addr)
keystore_file = "pyaccount.keystore"
mixer_instance.client.keystore_file = "pyaccount.keystore"
if os.path.exists(keystore_file) is False:
keystore_file = "{}/{}/{}".format(USER_DIR, username, FISCO_ADDRESS_FILE)
if exists(keystore_file) is False:
raise ClickException(f"invalid output spec: {keystore_file}")
with open(keystore_file, "r") as dump_f:
keytext = json.load(dump_f)
Expand All @@ -279,7 +277,7 @@ def create_zeth_client_and_mixer_desc(
keypair.address = mixer_instance.client.ecdsa_account.address
mixer_instance.client.keypair = keypair
zeth_client = MixerClient.open(
ctx.prover_server_endpoint, mixer_instance)
prover_server_endpoint, mixer_instance)
return (zeth_client)


Expand Down
74 changes: 74 additions & 0 deletions commands/zeth_deposit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright (c) 2015-2020 Clearmatics Technologies Ltd
#
# SPDX-License-Identifier: LGPL-3.0+

from commands.utils import create_zeth_client_and_mixer_desc, \
load_zeth_address, open_wallet, parse_output, do_sync
from zeth.constants import JS_INPUTS, JS_OUTPUTS
from commands.constants import PROVER_SERVER_ENDPOINT_DEFAULT
from zeth.mixer_client import ZethAddressPub
from zeth.utils import EtherValue, from_zeth_units
from api.zeth_messages_pb2 import ZethNote
from click import command, option, pass_context, ClickException, Context
from typing import List, Tuple, Optional
import sys
sys.path.append('../')
from contract.Groth16Mixer import Groth16Mixer
from python_web3.eth_account.account import Account

@command()
@option("--mixer-addr", help="The Groth16Mixer contract address you want to use")
@option("--username", help="The account you want to use")
@option("--password", help="the password of you keystore")
@option("--vin", default="0", help="public in value")
@option("--out", "output_specs", multiple=True, help="<receiver_pub_key>,<value>")
def deposit(
mixer_addr: str,
username: str,
password: str,
vin: str,
output_specs: List[str]
) -> None:
"""
Generic mix function
"""
# Some sanity checks
if len(output_specs) > JS_OUTPUTS:
raise ClickException(f"too many outputs (max {JS_OUTPUTS})")

print(f"vin = {vin}")

vin_pub = EtherValue(vin)
zeth_client = create_zeth_client_and_mixer_desc(PROVER_SERVER_ENDPOINT_DEFAULT, mixer_addr, username, password)

zeth_address = load_zeth_address(username)
wallet = open_wallet(
zeth_client.mixer_instance, zeth_address.addr_sk, username)

outputs: List[Tuple[ZethAddressPub, EtherValue]] = [
parse_output(out_spec) for out_spec in output_specs]

# Compute input and output value total and check that they match
output_note_sum = sum([value for _, value in outputs], EtherValue(0))
if vin_pub != output_note_sum:
raise ClickException("input and output value mismatch")

#eth_address = load_eth_address(eth_addr)
fisco_bcos_address = zeth_client.mixer_instance.client.ecdsa_account.address
# If instance uses an ERC20 token, tx_value can be 0 not default vin_pub.
tx_value: Optional[EtherValue] = EtherValue(0)
#if mixer_desc.token:
# tx_value = EtherValue(0)

(outputresult, receipt) = zeth_client.deposit(
wallet.merkle_tree,
zeth_address,
fisco_bcos_address,
vin_pub,
outputs,
tx_value)

print("receipt output :", outputresult)
#do_sync(wallet, receipt)
if __name__ == '__main__':
deposit()
Loading

0 comments on commit 0a95beb

Please sign in to comment.