灵符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/tests/p2p/t_p2p.ling
# t_p2p.ling — end-to-end test of the p2p_* builtins (LING_API.md §4) in one
# process: two LWP-1 networks on loopback, A listening, B dialing A.
#
#   ling run --interp t_p2p.ling
#
# Prints one PASS/FAIL line per check and a summary.

bind MAGIC = "4c573174"
bind NET_ID = 7
bind KIND_MSG = 32
bind KIND_TX = 33

fn check(name, cond) {
    if cond {
        print("PASS " + name)
        st_set("passed", st_get("passed", 0) + 1)
    } else {
        print("FAIL " + name)
        st_set("failed", st_get("failed", 0) + 1)
    }
    return cond
}

fn repeat_hex(pair, n) {
    bind s = ""
    bind i = 0
    while i < n {
        bind s = s + pair
        bind i = i + 1
    }
    return s
}

# Drain `net` into the event log stored under `key`.
fn pump(net, key) {
    bind evs = p2p_poll(net, 64, 20)
    bind log = st_get(key, [])
    bind i = 0
    while i < len(evs) {
        bind log = list_push(log, list_get(evs, i))
        bind i = i + 1
    }
    st_set(key, log)
    return len(evs)
}

# First logged event of `kind` whose field `idx` equals `val` (idx < 0: any).
fn find_ev(key, kind, idx, val) {
    bind log = st_get(key, [])
    bind i = 0
    while i < len(log) {
        bind ev = list_get(log, i)
        if list_get(ev, 0) == kind {
            if idx < 0 {
                return ev
            }
            if list_get(ev, idx) == val {
                return ev
            }
        }
        bind i = i + 1
    }
    return ()
}

# Pump both networks until `key` holds a matching event, or ~ms elapse.
fn wait_ev(a, b, key, kind, idx, val, ms) {
    bind waited = 0
    while waited < ms {
        pump(a, "ev_a")
        pump(b, "ev_b")
        bind ev = find_ev(key, kind, idx, val)
        if ev != () {
            return ev
        }
        bind waited = waited + 40
    }
    return ()
}

# Like wait_ev, pumping only `net` (e.g. once the other side is shut down).
fn wait_one(net, key, kind, idx, val, ms) {
    bind waited = 0
    while waited < ms {
        pump(net, key)
        bind ev = find_ev(key, kind, idx, val)
        if ev != () {
            return ev
        }
        bind waited = waited + 20
    }
    return ()
}

fn is_bad(r) {
    return match r {
        ok(v) => false,
        bad(e) => true,
    }
}

fn unwrap_or(r, d) {
    return match r {
        ok(v) => v,
        bad(e) => d,
    }
}

fn base_cfg(dir) {
    return [["magic_hex", MAGIC], ["network", NET_ID], ["data_dir", dir], ["fast_timers", true]]
}

fn test_config_validation() {
    check("config: unknown key -> bad", is_bad(p2p_start(list_push(base_cfg(".p2p_test/x"), ["colour", "red"]), "")))
    check("config: bad magic -> bad", is_bad(p2p_start([["magic_hex", "zz"], ["network", 1], ["data_dir", ".p2p_test/x"]], "")))
    check("config: missing network -> bad", is_bad(p2p_start([["magic_hex", MAGIC], ["data_dir", ".p2p_test/x"]], "")))
    check("config: duplicate key -> bad", is_bad(p2p_start(list_push(base_cfg(".p2p_test/x"), ["network", 2]), "")))
    check("config: bad peer address -> bad", is_bad(p2p_start(list_push(base_cfg(".p2p_test/x"), ["peers", ["nope"]]), "")))
    check("config: max_outbound type -> bad", is_bad(p2p_start(list_push(base_cfg(".p2p_test/x"), ["max_outbound", "8"]), "")))
    return 0
}

fn test_seeds() {
    bind auth_seed = repeat_hex("11", 32)
    bind auth_pk = mldsa87_public(mldsa87_keygen_from_seed(auth_seed))
    bind seed_pk = mldsa87_public(mldsa87_keygen_from_seed(repeat_hex("22", 32)))
    bind entries = [["1.2.3.4:4747", seed_pk], ["[2001:db8::1]:4747", seed_pk]]
    bind list_hex = p2p_seeds_sign(NET_ID, 1700000000, entries, auth_seed)
    bind v = p2p_seeds_verify(list_hex, auth_pk)
    check("seeds: verify ok", is_bad(v) == false)
    bind got = unwrap_or(v, [0, 0, []])
    check("seeds: network", list_get(got, 0) == NET_ID)
    check("seeds: issued_at", list_get(got, 1) == 1700000000)
    bind es = list_get(got, 2)
    check("seeds: entries", len(es) == 2)
    check("seeds: entry addr", list_get(list_get(es, 0), 0) == "1.2.3.4:4747")
    check("seeds: entry pk", list_get(list_get(es, 1), 1) == seed_pk)
    # Flip one hex digit in the body (inside the issued_at field).
    bind c = substr(list_hex, 14, 1)
    bind flip = if c == "0" { "1" } else { "0" }
    bind tampered = substr(list_hex, 0, 14) + flip + substr(list_hex, 15)
    check("seeds: tampered body -> bad", is_bad(p2p_seeds_verify(tampered, auth_pk)))
    bind n = len(list_hex)
    bind c2 = substr(list_hex, n - 1, 1)
    bind flip2 = if c2 == "0" { "1" } else { "0" }
    check("seeds: tampered signature -> bad", is_bad(p2p_seeds_verify(substr(list_hex, 0, n - 1) + flip2, auth_pk)))
    check("seeds: wrong authority -> bad", is_bad(p2p_seeds_verify(list_hex, seed_pk)))
    check("seeds: trailing byte -> bad", is_bad(p2p_seeds_verify(list_hex + "00", auth_pk)))
    # A verified list is accepted by p2p_start; a tampered one is refused.
    bind cfg = list_push(list_push(base_cfg(".p2p_test/s"), ["seeds_hex", list_hex]), ["authority_pk_hex", auth_pk])
    bind s = p2p_start(cfg, "")
    check("seeds: p2p_start accepts signed list", is_bad(s) == false)
    match s {
        ok(h) => p2p_shutdown(h),
        bad(e) => print("  start error: " + e),
    }
    bind cfg2 = list_push(list_push(base_cfg(".p2p_test/s"), ["seeds_hex", tampered]), ["authority_pk_hex", auth_pk])
    check("seeds: p2p_start rejects tampered list", is_bad(p2p_start(cfg2, "")))
    return 0
}

fn test_network() {
    bind ra = p2p_start(list_push(base_cfg(".p2p_test/a"), ["listen", "127.0.0.1:0"]), "")
    check("start A", is_bad(ra) == false)
    bind a = unwrap_or(ra, "")
    bind a_addr = p2p_local_addr(a)
    check("A local addr", substr(a_addr, 0, 10) == "127.0.0.1:")
    bind rb = p2p_start(list_push(base_cfg(".p2p_test/b"), ["peers", [a_addr]]), "")
    check("start B", is_bad(rb) == false)
    bind b = unwrap_or(rb, "")
    check("handles are 128-bit hex", len(a) == 32)

    bind ca = wait_ev(a, b, "ev_a", "connected", -1, 0, 20000)
    bind cb = wait_ev(a, b, "ev_b", "connected", -1, 0, 20000)
    check("A sees connected", ca != ())
    check("B sees connected", cb != ())
    if ca == () {
        return 0
    }
    if cb == () {
        return 0
    }
    check("connected event shape", len(ca) == 6)
    check("A: B is inbound", list_get(ca, 3) == true)
    check("B: A is outbound", list_get(cb, 3) == false)
    check("B: addr is A's", list_get(cb, 2) == a_addr)
    check("not a seed", list_get(cb, 5) == false)
    check("fingerprint form", len(list_get(cb, 4)) == 19)
    bind pa = list_get(ca, 1)
    bind pb = list_get(cb, 1)

    # p2p_peers shape: [peer_id, addr, inbound, fingerprint, is_seed, connected_secs]
    bind peers = p2p_peers(b)
    check("p2p_peers: one peer", len(peers) == 1)
    bind row = list_get(peers, 0)
    check("p2p_peers: row shape", len(row) == 6)
    check("p2p_peers: id", list_get(row, 0) == pb)
    check("p2p_peers: addr", list_get(row, 1) == a_addr)
    check("p2p_peers: inbound", list_get(row, 2) == false)
    check("p2p_peers: fingerprint", list_get(row, 3) == list_get(cb, 4))
    check("p2p_peers: is_seed", list_get(row, 4) == false)
    check("p2p_peers: connected_secs", list_get(row, 5) >= 0)
    check("p2p_netgroup", substr(p2p_netgroup(b, pb), 0, 6) == "local:")

    # Messages both ways.
    check("send A->B", p2p_send(a, pa, KIND_MSG, "a1b2c3"))
    bind m1 = wait_ev(a, b, "ev_b", "message", 3, "a1b2c3", 10000)
    check("B got message", m1 != ())
    if m1 != () {
        check("message shape", len(m1) == 4)
        check("message kind", list_get(m1, 2) == KIND_MSG)
        check("message peer", list_get(m1, 1) == pb)
    }
    check("send B->A", p2p_send(b, pb, KIND_MSG + 1, "00ff"))
    bind m2 = wait_ev(a, b, "ev_a", "message", 3, "00ff", 10000)
    check("A got message", m2 != ())
    if m2 != () {
        check("A message kind", list_get(m2, 2) == KIND_MSG + 1)
    }
    check("empty payload send", p2p_send(a, pa, KIND_MSG, ""))
    check("empty payload arrives", wait_ev(a, b, "ev_b", "message", 3, "", 10000) != ())
    check("send: reserved kind -> false", p2p_send(a, pa, 5, "00") == false)
    check("send: bad hex -> false", p2p_send(a, pa, KIND_MSG, "xyz") == false)
    check("send: unknown peer -> false", p2p_send(a, 999, KIND_MSG, "00") == false)

    # Broadcast.
    check("broadcast", p2p_broadcast(b, KIND_MSG, "beef", -1))
    check("broadcast arrives", wait_ev(a, b, "ev_a", "message", 3, "beef", 10000) != ())
    check("broadcast except", p2p_broadcast(a, KIND_MSG, "cafe", pa))

    # Dandelion++ relay. From B (outbound peer A = stem peer): A sees a stem
    # event (or, after the embargo, the fluffed message). From A (no outbound
    # peer): fluffed at once, B sees a message.
    bind txid1 = repeat_hex("ab", 32)
    check("relay B->A", p2p_relay(b, txid1, "7701", KIND_TX, -1))
    bind st = wait_ev(a, b, "ev_a", "stem", 2, "7701", 10000)
    bind fl = find_ev("ev_a", "message", 3, "7701")
    check("relay reaches A (stem or fluff)", st != () || fl != ())
    if st != () {
        check("stem shape", len(st) == 3)
        check("stem peer", list_get(st, 1) == pa)
    }
    bind txid2 = repeat_hex("cd", 32)
    check("relay A->B", p2p_relay(a, txid2, "7702", KIND_TX, -1))
    bind st2 = wait_ev(a, b, "ev_b", "stem", 2, "7702", 6000)
    bind fl2 = find_ev("ev_b", "message", 3, "7702")
    check("relay reaches B (stem or fluff)", st2 != () || fl2 != ())
    check("relay: bad id -> false", p2p_relay(a, "abcd", "00", KIND_TX, -1) == false)
    check("mark_fluffed", p2p_mark_fluffed(b, txid1))
    check("misbehaving (small score)", p2p_misbehaving(a, pa, 1, "test"))

    # Shutdown.
    check("shutdown A", p2p_shutdown(a))
    check("shutdown A again -> false", p2p_shutdown(a) == false)
    check("peers after shutdown", len(p2p_peers(a)) == 0)
    check("send after shutdown -> false", p2p_send(a, pa, KIND_MSG, "00") == false)
    bind d = wait_one(b, "ev_b", "disconnected", 1, pb, 20000)
    check("B sees disconnected", d != ())
    if d != () {
        check("disconnected shape", len(d) == 2)
    }
    check("shutdown B", p2p_shutdown(b))
    return 0
}

bind run = do {
    st_set("passed", 0)
    st_set("failed", 0)
    test_config_validation()
    test_seeds()
    test_network()
    bind f = st_get("failed", 0)
    print("passed " + str(st_get("passed", 0)) + ", failed " + str(f))
    if f == 0 {
        print("PASS t_p2p")
    } else {
        print("FAIL t_p2p")
    }
}

← Back to index