From 3b11292e72e0b796ac7fe7fef1e9462bf40ddb0a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 1 Apr 2022 14:43:33 +1030 Subject: [PATCH] pyln-testing: add new schema types. These are useful for requests: 1. "outpoint": : 2. "feerate": strings or a number 3. "outputdesc": bitcoin-style addresses-as-keys 4. "msat_or_all": amount or "all" 4. "msat_or_any": amount or "any" 5. "short_channel_id_dir": scid with /0 or /1. Signed-off-by: Rusty Russell --- contrib/pyln-testing/pyln/testing/fixtures.py | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/contrib/pyln-testing/pyln/testing/fixtures.py b/contrib/pyln-testing/pyln/testing/fixtures.py index 8742bf727..9d55a4a00 100644 --- a/contrib/pyln-testing/pyln/testing/fixtures.py +++ b/contrib/pyln-testing/pyln/testing/fixtures.py @@ -266,6 +266,48 @@ def _extra_validator(): and txnum >= 0 and txnum < 2**24 and outnum >= 0 and outnum < 2**16) + def is_short_channel_id_dir(checker, instance): + """Short channel id with direction""" + if not checker.is_type(instance, "string"): + return False + if not instance.endswith("/0") and not instance.endswith("/1"): + return False + return is_short_channel_id(checker, instance[:-2]) + + def is_outpoint(checker, instance): + """Outpoint: txid and outnum""" + if not checker.is_type(instance, "string"): + return False + parts = instance.split(":") + if len(parts) != 2: + return False + if len(parts[0]) != 64 or any(c not in string.hexdigits for c in parts[0]): + return False + try: + outnum = int(parts[1]) + except ValueError: + return False + return outnum < 2**32 + + def is_feerate(checker, instance): + """feerate string or number (optionally ending in perkw/perkb)""" + if checker.is_type(instance, "integer"): + return True + if not checker.is_type(instance, "string"): + return False + if instance in ("urgent", "normal", "slow"): + return True + if instance in ("opening", "mutual_close", "unilateral_close", "delayed_to_us", "htlc_resolution", "penalty", "min_acceptable", "max_acceptable"): + return True + if not instance.endswith("perkw") and not instance.endswith("perkb"): + return False + + try: + int(instance.rpartition("per")[0]) + except ValueError: + return False + return True + def is_pubkey(checker, instance): """SEC1 encoded compressed pubkey""" if not checker.is_type(instance, "hex"): @@ -308,6 +350,30 @@ def _extra_validator(): return False return len(instance) == 64 + def is_outputdesc(checker, instance): + """Bitcoin-style output object, keys = destination, values = amount""" + if not checker.is_type(instance, "object"): + return False + for k, v in instance.items(): + if not checker.is_type(k, "string"): + return False + if v != "all": + if not is_msat_request(checker, v): + return False + return True + + def is_msat_or_all(checker, instance): + """msat field, or 'all'""" + if instance == "all": + return True + return is_msat_request(checker, instance) + + def is_msat_or_any(checker, instance): + """msat field, or 'any'""" + if instance == "any": + return True + return is_msat_request(checker, instance) + type_checker = jsonschema.Draft7Validator.TYPE_CHECKER.redefine_many({ "hex": is_hex, "u64": is_u64, @@ -316,11 +382,17 @@ def _extra_validator(): "u8": is_u8, "pubkey": is_pubkey, "msat": is_msat, + "msat_or_all": is_msat_or_all, + "msat_or_any": is_msat_or_any, "txid": is_txid, "signature": is_signature, "bip340sig": is_bip340sig, "point32": is_point32, "short_channel_id": is_short_channel_id, + "short_channel_id_dir": is_short_channel_id_dir, + "outpoint": is_outpoint, + "feerate": is_feerate, + "outputdesc": is_outputdesc, }) return jsonschema.validators.extend(jsonschema.Draft7Validator,