Skip to content

Commit

Permalink
sim: make run at fixed scale an option
Browse files Browse the repository at this point in the history
  • Loading branch information
JSwambo committed Sep 30, 2021
1 parent 2cb282a commit 28699e5
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 41 deletions.
6 changes: 5 additions & 1 deletion Model/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
INVALID_SPEND_RATE = os.getenv("INVALID_SPEND_RATE", None)
# Catastrophe rate per day
CATASTROPHE_RATE = os.getenv("CATASTROPHE_RATE", None)
# Delegate rate per day (if scale_fixed)
DELEGATE_RATE = os.getenv("DELEGATE_RATE", None)

if __name__ == "__main__":
random.seed(21000000)
Expand All @@ -48,12 +50,13 @@
UNVAULT_RATE,
INVALID_SPEND_RATE,
CATASTROPHE_RATE,
DELEGATE_RATE,
]
if any(v is None for v in req_vars):
logging.error(
"Need all these environment variables to be set: N_STK, N_MAN, LOCKTIME,"
" HIST_CSV, RESERVE_STRAT, ESTIMATE_STRAT, I_VERSION,"
" CANCEL_COIN_SELECTION, NUMBER_VAULTS, REFILL_EXCESS,"
" CANCEL_COIN_SELECTION, NUMBER_VAULTS, REFILL_EXCESS, DELEGATE_RATE, "
" REFILL_PERIOD, UNVAULT_RATE, INVALID_SPEND_RATE, CATASTROPHE_RATE."
)
sys.exit(1)
Expand All @@ -73,6 +76,7 @@
float(UNVAULT_RATE),
float(INVALID_SPEND_RATE),
float(CATASTROPHE_RATE),
float(DELEGATE_RATE),
with_balance=True,
# with_fb_coins_dist=True,
with_cum_op_cost=True,
Expand Down
12 changes: 9 additions & 3 deletions Model/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ def sim_process(prng_seed, val=None, study_type=None, config_map=None):
"UNVAULT_RATE",
"INVALID_SPEND_RATE",
"CATASTROPHE_RATE",
"DELEGATE_RATE",
"CANCEL_COIN_SELECTION",
]
if study_type not in req_types:
logging.error(
"Study requires a type from: NUMBER_VAULTS,"
" REFILL_EXCESS, REFILL_PERIOD, REFILL_EXCESS, UNVAULT_RATE,"
" REFILL_EXCESS, REFILL_PERIOD, REFILL_EXCESS, UNVAULT_RATE, DELEGATE_RATE"
" INVALID_SPEND_RATE, CATASTROPHE_RATE, N_STK, N_MAN, HIST_CSV,"
" RESERVE_STRAT, ESTIMATE_STRAT, I_VERSION."
" RESERVE_STRAT, ESTIMATE_STRAT, I_VERSION, CANCEL_COIN_SELECTION."
)
sys.exit(1)

Expand All @@ -50,6 +52,8 @@ def sim_process(prng_seed, val=None, study_type=None, config_map=None):
UNVAULT_RATE = {config_map["UNVAULT_RATE"]}
INVALID_SPEND_RATE = {config_map["INVALID_SPEND_RATE"]}
CATASTROPHE_RATE = {config_map["CATASTROPHE_RATE"]}
DELEGATE_RATE = {config_map["DELEGATE_RATE"]}
CANCEL_COIN_SELECTION = {config_map["CANCEL_COIN_SELECTION"]}
"""
)

Expand All @@ -76,6 +80,7 @@ def sim_process(prng_seed, val=None, study_type=None, config_map=None):
int(config_map["UNVAULT_RATE"]),
float(config_map["INVALID_SPEND_RATE"]),
float(config_map["CATASTROPHE_RATE"]),
float(config_map["DELEGATE_RATE"]),
with_balance=True,
with_divergence=True,
with_cum_op_cost=True,
Expand Down Expand Up @@ -126,9 +131,10 @@ def multiprocess_run(range_seed, val, study_type, config_map):
"REFILL_EXCESS": 1,
"UNVAULT_RATE": 1,
"DELEGATE_RATE": 1,
"CANCEL_COIN_SELECTION": 0,
"INVALID_SPEND_RATE": 0.1,
"CATASTROPHE_RATE": 0.005,
"CANCEL_COIN_SELECTION": 0,
"DELEGATE_RATE": 1,
}

# Set the study parameters
Expand Down
65 changes: 40 additions & 25 deletions Model/simulation.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
"""
TODO:
Update sequences to handle transaction broadcast & finalize.
"""

import logging
import random

Expand Down Expand Up @@ -45,6 +40,8 @@ def __init__(
unvault_rate,
invalid_spend_rate,
catastrophe_rate,
delegate_rate,
with_scale_fixed=True,
with_balance=False,
with_divergence=False,
with_op_cost=False,
Expand All @@ -61,6 +58,7 @@ def __init__(
self.refill_excess = refill_excess
self.refill_period = refill_period
self.unvault_rate = unvault_rate
self.delegate_rate = delegate_rate

# Manager parameters
self.invalid_spend_rate = invalid_spend_rate
Expand Down Expand Up @@ -105,6 +103,7 @@ def __init__(
self.fb_coins_dist = []
self.vm_values = []
self.vb_values = []
self.scale_fixed = with_scale_fixed

# Simulation report
self.delegation_failures = 0
Expand Down Expand Up @@ -374,8 +373,8 @@ def confirm_sequence(self, height):
if tx.txouts[-1].processing_state == ProcessingState.UNPROCESSED:
cf_fee = self.wt.broadcast_consolidate_fanout(height)
logging.info(
f" Second Consolidate-fanout transition at block {height} with fee:"
f" {cf_fee}"
f" Second Consolidate-fanout transition at block {height} with"
f" fee: {cf_fee}"
)
if self.cf_fee is None:
self.cf_fee = 0
Expand Down Expand Up @@ -409,27 +408,35 @@ def run(self, start_block, end_block):
# First of all, was any transaction confirmed in this block?
self.confirm_sequence(block)

# We always try to keep the number of expected vaults under watch. We might
# not be able to allocate if a CF tx is pending but not yet confirmed.
for i in range(len(self.wt.list_vaults()), self.num_vaults):
amount = int(10e10) # 100 BTC
try:
self.wt.allocate(self.new_vault_id(), amount, block)
except AllocationError as e:
logging.error(
f"Not enough funds to allocate all the expected vaults at block {block}: {str(e)}"
)
# FIXME: should we break?
break
self.vault_count += 1
if self.scale_fixed:
# We always try to keep the number of expected vaults under watch. We might
# not be able to allocate if a CF tx is pending but not yet confirmed.
for i in range(len(self.wt.list_vaults()), self.num_vaults):
amount = int(10e10) # 100 BTC
try:
self.wt.allocate(self.new_vault_id(), amount, block)
except AllocationError as e:
logging.error(
"Not enough funds to allocate all the expected vaults at"
f" block {block}: {str(e)}"
)
break
self.vault_count += 1

# Refill once per refill period
if block % self.refill_period == 0:
self.refill_sequence(block, 0)

# The unvault rate is a rate per day
# The delegate rate is per day
if not self.scale_fixed:
if random.random() < self.delegate_rate / BLOCKS_PER_DAY:
self.delegate_sequence(block)

# The spend rate is a rate per day
if random.random() < self.unvault_rate / BLOCKS_PER_DAY:
self.delegate_sequence(block)
if self.scale_fixed:
self.delegate_sequence(block)

# generate invalid spend, requires cancel
if random.random() < self.invalid_spend_rate:
try:
Expand Down Expand Up @@ -865,8 +872,14 @@ def plot(self, output=None, show=False):
plot_num += 1

# Report confirmation tracking
report += f"Max confirmation time for a Cancel Tx: {self.report_df['max_cancel_conf_time'][0]}\n"
report += f"Max confirmation time for a Consolidate-fanout Tx: {self.report_df['max_cf_conf_time'][0]}\n"
report += (
"Max confirmation time for a Cancel Tx:"
f" {self.report_df['max_cancel_conf_time'][0]}\n"
)
report += (
"Max confirmation time for a Consolidate-fanout Tx:"
f" {self.report_df['max_cf_conf_time'][0]}\n"
)

if output is not None:
plt.savefig(f"{output}.png")
Expand Down Expand Up @@ -970,6 +983,8 @@ def plot_fee_estimate(
unvault_rate=1,
invalid_spend_rate=0.1,
catastrophe_rate=0.05,
delegate_rate=1,
with_scale_fixed=True,
with_balance=True,
with_divergence=True,
with_op_cost=False,
Expand All @@ -982,7 +997,7 @@ def plot_fee_estimate(
with_fb_coins_dist=False,
)

start_block = 200000
start_block = 350000
end_block = 680000

sim.run(start_block, end_block)
Expand Down
24 changes: 12 additions & 12 deletions Model/statemachine.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
"""
TODO:
* simulate requirement for cancel feebump, then implement feebump algo
* Add random time interval between balance low and re-fill trigger (to simulate slow stakeholder),
to investigate time-at-risk.
* Make good documentation
* Remove possibility for inconsistencies in progress of blocks with WTSim
- could break with certain DELEGATION_PERIODs.
* Make good documentation
"""

import bisect
Expand Down Expand Up @@ -115,7 +112,10 @@ def __init__(
self.fan_block = fan_block

def __repr__(self):
return f"Coin(id={self.id}, amount={self.amount}, fan_block={self.fan_block}, state={self.processing_state})"
return (
f"Coin(id={self.id}, amount={self.amount}, fan_block={self.fan_block},"
f" state={self.processing_state})"
)

def __lt__(a, b):
return a.amount < b.amount
Expand Down Expand Up @@ -886,8 +886,7 @@ def allocate(self, vault_id, amount, block_height):
)
except (StopIteration):
logging.debug(
f" No coin found with amount = {x} with tolerance"
f" {tol*100}%"
f" No coin found with amount = {x} with tolerance {tol*100}%"
)
not_found.append(x)
continue
Expand All @@ -908,9 +907,10 @@ def allocate(self, vault_id, amount, block_height):
if vault.reserve_balance() >= required_reserve:
break

assert (
vault.reserve_balance() >= required_reserve
), f"Was checked before searching, {vault.reserve_balance()} vs {required_reserve}"
assert vault.reserve_balance() >= required_reserve, (
f"Was checked before searching, {vault.reserve_balance()} vs"
f" {required_reserve}"
)

# Now we have enough coins for the required reserve we can look for
# coins in the bonus reserve
Expand Down Expand Up @@ -990,8 +990,8 @@ def cancel_coin_selec_0(self, vault, needed_fee, feerate):
fbcoin = reserve[-1]
if fbcoin.amount <= fbcoin_cost + self.cancel_tx_fee(feerate, 0):
logging.error(
f"Not enough coins to cover for the Cancel fee of "
f"{needed_fee} at feerate {feerate}. Collected {collected_fee} sats."
f"Not enough coins to cover for the Cancel fee of {needed_fee}"
f" at feerate {feerate}. Collected {collected_fee} sats."
)
break
self.remove_coin(fbcoin)
Expand Down

0 comments on commit 28699e5

Please sign in to comment.