Skip to content

Commit

Permalink
Allow paying fees in CC and add integration test for transfer_all (#226)
Browse files Browse the repository at this point in the history
* benchmark results for transfer_all

* fmt

* fix benchmark results

* initial cc payment setup

* add cc payment to all extrinsics

* update ensure_payment

* transfer_all wip

* Implement transfer_all

* implement trasnfer_all integration test

* remove .clone().into() and fix endorse_newcomers

* refactor ensure_payment

* refactor py client

* use cc paymant in all xts

* update pallets

* fix ipfs-cid ard

* downgrade substrate

* update transfer_all test

* set python line length to 120
  • Loading branch information
pifragile authored Jun 16, 2022
1 parent 0f2c62e commit fb3b42b
Show file tree
Hide file tree
Showing 9 changed files with 400 additions and 211 deletions.
224 changes: 112 additions & 112 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ panic = 'unwind'

[workspace]
members = [
'node',
'runtime',
'client',
'client/encointer-api-client-extension',
'node',
'runtime',
'client',
'client/encointer-api-client-extension',
]

#only while debugging
Expand Down
12 changes: 11 additions & 1 deletion client/bootstrap_demo_community.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
TEST_DATA_DIR = './test-data/'
TEST_LOCATIONS_MEDITERRANEAN = 'test-locations-mediterranean.json'


def perform_meetup(client, cid):
print('Starting meetup...')
print('Creating claims...')
Expand Down Expand Up @@ -78,7 +79,7 @@ def main(ipfs_local, client, port, spec_file):

# charlie has no genesis funds
print('Faucet is dripping to Charlie...')
client.faucet([account3], is_faucet = True)
client.faucet([account3], is_faucet=True)

blocks_to_wait = 3
print(f"Waiting for {blocks_to_wait} blocks, such that xt's are processed...")
Expand Down Expand Up @@ -125,6 +126,15 @@ def main(ipfs_local, client, port, spec_file):
print("no reputation gained")
exit(1)

print(f'Transfering 0.5CC from //Alice to //Eve')
client.transfer(cid, '//Alice', '//Eve', '0.5', pay_fees_in_cc=False)

print(f'Transfering all CC from //Eve to //Ferdie')
client.transfer_all(cid, '//Eve', '//Ferdie', pay_fees_in_cc=True)
if client.balance('//Eve', cid=cid) > 0 or client.balance('//Ferdie', cid=cid) == 0:
print("transfer_all failed")
exit(1)

print("tests passed")


Expand Down
118 changes: 64 additions & 54 deletions client/py_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

DEFAULT_CLIENT = '../target/release/encointer-client-notee'


class Error(Exception):
"""Base class for exceptions in this module."""
pass
Expand Down Expand Up @@ -41,6 +42,7 @@ def ensure_clean_exit(returncode):
raise ParticipantAlreadyLinked
raise UnknownError


class Client:
def __init__(self,
node_url=None,
Expand All @@ -51,7 +53,8 @@ def __init__(self,
try:
rust_client = os.environ['ENCOINTER_CLIENT']
except:
print(f"didn't find ENCOINTER_CLIENT in env variables nor arguments, setting client to {DEFAULT_CLIENT}")
print(
f"didn't find ENCOINTER_CLIENT in env variables nor arguments, setting client to {DEFAULT_CLIENT}")
rust_client = DEFAULT_CLIENT

if node_url:
Expand All @@ -61,12 +64,20 @@ def __init__(self,
print("connecting to local chain")
self.cli = [rust_client, '-p', str(port)]

def next_phase(self):
ret = subprocess.run(self.cli + ["next-phase"])
def run_cli_command(self, command, cid=None, pay_fees_in_cc=False, ipfs_cid=None, **kwargs):
cid_part = ["--cid", cid] if cid else []
fee_part = ["--tx-payment-cid", cid] if pay_fees_in_cc else []
ipfs_cid_part = ["--ipfs-cid", ipfs_cid] if ipfs_cid else []
command = self.cli + cid_part + fee_part + command + ipfs_cid_part
ret = subprocess.run(command, stdout=subprocess.PIPE, **kwargs)
return ret

def next_phase(self, pay_fees_in_cc=False):
ret = self.run_cli_command(["next-phase"], pay_fees_in_cc=pay_fees_in_cc)
ensure_clean_exit(ret.returncode)

def get_phase(self):
ret = subprocess.run(self.cli + ["get-phase"], stdout=subprocess.PIPE)
ret = self.run_cli_command(["get-phase"])
return ret.stdout.strip().decode("utf-8")

def go_to_phase(self, phase):
Expand All @@ -81,71 +92,68 @@ def go_to_phase(self, phase):
self.next_phase()

def list_accounts(self):
ret = subprocess.run(self.cli + ["list-accounts"], stdout=subprocess.PIPE)
ret = self.run_cli_command(["list-accounts"])
return ret.stdout.decode("utf-8").splitlines()

def new_account(self):
ret = subprocess.run(self.cli + ["new-account"], stdout=subprocess.PIPE)
ret = self.run_cli_command(["new-account"])
return ret.stdout.decode("utf-8").strip()

def create_accounts(self, amount):
return [self.new_account() for _ in range(0, amount)]

def faucet(self, accounts, faucet_url='http://localhost:5000/api', is_faucet=False):
def faucet(self, accounts, faucet_url='http://localhost:5000/api', is_faucet=False, pay_fees_in_cc=False):
if is_faucet:
self.await_block(1)
ret = subprocess.run(self.cli + ['faucet'] + accounts, check=True, timeout=2, stdout=subprocess.PIPE)
ret = self.run_cli_command(
['faucet'] + accounts, pay_fees_in_cc=pay_fees_in_cc, check=True, timeout=2)
print(ret.stdout.decode("utf-8"))
ensure_clean_exit(ret.returncode)
else:
payload = {'accounts': accounts}
requests.get(faucet_url, params=payload)


def balance(self, account, cid=None):
if not cid:
ret = subprocess.run(self.cli + ["balance", account], stdout=subprocess.PIPE)
return float(ret.stdout.strip().decode("utf-8").split(' ')[-1])
else:
ret = subprocess.run(self.cli + ["--cid", cid, "balance", account], stdout=subprocess.PIPE)
return float(ret.stdout.strip().decode("utf-8").split(' ')[-1])
ret = self.run_cli_command(["balance", account], cid=cid)
return float(ret.stdout.strip().decode("utf-8").split(' ')[-1])

def reputation(self, account):
ret = subprocess.run(self.cli + ["reputation", account], stdout=subprocess.PIPE)
ret = self.run_cli_command(["reputation", account])
ensure_clean_exit(ret.returncode)
reputation_history = []
lines = ret.stdout.decode("utf-8").splitlines()
while len(lines) > 0:
(cindex, cid, rep) = lines.pop(0).split(',')
reputation_history.append((cindex, cid, rep.strip().split('::')[1]))
reputation_history.append(
(cindex, cid, rep.strip().split('::')[1]))
return reputation_history

def new_community(self, specfile):
ret = subprocess.run(self.cli + ["new-community", specfile], stdout=subprocess.PIPE)
def new_community(self, specfile, pay_fees_in_cc=False):
ret = self.run_cli_command(["new-community", specfile], pay_fees_in_cc=pay_fees_in_cc)
ensure_clean_exit(ret.returncode)
return ret.stdout.decode("utf-8").strip()

def list_communities(self):
ret = subprocess.run(self.cli + ["list-communities"], stdout=subprocess.PIPE)
ret = self.run_cli_command(["list-communities"])
return ret.stdout.decode("utf-8").strip()

def await_block(self, amount=1):
subprocess.run(self.cli + ["listen", "-b", str(amount)], stdout=subprocess.PIPE)
self.run_cli_command(["listen", "-b", str(amount)])

def list_participants(self, cid):
ret = subprocess.run(self.cli + ["--cid", cid, "list-participants"], stdout=subprocess.PIPE)
ret = self.run_cli_command(["list-participants"], cid=cid)
return ret.stdout.decode("utf-8").strip()

def register_participant(self, account, cid):
ret = subprocess.run(self.cli + ["--cid", cid, "register-participant", account], stdout=subprocess.PIPE)
def register_participant(self, account, cid, pay_fees_in_cc=False):
ret = self.run_cli_command(["register-participant", account], cid, pay_fees_in_cc)
ensure_clean_exit(ret.returncode)

def new_claim(self, account, vote, cid):
ret = subprocess.run(self.cli + ["--cid", cid, "new-claim", account, str(vote)], stdout=subprocess.PIPE)
def new_claim(self, account, vote, cid, pay_fees_in_cc=False):
ret = self.run_cli_command(["new-claim", account, str(vote)], cid=cid)
return ret.stdout.decode("utf-8").strip()

def list_meetups(self, cid):
ret = subprocess.run(self.cli + ["--cid", cid, "list-meetups"], stdout=subprocess.PIPE)
ret = self.run_cli_command(["list-meetups"], cid)
# print(ret.stdout.decode("utf-8"))
meetups = []
lines = ret.stdout.decode("utf-8").splitlines()
Expand All @@ -160,60 +168,62 @@ def list_meetups(self, cid):
meetups.append(participants)
return meetups

def attest_claims(self, account, claims):
ret = subprocess.run(self.cli + ["attest-claims", account] + claims, stdout=subprocess.PIPE)
def attest_claims(self, account, claims, pay_fees_in_cc=False):
ret = self.run_cli_command(["attest-claims", account] + claims, pay_fees_in_cc=pay_fees_in_cc)
ensure_clean_exit(ret.returncode)

def list_attestees(self, cid):
ret = subprocess.run(self.cli + ["--cid", cid, "list-attestees"], stdout=subprocess.PIPE)
ret = self.run_cli_command(["list-attestees"], cid=cid)
return ret.stdout.decode("utf-8").strip()

def claim_reward(self, account, cid):
ret = subprocess.run(self.cli + ["--cid", cid, "claim-reward", account], stdout=subprocess.PIPE)
def claim_reward(self, account, cid, pay_fees_in_cc=False):
ret = self.run_cli_command(["claim-reward", account], cid, pay_fees_in_cc)
return ret.stdout.decode("utf-8").strip()

def create_business(self, account, cid, ipfs_cid):
ret = subprocess.run(self.cli + ["--cid", cid, "create-business", account, "--ipfs-cid", ipfs_cid],
stdout=subprocess.PIPE)
def create_business(self, account, cid, ipfs_cid, pay_fees_in_cc=False):
ret = self.run_cli_command(["create-business", account], cid, pay_fees_in_cc, ipfs_cid)
ensure_clean_exit(ret.returncode)
return ret.stdout.decode("utf-8").strip()

def update_business(self, account, cid, ipfs_cd):
def update_business(self, account, cid, ipfs_cid, pay_fees_in_cc=False):
""" Update has not been tested """
ret = subprocess.run(self.cli + ["--cid", cid, "update-business", account, "--ipfs-cid", ipfs_cd],
stdout=subprocess.PIPE)
ret = self.run_cli_command(["update-business", account], cid, pay_fees_in_cc, ipfs_cid)
ensure_clean_exit(ret.returncode)
return ret.stdout.decode("utf-8").strip()

def create_offering(self, account, cid, ipfs_cd):
ret = subprocess.run(self.cli + ["--cid", cid, "create-offering", account, "--ipfs-cid", ipfs_cd],
stdout=subprocess.PIPE)
def create_offering(self, account, cid, ipfs_cid, pay_fees_in_cc=False):
ret = self.run_cli_command(["create-offering", account], cid, pay_fees_in_cc, ipfs_cid)
ensure_clean_exit(ret.returncode)
return ret.stdout.decode("utf-8").strip()

def list_businesses(self, cid):
ret = subprocess.run(self.cli + ["--cid", cid, "list-businesses"],
stdout=subprocess.PIPE)
ret = self.run_cli_command(["list-businesses"], cid=cid)
return ret.stdout.decode("utf-8").strip()

def list_offerings(self, cid):
ret = subprocess.run(self.cli + ["--cid", cid, "list-offerings"],
stdout=subprocess.PIPE)
ret = self.run_cli_command(["list-offerings"], cid=cid)
return ret.stdout.decode("utf-8").strip()

def list_offerings_for_business(self, cid, account):
ret = subprocess.run(self.cli + ["--cid", cid, "list-business-offerings", account],
stdout=subprocess.PIPE)
ret = self.run_cli_command(["list-business-offerings", account], cid=cid)
return ret.stdout.decode("utf-8").strip()

def endorse_newcomers(self, cid, endorser, endorsees):
ret = subprocess.run(self.cli +
["endorse-newcomers", "--cid", cid, endorser, "--endorsees"] +
endorsees, # must be separate to append a list of args to the cli
stdout=subprocess.PIPE)
def endorse_newcomers(self, cid, endorser, endorsees, pay_fees_in_cc=False):
ret = self.run_cli_command(
["endorse-newcomers", endorser, "--endorsees"] +
endorsees, # must be separate to append a list of args to the cli
cid,
pay_fees_in_cc)
return ret.stdout.decode("utf-8").strip()

def get_bootstrappers_with_remaining_newbie_tickets(self, cid):
ret = subprocess.run(self.cli + ["get-bootstrappers-with-remaining-newbie-tickets", "--cid", cid],
stdout=subprocess.PIPE)
ret = self.run_cli_command(["get-bootstrappers-with-remaining-newbie-tickets"], cid=cid)
return ret.stdout.decode("utf-8").strip()

def transfer_all(self, cid, source, dest, pay_fees_in_cc=False):
ret = self.run_cli_command(["transfer_all", source, dest], cid, pay_fees_in_cc)
return ret.stdout.decode("utf-8").strip()

def transfer(self, cid, source, dest, amount, pay_fees_in_cc=False):
ret = self.run_cli_command(["transfer", source, dest, amount], cid, pay_fees_in_cc)
return ret.stdout.decode("utf-8").strip()
17 changes: 17 additions & 0 deletions client/src/cli_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const TO_CINDEX_ARG: &'static str = "to-cindex";
const ENDORSEES_ARG: &'static str = "endorsees";
const TIME_OFFSET_ARG: &'static str = "time-offset";
const ALL_FLAG: &'static str = "all";
const TX_PAYMENT_CID_ARG: &'static str = "tx-payment-cid";

pub trait EncointerArgs<'b> {
fn account_arg(self) -> Self;
Expand All @@ -28,6 +29,7 @@ pub trait EncointerArgs<'b> {
fn endorsees_arg(self) -> Self;
fn time_offset_arg(self) -> Self;
fn all_flag(self) -> Self;
fn tx_payment_cid_arg(self) -> Self;
}

pub trait EncointerArgsExtractor {
Expand All @@ -44,6 +46,7 @@ pub trait EncointerArgsExtractor {
fn endorsees_arg(&self) -> Option<Vec<&str>>;
fn time_offset_arg(&self) -> Option<i32>;
fn all_flag(&self) -> bool;
fn tx_payment_cid_arg(&self) -> Option<&str>;
}

impl<'a, 'b> EncointerArgs<'b> for App<'a, 'b> {
Expand Down Expand Up @@ -182,6 +185,17 @@ impl<'a, 'b> EncointerArgs<'b> for App<'a, 'b> {
.help("list all community currency balances for account"),
)
}
fn tx_payment_cid_arg(self) -> Self {
self.arg(
Arg::with_name(TX_PAYMENT_CID_ARG)
.long("tx-payment-cid")
.global(true)
.takes_value(true)
.required(false)
.value_name("STRING")
.help("cid of the community currency in which tx fees should be paid"),
)
}
}

impl<'a> EncointerArgsExtractor for ArgMatches<'a> {
Expand Down Expand Up @@ -234,4 +248,7 @@ impl<'a> EncointerArgsExtractor for ArgMatches<'a> {
fn all_flag(&self) -> bool {
self.is_present(ALL_FLAG)
}
fn tx_payment_cid_arg(&self) -> Option<&str> {
self.value_of(TX_PAYMENT_CID_ARG)
}
}
Loading

0 comments on commit fb3b42b

Please sign in to comment.