render.gno
4.58 Kb · 106 lines
1package provable
2
3import (
4 "strconv"
5 "strings"
6)
7
8// Render serves the overview at "" and one entry with its proof at
9// "entry/<index>".
10//
11// Output is a fixed size: the entry list is capped at renderEntries, so a full
12// log still renders. The chain caps a query at maxGasQuery and a reader cannot
13// raise it, so an unbounded Render is a permanently unreadable page.
14func Render(path string) string {
15 path = strings.TrimSpace(path)
16 if strings.HasPrefix(path, "entry/") {
17 return renderEntry(strings.TrimPrefix(path, "entry/"))
18 }
19 return renderIndex()
20}
21
22func renderIndex() string {
23 var b strings.Builder
24 b.WriteString("# provable\n\n")
25 b.WriteString("What gno.land can and cannot prove about itself, demonstrated rather than asserted.\n\n")
26
27 b.WriteString("## The log\n\n")
28 b.WriteString("An append-only Merkle mountain range. Appending costs O(log n) hashes and never rebuilds.\n\n")
29 b.WriteString("| Field | Value |\n|---|---|\n")
30 b.WriteString("| Entries | " + strconv.Itoa(log.Size()) + " / " + strconv.Itoa(MaxEntries) + " |\n")
31 b.WriteString("| Stored hashes | " + strconv.Itoa(log.Nodes()) + " |\n")
32 b.WriteString("| Peaks | " + strconv.Itoa(len(log.PeakHashes())) + " |\n")
33 b.WriteString("| Root | `" + rootOrDash() + "` |\n\n")
34
35 b.WriteString("This root is also the Tendermint simple-tree root over the same entries, so any\n")
36 b.WriteString("Tendermint verifier accepts it. `Verify` and `VerifyFixed` check the two proof\n")
37 b.WriteString("encodings against it.\n\n")
38
39 b.WriteString("## What the chain can prove\n\n")
40 b.WriteString("`gno.land/pkg/gnoland/app.go` mounts exactly two stores. One is IAVL and merkleized,\n")
41 b.WriteString("the other is a plain dbadapter whose `Commit` is documented as *\"Always returns a zero\n")
42 b.WriteString("commitID, as dbadapter store doesn't merkleize\"*.\n\n")
43 b.WriteString("| Data | Store | Provable against the app hash |\n|---|---|---|\n")
44 b.WriteString("| Package source | iavl | yes |\n")
45 b.WriteString("| Account balances | iavl | yes |\n")
46 b.WriteString("| Escaped object hashes (cross-realm) | iavl | yes, the hash only |\n")
47 b.WriteString("| Realm objects, types, realm metadata | base | **no** |\n")
48 b.WriteString("| **This log** | base | **no** |\n\n")
49
50 b.WriteString("## What that means here\n\n")
51 b.WriteString("A proof from this realm says *this entry is consistent with the root this realm\n")
52 b.WriteString("published*. It cannot say *this root is the chain's own*, for two independent reasons:\n\n")
53 b.WriteString("1. Realm state is not merkleized, so there is no state proof to produce.\n")
54 b.WriteString("2. `chain/runtime` exposes `ChainID`, `ChainDomain`, `ChainHeight` and `GetSessionInfo`\n")
55 b.WriteString(" and nothing else. No app hash, no block hash, no header. A realm has no trusted\n")
56 b.WriteString(" root to check anything against.\n\n")
57 b.WriteString("Anything built on Merkle proofs in a gno realm is trust-minimised relative to a\n")
58 b.WriteString("committed root, never trustless. Saying otherwise would be the interesting-sounding\n")
59 b.WriteString("half of a true story.\n\n")
60
61 b.WriteString("## Entries\n\n")
62 if log.Size() == 0 {
63 b.WriteString("_Empty. Call `Append(\"something\")`._\n")
64 return b.String()
65 }
66 start := 0
67 if len(entries) > renderEntries {
68 start = len(entries) - renderEntries
69 b.WriteString("Showing the last " + strconv.Itoa(renderEntries) + " of " + strconv.Itoa(len(entries)) + ".\n\n")
70 }
71 b.WriteString("| # | Entry |\n|---|---|\n")
72 for i := start; i < len(entries); i++ {
73 b.WriteString("| [" + strconv.Itoa(i) + "](/r/moul/x/provable/v0:entry/" + strconv.Itoa(i) + ") | " + entries[i] + " |\n")
74 }
75 return b.String()
76}
77
78func renderEntry(raw string) string {
79 i, err := strconv.Atoi(raw)
80 if err != nil || i < 0 || i >= len(entries) {
81 return "# provable\n\nNo entry `" + raw + "`.\n"
82 }
83 path, before, after := ProofOf(i)
84 var b strings.Builder
85 b.WriteString("# provable: entry " + strconv.Itoa(i) + "\n\n")
86 b.WriteString("```\n" + entries[i] + "\n```\n\n")
87 b.WriteString("## Inclusion proof\n\n")
88 b.WriteString("| Field | Value |\n|---|---|\n")
89 b.WriteString("| Index | " + strconv.Itoa(i) + " |\n")
90 b.WriteString("| Total | " + strconv.Itoa(log.Size()) + " |\n")
91 b.WriteString("| Path | `" + orDash(path) + "` |\n")
92 b.WriteString("| Before | `" + orDash(before) + "` |\n")
93 b.WriteString("| After | `" + orDash(after) + "` |\n")
94 b.WriteString("| Root | `" + rootOrDash() + "` |\n\n")
95 b.WriteString("Valid against that root only. The next `Append` moves it.\n")
96 return b.String()
97}
98
99func rootOrDash() string { return orDash(Root()) }
100
101func orDash(s string) string {
102 if s == "" {
103 return "-"
104 }
105 return s
106}