Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repos auto update #29

Merged
merged 9 commits into from
Dec 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 130 additions & 69 deletions README.md

Large diffs are not rendered by default.

67 changes: 53 additions & 14 deletions aquarium.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,22 @@
EXECUTOR_WORKERS,
LOG_LEVEL,
DEBUG_GUI,
REVAULTD_PATH,
)


BASE_DIR = os.getenv("BASE_DIR", os.path.abspath("demo"))
SRC_DIR = os.getenv("SRC_DIR", os.path.abspath("src"))
COORDINATORD_SRC_DIR = os.path.join(SRC_DIR, "coordinatord")
COSIGNERD_SRC_DIR = os.path.join(SRC_DIR, "cosignerd")
MIRADORD_SRC_DIR = os.path.join(SRC_DIR, "miradord")
REVAULTD_SRC_DIR = os.path.join(SRC_DIR, "revaultd")
REVAULT_GUI_SRC_DIR = os.path.join(SRC_DIR, "revault-gui")
SHELL = os.getenv("SHELL", "bash")
COORDINATORD_VERSION = os.getenv("COORDINATORD_VERSION", "master")
COSIGNERD_VERSION = os.getenv("COSIGNERD_VERSION", "master")
MIRADORD_VERSION = os.getenv("MIRADORD_VERSION", "master")
REVAULTD_VERSION = os.getenv("REVAULTD_VERSION", "master")
REVAULT_GUI_VERSION = os.getenv("REVAULT_GUI_VERSION", "gethistory")
REVAULT_GUI_VERSION = os.getenv("REVAULT_GUI_VERSION", "master")
WITH_GUI = os.getenv("WITH_GUI", "1") == "1"
WITH_ALL_HWS = os.getenv("WITH_ALL_HWS", "0") == "1"

Expand Down Expand Up @@ -67,13 +68,14 @@ def build_src(src_dir, version, git_url):
os.makedirs(SRC_DIR)
subprocess.check_call(["git", "-C", f"{SRC_DIR}", "clone", git_url])

subprocess.check_call(["git", "-C", f"{src_dir}", "checkout", version])
subprocess.check_call(["git", "-C", f"{src_dir}", "fetch", "origin", version])
subprocess.check_call(["git", "-C", f"{src_dir}", "checkout", f"origin/{version}"])
subprocess.check_call(
["cargo", "build", "--manifest-path", f"{src_dir}/Cargo.toml"]
)


def build_all_binaries(build_cosig):
def build_all_binaries(build_cosig, build_wt):
logging.info(
f"Building coordinatord at '{COORDINATORD_VERSION}' in '{COORDINATORD_SRC_DIR}'"
)
Expand All @@ -91,7 +93,15 @@ def build_all_binaries(build_cosig):
COSIGNERD_SRC_DIR, COSIGNERD_VERSION, "https://github.com/revault/cosignerd"
)

logging.info(f"Building cosignerd at '{REVAULTD_VERSION}' in '{REVAULTD_SRC_DIR}'")
if build_wt:
logging.info(
f"Building miradord at '{MIRADORD_VERSION}' in '{MIRADORD_SRC_DIR}'"
)
build_src(
MIRADORD_SRC_DIR, MIRADORD_VERSION, "https://github.com/revault/miradord"
)

logging.info(f"Building revaultd at '{REVAULTD_VERSION}' in '{REVAULTD_SRC_DIR}'")
build_src(REVAULTD_SRC_DIR, REVAULTD_VERSION, "https://github.com/revault/revaultd")

if WITH_GUI:
Expand All @@ -102,10 +112,10 @@ def build_all_binaries(build_cosig):
build_src(
REVAULT_GUI_SRC_DIR,
REVAULT_GUI_VERSION,
"https://github.com/edouardparis/revault-gui",
"https://github.com/revault/revault-gui",
)

logging.info(f"Building revault-gui's dummysigner")
logging.info("Building revault-gui's dummysigner")
subprocess.check_call(
[
"cargo",
Expand All @@ -131,7 +141,11 @@ def bitcoind():
return bitcoind


def deploy(n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False):
def deploy(
n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False, policies=[]
):
with_wts = len(policies) > 0

if not POSTGRES_IS_SETUP:
logging.error("I need the Postgres environment variable to be set.")
print("Example:")
Expand Down Expand Up @@ -160,6 +174,11 @@ def deploy(n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False):
logging.error("Invalid managers threshold")
sys.exit(1)

for p in policies:
if not os.path.isfile(p):
logging.error(f"No plugin at '{p}'")
sys.exit(1)

if os.path.isdir(BASE_DIR):
logging.warning("Base directory exists already")
resp = input(f"Remove non-empty '{BASE_DIR}' and start fresh? (y/n) ")
Expand All @@ -170,7 +189,7 @@ def deploy(n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False):
sys.exit(1)

logging.info("Checking the source directories..")
build_all_binaries(with_cosigs)
build_all_binaries(build_cosig=with_cosigs, build_wt=with_wts)

logging.info("Setting up bitcoind")
bd = bitcoind()
Expand All @@ -192,6 +211,9 @@ def deploy(n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False):
test_framework.cosignerd.COSIGNERD_PATH = os.path.join(
COSIGNERD_SRC_DIR, "target", "debug", "cosignerd"
)
test_framework.miradord.MIRADORD_PATH = os.path.join(
MIRADORD_SRC_DIR, "target", "debug", "miradord"
)
rn = RevaultNetwork(
BASE_DIR,
bd,
Expand All @@ -206,10 +228,16 @@ def deploy(n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False):
n_stkmans,
csv,
mans_thresh,
with_watchtowers=False,
with_watchtowers=with_wts,
with_cosigs=with_cosigs,
)

if with_wts:
# NOTE: no config. We use hardcoded values for the demo.
policies = [{"path": p} for p in policies]
for stk in rn.stk_wallets + rn.stkman_wallets:
stk.watchtower.add_plugins(policies)

dummysigner_conf_file = os.path.join(BASE_DIR, "dummysigner.toml")
# We use a hack to avoid having to modify the test_framework to include the GUI.
if WITH_GUI:
Expand Down Expand Up @@ -245,7 +273,7 @@ def deploy(n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False):
)
with open(p.gui_conf_file, "w") as f:
f.write(f"revaultd_config_path = '{p.conf_file}'\n")
f.write(f"revaultd_path = '{REVAULTD_PATH}'\n")
f.write(f"revaultd_path = '{test_framework.revaultd.REVAULTD_PATH}'\n")
f.write(f"log_level = '{LOG_LEVEL}'\n")
f.write(f"debug = {'true' if DEBUG_GUI else 'false'}")
revault_gui = os.path.join(
Expand All @@ -271,7 +299,7 @@ def deploy(n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False):
)
for i, stk in enumerate(rn.stk_wallets):
f.write(f'alias stk{i}cli="{revault_cli} --conf {stk.conf_file}"\n')
f.write(f'alias stk{i}d="{REVAULTD_PATH} --conf {stk.conf_file}"\n')
f.write(f'alias stk{i}d="{test_framework.revaultd.REVAULTD_PATH} --conf {stk.conf_file}"\n')
if WITH_GUI:
f.write(
f"alias stk{i}gui='{revault_gui} --conf {stk.gui_conf_file}'\n"
Expand All @@ -282,7 +310,7 @@ def deploy(n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False):
)
for i, man in enumerate(rn.man_wallets):
f.write(f'alias man{i}cli="{revault_cli} --conf {man.conf_file}"\n')
f.write(f'alias man{i}d="{REVAULTD_PATH} --conf {man.conf_file}"\n')
f.write(f'alias man{i}d="{test_framework.revaultd.REVAULTD_PATH} --conf {man.conf_file}"\n')
if WITH_GUI:
f.write(
f"alias man{i}gui='{revault_gui} --conf {man.gui_conf_file}'\n"
Expand All @@ -296,7 +324,7 @@ def deploy(n_stks, n_mans, n_stkmans, csv, mans_thresh=None, with_cosigs=False):
f'alias stkman{i}cli="{revault_cli} --conf {stkman.conf_file}"\n'
)
f.write(
f'alias stkman{i}d="{REVAULTD_PATH} --conf {stkman.conf_file}"\n'
f'alias stkman{i}d="{test_framework.revaultd.REVAULTD_PATH} --conf {stkman.conf_file}"\n'
)
if WITH_GUI:
f.write(
Expand Down Expand Up @@ -394,6 +422,16 @@ def parse_args():
action="store_true",
help="Enable cosigning servers to allow Spend policies at the cost of weaker assumptions",
)
deploy_config.add_argument(
"-policy",
"--spending-policy",
action="append",
default=[],
dest="policies",
help="Enforce a spending policy on all watchtowers by specifying a path to a "
"watchtower plugin. Specify this option multiple times to enable multiple "
"policies.",
)
return parser.parse_args()


Expand All @@ -408,4 +446,5 @@ def parse_args():
args.timelock,
args.managers_threshold,
args.with_cosigning_servers,
args.policies,
)
74 changes: 74 additions & 0 deletions policies/max_value_in_flight.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env python3
"""A plugin which enforces a maximum total value in flight (being unvaulted).

It uses a fixed configuration:
- Its datadir is set in the 'demo' directory.
- The maximum value in flight enforced is 10btc.

It stores the in flight vaults info as "deposit outpoint", "value" pairs in a
JSON file at the root of its data directory.
"""

import json
import os
import sys


MAX_VALUE = 10 * 10 ** 8
DATADIR = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"demo",
"max_value_flight_datadir",
)
DATASTORE_FNAME = os.path.join(DATADIR, "datastore.json")
JSON_KEY = "in_flight"


def read_request():
"""Read a JSON request from stdin up to the '\n' delimiter."""
buf = ""
while len(buf) == 0 or buf[-1] != "\n":
buf += sys.stdin.read()
return json.loads(buf)


def update_in_flight(entries):
with open(DATASTORE_FNAME, "w+") as f:
f.write(json.dumps({JSON_KEY: entries}))


def maybe_create_data_dir():
if not os.path.isdir(DATADIR):
os.makedirs(DATADIR)
update_in_flight({})


def recorded_attempts():
"""Read the current value in-flight from a text file in our datadir."""
maybe_create_data_dir()
with open(DATASTORE_FNAME, "r") as f:
data_store = json.loads(f.read())
return data_store[JSON_KEY]


if __name__ == "__main__":
req = read_request()
block_info = req["block_info"]
maybe_create_data_dir()

# First update the recorded attempts with the new and pass attempts.
in_flight = recorded_attempts()
for op in block_info["successful_attempts"] + block_info["revaulted_attempts"]:
del in_flight[op]
for v in block_info["new_attempts"]:
in_flight[v["deposit_outpoint"]] = v["value"]
update_in_flight(in_flight)

# If we get above the threshold, revault everything that is currently in-flight.
resp = {"revault": []}
value_in_flight = sum([in_flight[k] for k in in_flight])
if value_in_flight >= MAX_VALUE:
resp["revault"] = list(in_flight.keys())

sys.stdout.write(json.dumps(resp))
sys.stdout.flush()
74 changes: 74 additions & 0 deletions policies/max_value_per_day.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env python3
"""A plugin which enforces a maximum total value per day.

It uses a fixed configuration:
- Its datadir is set in the 'demo' directory.
- The maximum value enforced is 50btc per day.

It simply stores a counter which is reset to 0 after 144 blocks (assumes no reorg).
"""

import json
import os
import sys


MAX_VALUE = 50 * 10 ** 8
DATADIR = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"demo",
"max_value_day_datadir",
)
DATASTORE_FNAME = os.path.join(DATADIR, "datastore.json")


def read_request():
"""Read a JSON request from stdin up to the '\n' delimiter."""
buf = ""
while len(buf) == 0 or buf[-1] != "\n":
buf += sys.stdin.read()
return json.loads(buf)


def update_counter(counter):
data = json.loads(open(DATASTORE_FNAME, "r").read())
data["counter"] = counter
open(DATASTORE_FNAME, "w+").write(json.dumps(data))


def maybe_create_data_dir(block_height):
if not os.path.isdir(DATADIR):
os.makedirs(DATADIR)
open(DATASTORE_FNAME, "w+").write(
json.dumps({"counter": 0, "block_height": block_height})
)


def current_data():
with open(DATASTORE_FNAME, "r") as f:
return json.loads(f.read())


if __name__ == "__main__":
req = read_request()
block_info = req["block_info"]
maybe_create_data_dir(req["block_height"])
data = current_data()

counter = data["counter"]
if req["block_height"] >= data["block_height"] + 144:
counter = 0

resp = {"revault": []}
for v in block_info["new_attempts"]:
# Revault everything that gets above the threshold, but only what gets
# above it.
# FIXME: should we revault everything that is in flight?
if counter + v["value"] > MAX_VALUE:
resp["revault"].append(v["deposit_outpoint"])
continue
counter += v["value"]
update_counter(counter)

sys.stdout.write(json.dumps(resp))
sys.stdout.flush()
File renamed without changes.
20 changes: 20 additions & 0 deletions policies/revault_nothing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env python3
"""A plugin which never returns any attempt sent to it as needing to be revaulted"""

import json
import sys


def read_request():
"""Read a JSON request from stdin up to the '\n' delimiter."""
buf = ""
while len(buf) == 0 or buf[-1] != "\n":
buf += sys.stdin.read()
return json.loads(buf)


if __name__ == "__main__":
req = read_request()
resp = {"revault": []}
sys.stdout.write(json.dumps(resp))
sys.stdout.flush()
Binary file added screenshots/0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion test_framework/mscompiler/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ macro_rules! from_json {
serde_json::from_str($str).unwrap_or_else(|e| {
eprintln!("Failed to deserialize '{}' as JSON: '{}'", $str, e);
process::exit(1);
});
})
};
}

Expand Down
Loading