一个应用的两半
想象一个普通的网上银行。你在浏览器里看到一块精致的界面——按钮、余额、一个转账键——但真正的钱住在银行的服务器上,锁在公司的数据库背后。那块界面只是一扇友好的窗,望向一个你看不见、也掌控不了的金库。
去中心化应用保留了那扇友好的窗,却把金库换掉了。它的前端是一个普通网站,可以住在任何服务器上(甚至你的笔记本电脑);而*逻辑与资金*则坐落在以太坊这类公链上的智能合约里。所以一个 dApp 其实是两半:一半是你看着的前端,一半是无法伪造、也无法关停的链上代码。前端明天就算消失,合约——以及你的资金——也会一如既往地照常运转。
钱包,是你的签名笔
你的钱包并不是存放硬币的地方——那些数字住在链上。钱包真正的工作,是守护一个秘密:你的私钥。把这把私钥想成一支只有你握着的签名笔,它写出的签名,地球上没有任何人能够伪造。当一个 dApp 想让你做某件事时,你的钱包就用这支笔为请求签名,证明这道指令确实出自你手。
这支笔背后的密码学,是数字签名。它的奇妙之处在于单向:你的私钥造出一个签名,任何人都能拿它来核对你的公开地址,可无论怎么核对,都永远不会反推出私钥本身。于是整个网络都能确认*「没错,这个账户的主人确实授权了此事」*,却从不曾窥见你的秘密。先签名,签好的请求便能安全地穿行于开放的互联网。
读取免费,写入花燃料
你与合约的每一次互动,都落进两个篮子中的一个,而二者之别,决定了你究竟要不要打开钱包。读取是向链发问——*我的余额是多少?这件物品归谁?*——它什么也不改变。任何节点都能用手头已有的数据作答,所以读取既即时又免费;无需签名,也无需付费。这正是为什么页面一加载,dApp 就能显示你的余额,而你还什么都没批准。
写入则是另一个篮子:它*改变共享状态*——转出代币、投下一票、铸造一件物品。一次写入必须由网络上每一个节点重新运行并达成一致,再被永久存下,因此它不可能免费。它必须是一笔签了名的交易,并附带一笔燃料费,为这场全球性的运算付账。读取是图书管理员瞥一眼书架;写入则是馆里所有人同时改写各自那一本书。
READ (a question) WRITE (a change)
cost: free cost: gas fee
signature: none signature: required
speed: instant speed: wait for a block
example: getBalance() example: transfer(to, 10)
Flow of a write:
front-end drafts tx -> wallet shows it -> YOU sign
-> broadcast -> a validator includes it in a block
-> every node re-runs it -> state updated forever代币授权:交出一份支出额度
有一个动作常让新手栽跟头。多数合约无法伸进你的钱包、把你的代币掏出来——而这是刻意如此设计的。于是,当一个 dApp 需要*代你*转移代币时(比如一个交易应用,要把一种币换成另一种),你得先签一笔单独的交易,叫作授权。它告诉代币合约:*「允许这个另外的合约,最多花掉我 N 枚代币。」*
// Solidity: the approval lives in the TOKEN contract
function approve(address spender, uint amount) public {
allowance[msg.sender][spender] = amount; // set a limit
}
// Later the dApp's contract may pull tokens, but only
// up to the limit you set:
// transferFrom(you, someoneElse, amount <= allowance)
// approve(dApp, 50) -> safe, capped at 50
// approve(dApp, UNLIMITED) -> convenient, but risky授权是真正有用的——它让一个应用顺畅地行事,不必每一步都来烦你签名。但症结在于额度。为了省去你日后的弹窗,许多 dApp 会索要一份无上限的额度,而人们往往不看就一路点过。倘若那个支出合约日后被发现存在缺陷、或心怀恶意,这份长期有效的许可,恰恰就是让它能抽干已授权代币的那把钥匙。补救之道很简单:尽量只授权你实际要花的数额,并撤销那些你不再使用的旧额度。
把它们串起来
- 打开 dApp。它的前端加载后,免费*读取*链上数据来显示你的余额——此刻还没有钱包弹窗。
- 点击一个动作。前端*起草*一笔交易(比如一次兑换),并把它递给你的钱包——它自己无法发送。
- 读一读,再签名。你的钱包显示这份请求和燃料预估;你的签名把它变成一笔有效且经授权的交易。
- 网络结清它。这笔签好的写入被广播、被打包进区块、被每个节点重新运行,并永久记录到链上。
整套模式就是这样。一个 dApp 是前端加链上代码;你的钱包是那支签名的笔;读取是免费的发问,写入是付费的改动;而一次授权,是一份值得仔细设定的支出额度。接下来,我们要看代币本身——那些标准,让一个合约发行的一种币或一件藏品,能被每个钱包和应用瞬间认得、知道如何处理。