Graph Basics: DAGs, Trees, and Hash Links TODO
Concept
A graph is a pair of a vertex set and an edge set, and its properties diverge sharply depending on whether edges are directed and whether cycles exist. A DAG has only directed edges and no cycles, so a topological sort is always possible, and that ordering is the basis for dependency resolution and sequential processing. A tree is a connected, acyclic graph; with n vertices it has exactly n-1 edges, and once you pick a root, the path from any vertex to the root is unique. A hash link is an edge that points to the target node's content hash rather than a memory address, so changing a node's content changes its hash, which cascades up through every ancestor node that pointed to it — making the whole structure tamper-evident. Because a structure built from hash links can never point ahead to a hash that doesn't exist yet, it can never contain a cycle by construction and is always a DAG; Merkle trees and blockchains are the special case.
Blockchain structure, Merkle proofs, build dependencies, and transaction dependency graphs are all described in this same language of DAGs and hash links.
Code & Formula
# 그래프 기초(DAG·트리·해시 링크) — 해시 링크로 만든 체인은 원리상 사이클이 생길 수 없어 항상 DAG.
# 노드 하나(payload)를 바꾸면 그 해시가 바뀌고, 상위 노드가 가리키던 해시도 전부 달라진다.
import hashlib
def h(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()[:12]
class HashNode:
def __init__(self, payload, prev_hash=""):
self.payload = payload
self.prev_hash = prev_hash
self.hash = h(f"{payload}|{prev_hash}".encode())
def build_chain(payloads):
chain = []
prev = ""
for p in payloads:
node = HashNode(p, prev)
chain.append(node)
prev = node.hash
return chain
def verify_chain(chain):
prev = ""
for node in chain:
if node.prev_hash != prev:
return False
if h(f"{node.payload}|{node.prev_hash}".encode()) != node.hash:
return False
prev = node.hash
return True
chain = build_chain(["genesis", "tx1", "tx2", "tx3"])
print("원본 체인 유효?", verify_chain(chain))
for n in chain:
print(f" {n.payload:10} prev={n.prev_hash or '(none)':14} hash={n.hash}")
# tx2 의 내용을 변조하면 → 그 노드의 해시가 바뀌고, tx3.prev_hash 와 불일치 → 검증 실패.
chain[2].payload = "tx2-tampered"
chain[2].hash = h(f"{chain[2].payload}|{chain[2].prev_hash}".encode())
print("\ntx2 변조 후 체인 유효?", verify_chain(chain))
Exercise
Implement a Merkle tree that reads a directory tree and computes each node's hash from its children's hashes, then verify that changing one byte of a file changes the root, while only the nodes on the changed path need to be recomputed.
Practical Connection
Ethereum's state tree and block linkage are both hash-linked DAGs, and the same principle underlies how Gnosis Conditional Tokens derive condition and position identifiers as hashes of their inputs.
Where it lands in Jayverse
- Verex: since it's a ctf-exchange fork, verify condition-ID and position-ID derivation follows the exact hash scheme, and add a test that changing one input (oracle, questionId, outcome count) changes only that ID. A silent collision in the hash-link derivation would corrupt the whole condition tree.
- gitboard: model service dependency (token before bridge before wallet, etc.) as an explicit DAG with a topological order. Deploy and migration order should be derived from the graph, not remembered by whoever runs it.
- Bridge: use a hash-linked snapshot (a Merkle root of locked balances) as the thing the relayer commits to. Tampering with one locked deposit becomes detectable by a root mismatch alone, without walking the whole ledger.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| diverge sharply | 크게 갈라지다/차이 나다 · 조건에 따라 성질이 확연히 달라질 때. "diverge sharply depending on whether edges are directed" |
| cascade up | (변화가) 위로 연쇄적으로 퍼지다 · 하나의 변경이 상위 노드까지 줄줄이 영향을 줄 때. "cascades up through every ancestor node" |
| tamper-evident | 조작하면 티가 나는(변조 감지 가능한) · 데이터가 변경되면 바로 드러나는 구조를 말할 때. "making the whole structure tamper-evident" |
| by construction | 구조상 원천적으로, 설계 자체에 의해 · 별도 증명 없이 구조만으로 성립하는 성질을 말할 때. "can never contain a cycle by construction" |
| point ahead to | 아직 존재하지 않는 대상을 미리 가리키다 · 해시 링크가 미래 값을 참조할 수 없다는 제약. "can never point ahead to a hash that doesn't exist" |
| the basis for | ~의 토대/근거가 되다 · 어떤 개념이 다른 응용의 기반이 될 때. "the basis for dependency resolution" |
| connected, acyclic | 연결되어 있고 순환이 없는 · 트리의 정의를 이루는 두 성질을 가리킬 때. "A tree is a connected, acyclic graph" |
| DAG | 방향성 비순환 그래프(Directed Acyclic Graph) · 사이클 없는 방향 그래프, 위상정렬이 가능한 구조. "A DAG has only directed edges and no cycles" |
| Gnosis Conditional Tokens | Gnosis가 만든 조건부 토큰 프레임워크(예측시장용 포지션 토큰 표준) · 조건·포지션 식별자를 해시로 만드는 예로 언급. "Gnosis Conditional Tokens derive condition and position identifiers as hashes" |
If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/math-50-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.