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/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")
}
}