一個應用的兩半
想像一個普通的網路銀行。你在瀏覽器裡看到一塊精緻的介面——按鈕、餘額、一個轉帳鍵——但真正的錢住在銀行的伺服器上,鎖在公司的資料庫背後。那塊介面只是一扇友好的窗,望向一個你看不見、也掌控不了的金庫。
去中心化應用保留了那扇友好的窗,卻把金庫換掉了。它的前端是一個普通網站,可以住在任何伺服器上(甚至你的筆記型電腦);而*邏輯與資金*則坐落在以太坊這類公鏈上的智慧合約裡。所以一個 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 是前端加鏈上程式碼;你的錢包是那支簽名的筆;讀取是免費的發問,寫入是付費的改動;而一次授權,是一份值得仔細設定的支出額度。接下來,我們要看代幣本身——那些標準,讓一個合約發行的一種幣或一件藏品,能被每個錢包和應用瞬間認得、知道如何處理。