灵符lingfu
L

ling-wallet

↓ 0 downloads

Ling Wallet: a post-quantum privacy-coin wallet, full node and HyperTorus miner for LNG

Windows · x86-64 ✕Linux · x86-64 ✕LingOS · x86-64LingOS · Pi 5 ARM64 ✕
Keywords wallet, cryptocurrency, lng, node, miner, ling
lingfu install ling-wallet
LicenseMIT
Authorsling-lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / 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
}

← Back to index