L
ling-wallet
↓ 0 downloadsLing Wallet: a post-quantum privacy-coin wallet, full node and HyperTorus miner for LNG
Keywords wallet, cryptocurrency, lng, node, miner, ling
lingfu install ling-walletCode / Files (116)
ling/core/money.ling
# money.ling — denominations (DESIGN §7.1), emission (§7.2), and the
# LWMA-1 difficulty algorithm (§7.3).
use "params.ling"
# d · 10^e with d ∈ {1, 2, 5}, 0 ≤ e ≤ 15.
fn is_denomination(v) {
if v < 1 {
return false
}
if v != floor(v) {
return false
}
bind x = v
bind e = 0
while x % 10 == 0 {
bind x = x / 10
bind e = e + 1
}
return e <= 15 && (x == 1 || x == 2 || x == 5)
}
# All denominations, largest first.
fn all_denominations() {
bind out = []
bind e = 15
while e >= 0 {
bind p = pow(10, e)
bind out = list_push(out, 5 * p)
bind out = list_push(out, 2 * p)
bind out = list_push(out, p)
bind e = e - 1
}
return out
}
# Greedy decomposition, largest first (optimal for {1,2,5}·10^e).
fn decompose(amount) {
bind out = []
bind rest = amount
bind ds = all_denominations()
bind i = 0
while i < len(ds) {
bind d = list_get(ds, i)
while rest >= d {
bind out = list_push(out, d)
bind rest = rest - d
}
bind i = i + 1
}
return out
}
fn list_sum(l) {
bind s = 0
bind i = 0
while i < len(l) {
bind s = s + list_get(l, i)
bind i = i + 1
}
return s
}
# Reward for the next block given coins already generated.
fn block_reward(generated) {
bind remaining = MONEY_SUPPLY - generated
if remaining < 0 {
bind remaining = 0
}
bind r = floor(remaining / EMISSION_DIV)
if r < TAIL_REWARD {
return TAIL_REWARD
}
return r
}
# Coinbase payout rounded down to 1000 atomic units (dust is burned).
fn coinbase_split(total) {
return decompose(total - total % 1000)
}
# Tests may shorten the target block time so coins mature quickly.
fn target_secs() {
return to_number(shared_get("test_target_secs", TARGET_BLOCK_SECS))
}
fn clamp(v, lo, hi) {
if v < lo {
return lo
}
if v > hi {
return hi
}
return v
}
# LWMA-1. `ts` and `cd` cover the most recent blocks oldest-first (at most
# LWMA_WINDOW + 1); `cd` are cumulative difficulties as decimal strings.
fn next_difficulty(ts, cd, genesis_difficulty) {
bind n = len(ts) - 1
if n > LWMA_WINDOW {
bind n = LWMA_WINDOW
}
if n < 6 {
return genesis_difficulty
}
bind off = len(ts) - n - 1
bind t = target_secs()
bind weighted = 0
bind i = 1
while i <= n {
bind st = clamp(list_get(ts, off + i) - list_get(ts, off + i - 1), 0 - 6 * t, 6 * t)
bind weighted = weighted + st * i
bind i = i + 1
}
bind floor_w = floor(n * n * t / 20)
if weighted < floor_w {
bind weighted = floor_w
}
bind work = big_sub(list_get(cd, off + n), list_get(cd, off))
bind avg = big_div(work, format("{}", n))
# next = avg · T · n(n+1) / (2 · weighted); steady state ⇒ next = avg.
bind num = big_mul(avg, format("{}", t * n * (n + 1)))
bind next = big_div(num, format("{}", 2 * weighted))
if big_cmp(next, "1") < 0 {
return "1"
}
return next
}