未來 Web 應用程式構建展望:探索新的技術方向!

在未來,我們會怎樣構建 Web 應用程序呢?

如果行業正常發展下去的話,那麼今天我們認為很難、做起來很有價值的事情在明天都會變得很輕松普遍。我想我們會發現很多新的抽象,讓 Google Docs 寫起來也能像今天的普通 Web 應用一樣簡單。

這就引出來一個問題——這些抽象會是什麼樣子?我們今天能發現它們嗎?想要找出答案,一種方法是審視我們在構建 Web 應用程序時必須經歷的所有問題,然后看看我們能做些什麼。

親愛的讀者,這篇文章就是我對上述方法的一次實踐嘗試。我們會走過一段旅程,看看今天我們是如何構建 Web 應用程序的:我們將回顧行業面臨的各種問題,評估 Firebase、Supabase、Hasura 等解決方案,看看還有什麼需要做的事情。我想到了旅途的最后,你一定會同意我的觀點,那就是瀏覽器中的數據庫看起來應該是最有用的抽象之一。不過,這里說的有點太遠了,我們先從頭開始。

1客戶端

這段旅程始于瀏覽器中的 Javascript。

A. 數據管道

我們的第一步工作是獲取信息并將其顯示在各個位置。例如,我們可能會顯示一個好友列表、好友數量、特定好友組的一個模態等。

我們面臨的問題是,所有組件看到的信息都需要是一致的。如果一個組件看到的好友數據和別的不一樣,你就可能顯示出錯誤的“計數”,或者一個視圖與另一個視圖中的昵稱不一樣。

為解決這個問題,我們需要有一個核心的事實來源。于是每當我們獲取什麼東西時,我們都會對其標準化并把它放在一個地方(通常是一個存儲)。然后,每個組件(使用一個選擇器)讀取并轉換所需的數據。下面這樣的代碼是很常見的:

// normalise [posts] -> {[id]: post}fetchRelevantPostsFor(user).then(posts => { posts.forEach(post => { store.addPost(post); })})// see all posts by author: store.posts.values().reduce((res, post) => {  res[post.authorId] = res[post.authorId] || [];  res[post.authorId].push(post); return res;}, {})

這里的問題是,為什麼我們需要做這些工作呢?我們得編寫自制代碼來處理這些數據,可是數據庫早就解決這個問題了。我們應該能夠“查詢”數據才是,比如說:

SELECT posts WHERE post.author_id = ?;

這樣查詢我們瀏覽器內部的信息不是很方便嗎?

B. 更改

下一個問題是讓數據保持最新狀態。假設我們刪除了一個好友,會發生什麼呢?

我們發送一個 API 請求,等待它完成,然后編寫一些邏輯來“刪除”關于這個好友的所有信息。比如這樣的代碼:

deleteFriend(user, friend.id).then(res => {  userStore.remove(friend.id); postStore.removeUserPosts(friend.id);})

但這種機制很快就會變得很麻煩:我們必須記住存儲中可能受這一更改影響的所有位置才行,就好像我們要在大腦里搞一個垃圾收集器,可我們的大腦不擅長這種活兒。為了避開它,人們想出的一種辦法是跳過問題并重新獲取整個世界:

deleteFriend(user, id).then(res => { fetchFriends(user); fetchPostsRelevantToTheUser(post);})

這兩種解決方案都不是很好。在這兩種情況下都存在我們需要留意的隱式不變量(基于這一更改,我們還需要注意其他哪些更改?),并且我們在應用程序中引入了延遲。

問題是,當我們對數據庫做任何更改時,它用不著我們這麼小心就可以完成工作。為什麼瀏覽器不能自動搞定這種事情呢?

DELETE FROM friendships WHERE friend_one_id = ? AND friend_two_id = ?-- Browser magically updates with all the friend and post information removed

C. 樂觀更新

你可能已經注意到 B. 的問題是,我們必須等待好友被移除才能更新瀏覽器狀態。

在大多數情況下,我們可以通過一個樂觀更新來加快速度——畢竟,我們知道調用很可能會成功。為此,我們執行以下操作:

friendPosts = userStore.getFriendPosts(friend);userStore.remove(friend.id);postStore.removeUserPosts(friend.id);deleteFriend(user, id).catch(e => {  // undo userStore.addFriend(friend); postStore.addPosts(friendPosts);})

這更煩人了。現在我們需要手動更新成功操作和失敗操作才行。

這是為什麼?在后端,數據庫本來就能做樂觀更新啊——為什麼我們不能在瀏覽器中這樣做?

DELETE friendship WHERE friend_one_id = ? AND friend_two_id = ?-- local store optimistically updated, if operation fails we undo

D. 響應性

數據不僅會因我們自己的行為而改變。有時我們需要連接到其他用戶所做的更改。例如,有人可以取消我們的好友關系,或者有人可以向我們發送消息。

為了完成這項工作,我們需要做的事情與在 API 端點中所做的是一樣的,但這次是在我們的 websocket 連接上:

ws.listen(`$/friends-removed`, friend => {  userStore.remove(friend.id); postStore.removeUserPosts(friend.id);}

但這又引入兩個問題。首先,我們又得玩垃圾收集器那套了,需要記住可能受事件影響的每一個位置。

其次,如果我們要做樂觀更新,我們就會遇到爭用情況。想象一下,你運行一個樂觀更新,將一個形狀的顏色設置為blue,同時一個陳舊(stale)更新跑來了,說它是red

1. Optimistic Update: `Blue`2. Stale reactive update: `Red`3. Successful Update, comes in through socket: `Blue`

現在你會看到閃爍的圖像。樂觀更新把形狀改成藍色,響應更新又會把它改成紅色,但是一旦樂觀更新成功,新的響應更新又會把它變回藍色。

解決這樣的問題涉及一致性的主題,于是你會去搜索關于……數據庫的資料。

其實,用不著這麼麻煩。如果每個查詢都是響應式的呢?

SELECT friends FROM users JOIN friendships on friendship.user_one_id = ?

現在,好友關系的任何變化都會自動更新訂閱這個查詢的視圖。你不必操心哪些內容出現了更改,并且你的本地數據庫可以找出“最新更新”的內容,于是消除了大部分復雜性。

2服務器

在服務器上,問題只會更復雜。

E. 端點

許多后端開發工作到頭來成為了數據庫和前端之間的一種粘合劑。

// db.jsfunction getRelevantPostsFor(userId) {  db.exec("SELECT * FROM users WHERE ...")}// api.jsapp.get("relevantPosts", (req, res) => {  res.status(200).send(getRelevantPosts(req.userId));})

這里面也太多重復了,以至于我們最后要創建腳本來生成這些文件。但是為什麼我們需要這樣做呢?不管怎樣,它們通常是與客戶端非常緊密地耦合的。為什麼我們不能直接將數據庫暴露給客戶端呢?

F. 權限

好吧,我們不這樣做的原因是我們需要確保權限正確設置。例如,你應該只能看到你好友的帖子。為此,我們向 API 端點添加中間件:

app.put("user", auth, (req, res) => {...}

但這會變得越來越混亂。Websocket 呢?新的代碼更改有時會引入一些你意想不到的方法來更新數據庫對象。突然之間,你就遇到了麻煩。

這里要問的問題是,為什麼要在 API 級別進行身份驗證?理想情況下,我們應該有一些非常接近數據庫的東西,確保任何數據訪問都通過權限檢查。像 Postgres 這樣的數據庫有行級安全性,但這很快就會變得很麻煩。但如果你能“描述”數據庫附近的實體呢?

User {  view: [ IAllowIfAdmin(), IAllowIfFriend(), IAllowIfSameUser(), ] write: [ IAllowIfAdmin(), IAllowIfSameUser(), ]}

在這里,我們編寫一些身份驗證規則,并確保不管你嘗試用哪種方式來編寫和更新用戶實體,你都可以被許可。于是乎,現在只有少數代碼更改(而不是大多數更改)會影響權限了。

G. 審計、撤消 / 重做

并且在某些時候,我們要完成的需求會增加復雜性。

例如,假設我們需要支持“撤消 / 重做”,用于好友操作。一個用戶刪除了一個好友,然后他們按下了“撤消”——我們怎麼來支持這一過程呢?

我們不能直接刪除好友關系,因為如果我這樣做的話,就沒法不知道這個人原本“已經是好友”,還是現在剛請求成為好友。在后一種情況下,我們可能需要發送好友請求才行。

為了解決這個問題,我們改進了數據模型。我們將用“好友事實”來代替單一的好友關系。

[,,]

那麼“最新事實”會代表倆人之間是否存在好友關系。

這種辦法是可行的,但大多數數據庫并不是為它設計的:查詢不像我們預期的那樣工作,優化起來也比我們預期的更難。我們最后不得不非常小心地處理更新機制,以免意外刪除記錄。

突然之間,我們變成了“某種數據庫工程師”,跑去大量查閱有關查詢優化的資料。

這種要求看似獨特,但在實踐中越來越常見。如果你處理的是金融交易,你需要這樣的機制來做審計。撤消 / 重做是許多應用中的必需品。

也許突然發生了一個錯誤,于是我們不小心刪除了數據。在事實統治的世界中不會有這樣的事情——反正你可以撤銷刪除操作。但這并不是我們大多數人生活的世界。

有一些模式將事實視為一等公民(Datomic,后文具體討論),但現在它們還是很罕見的,很少有工程師能做到。如果這種模式沒那麼罕見呢?

H. 離線模式

令人頭疼的例子還有很多。比如說離線模式——許多應用程序都是長期運行的,可以在沒有互聯網連接的情況下繼續運行一段時間。我們如何支持這一特性呢?

我們只能再次進化我們的數據模型,但這一次真正將所有內容都作為“事實”,并準備一個客戶端數據庫,該數據庫基于這些事實來演進自己的內部狀態。恢復連接后,我們應該能夠協調更改。

這很難做到。從本質上講,能做到這一步的程序員都變成了數據庫工程師。但是,如果我們在瀏覽器中有一個數據庫,讓它扮演分布式數據庫中的一個“節點”,上面的任務不就可以自動完成了嗎?

事實證明,基于事實的系統實際上更容易做到這一點。許多人認為我們需要求助于操作轉換來做這樣的事情,但正如 figma 展示的那樣,只要我們允許單一的領導者,并且可以接受最后寫入者獲勝這樣的語義,我們就可以徹底簡化這個機制,只要事實就足夠了。當你需要更嚴肅的解決方案時,你可以打開 OT 兔子洞。

想象一下…… 立即啟用離線模式。這樣一來,大多數應用程序會變成什麼樣?

I. 響應性

前面,我們討論了來自客戶端的響應性。在服務器上的響應性也是個問題。我們必須確保在數據更改時更新所有相關客戶端。例如,如果添加了一個“帖子”,我們需要通知與這個帖子相關的所有可能訂閱。

function addPost(post) { db.addPost(post); getAllFriends(post).forEach(notifyNewPost);}

這會變得相當混亂。我們很難知曉所有可能相關的主題。錯過一些主題也是很容易的:如果使用addPost之外的查詢更新數據庫,我們永遠不會知道是不是有主題被錯過了。這項工作需要開發人員來完成。它開始做起來很容易,但會變得越來越復雜。

然而,數據庫也可以知曉所有這些訂閱,并且可以只處理更新相關的查詢。RethinkDB 是在這方面做得很好的一個例子。如果你選擇的查詢語言可以做到這一點,是不是會很方便?

J. 衍生數據

最終,我們需要將數據放在多個位置:緩存(Redis)、搜索索引(ElasticSearch)或分析引擎(Hive)。這個步驟會變得非常麻煩。你可能需要引入某種隊列(Kafka),確保所有這些衍生源都保持最新狀態。這里面的工作涉及配置機器、引入服務發現和整個 shebang 等操作。

可為什麼要這麼復雜呢?在一個常規數據庫中,你可以執行以下操作:

CREATE INDEX ...

對于其他服務,我們為什麼不能這樣做?Martin Kleppman 在他的《數據密集型應用程序》中提出了這樣一種語言:

db |> ElasticSearchdb |> Analyticsdb.user |> Redis// Bam, we've connected elastic search, analytics, and redis to our db

3破壞性因素

我們都列舉到了 J。但這些只是你開始構建應用程序后才開始面臨的問題。那麼在開始構建之前呢?

K.TTP——原型制作時間

也許今天對開發人員來說最難辦的問題是上手。如果你想存儲用戶信息并顯示一個頁面,你會怎麼做?

以前,你只需要一個index.html和 FTP 就行了。現在,你需要 webpack、typescript、大量的構建過程,經常還需要多個服務。活動的部件太多了,邁出第一步都絕非易事。

這似乎是一個菜鳥才需要面對的問題,似乎有經驗的程序員上手起來會快很多。我認為情況更復雜一些。大多數項目都處于邊緣場景——它們不是你日常應對的那種類型。這意味著原型制作階段哪怕只多了幾分鐘,也可能會讓我們淘汰很多項目。

簡化這一步驟將大大增加我們可以使用的應用程序數量。如果這一階段能比index.html和 FTP 更容易完成呢?

4當前的解決方案

這問題可是真夠多的。情況看起來很糟糕,但如果你回過頭看看區區幾年前的樣子,就會發現我們已經有了這麼大的進步。不管怎樣,我們不再需要自己應付那些機架了。如同文藝復興時代一樣,很多杰出的人才正在努力開發這些問題的解決方案。這些方案有哪些代表呢?

Firebase

我認為 Firebase 在推動 Web 應用程序開發方面做了一些最具創新性的工作。他們做的最重要的一件事情就是 瀏覽器上的數據庫

有了 firebase,你可以像在服務器上一樣查詢數據。通過這種抽象,他們解決了上面列出的 A-E 問題。Firebase 可以處理樂觀更新,默認就是響應式的。它提供了對權限的支持,從而消除了對端點的需求。

K 問題也可以從中大大獲益:我認為它的原型制作速度表現還是市面上最出色的。你只需從index.html開始就行了!

但它也有兩個問題:

第一,查詢能力。Firebase 選擇的文檔模型簡化了抽象管理,但會破壞你的查詢能力。很多時候,你必須對數據做反正則化,或者查詢變得很難處理。例如,要記錄像好友這樣的多對多關系,你需要執行以下操作:

userA:  friends:  userBId: true userB: friends: userAId: true

你通過兩個不同的路徑(userA/friends/userBId)和(userB/friends/userAId)對好友關系進行反正則化。要獲取完整數據,你需要手動復制一個聯接(join):

1. get `userA/friends`2. for each id, get `/$`

這種關系在你的應用程序中很快就會出現。如果能有解決方案幫助你處理它就太好了。

第二,權限。Firebase 要求你使用一種受限的語言來編寫權限。在實踐中,這些規則很快就會變得非常混亂——于是人們開始自己編寫一些高級語言并編譯成 Firebase 規則。

我們在 Facebook 對此進行了大量實驗,得出的結論是,你需要一種真正的語言來表達權限。如果 Firebase 有這樣的語言就會更加強大。

至于剩下的項目(審計、撤消 / 重做、寫入的離線模式、衍生數據)——Firebase 還沒有解決它們。

Supabase

Supabase 正在嘗試做 Firebase 為 Mongo 所做的事情,但 Supabase 是為 Postgres 做的。如果他們成功了,這將是一個非常有吸引力的選擇,因為它將解決 Firebase 面臨的最大問題:查詢能力。

到目前為止,Supabase 取得了一些重大進展。他們的身份驗證抽象非常棒,這讓它成為少數幾個像 firebase 一樣容易上手的平臺之一。

他們的實時選項允許你訂閱行級更新。例如,如果我們想知道一個好友是何時被創建、更新或更改的,我們可以這樣寫:

const friendsChange = supabase .from('friendships:friend_one_id=eq.200') .on('*', handleFriendshipChange) .subscribe()

在實踐中這可以讓你走得更遠。不過它可能會變得很麻煩。例如,如果我們創建了一個好友,我們可能沒有用戶信息,所以必須獲取它。

function handleFriendshipChange(friendship) {  if (!userStore.get(friendship.friend_two_id)) {  fetchUser(...) }}

這里指出了 Supabase 的主要弱點:它還沒有“瀏覽器上的數據庫”這種抽象。雖然你可以做查詢,但你要自己負責正則化并處理數據。這意味著它不能自動進行樂觀更新,不能做響應式查詢等。他們的權限模型也很像 Firebase,因為它遵循了 Postgres 的行級安全性。一開始這是很好用的,但就像 Firebase,它很快就會變得很麻煩。這些規則往往會拖慢查詢優化器的速度,并且 SQL 本身會變得越來越難推理。

GraphQL+Hasura

GraphQL 是一種很好的方法來聲明性地定義你想要從客戶端獲取的數據。像 Hasura 這樣的服務可以使用像 Postgres 這樣的數據庫,并做一些聰明的事情,比如給你一個 GraphQL API。

Hasura 很適合讀取數據。他們在處理聯接方面做得很聰明,并且可以給你一個很好的數據視圖。你可以用一個 flip 將任何查詢轉換為訂閱。當我第一次嘗試將查詢轉換為訂閱時,確實感覺這很神奇。

今天 GraphQL 工具的一大問題是它們的原型制作速度。你往往需要多個不同的庫和構建步驟。他們在數據寫入方面做得也沒那麼好。樂觀更新不會自動發生——你必須自己處理它。

小結

我們已經研究了三個最有前途的解決方案。現在,Firebase 可以立刻解決大多數問題。Supabase 以犧牲更多客戶端支持為代價為你提供了更好的查詢能力。Hasura 以犧牲原型制作速度為代價,為你提供了更強大的訂閱和更強大的本地狀態。據我所知,還沒有方案能在客戶端解決沖突,提供撤消 / 重做和強大的響應式查詢。

5未來

現在的問題是:這些工具會演變成什麼樣子?

在某些層面,未來已經到來了。例如,我認為 Figma 就是一款來自未來的應用:它可以出色地處理離線模式、撤消 / 重做和多人關系。如果我們想制作這樣的應用,理想的數據抽象應該是什麼樣的?

需求

客戶端數據庫,有著強大的查詢語言

從瀏覽器來看,這種抽象必須像 firebase 一樣,但要有強大的查詢語言。

你應該能夠查詢本地數據,并且它應該與 SQL 一樣強大。你的查詢應該是響應式的,如果有更改會自動更新。它也應該為你處理樂觀更新。

user = useQuery("SELECT * FROM users WHERE id = ?", 10);

真正的權限語言

接下來,我們需要一種可組合的權限語言。FB 的 EntFramework 也是我經常使用的例子,因為它非常強大。我們應該能夠定義實體的規則,并且應該保證我們不會意外看到不允許我們看到的東西。

User {  view: [ IAllowIfAdmin(), IAllowIfFriend(), IAllowIfSameUser(), ] write: [ IAllowIfAdmin(), IAllowIfFriend(), ]}

離線模式和撤消 / 重做

最后,這個抽象應該讓我們更容易實現離線模式,或者撤消重做。如果發生本地寫入,并且服務器上存在寫入沖突,則應該有一個協調器在大多數情況下做出正確的決定。如果有問題,我們應該能夠朝著正確的方向推動它前進。

無論我們選擇什麼抽象,它都應該讓我們能夠在離線時運行寫入操作。

下一個云

最后,我們應該能夠表達數據依賴關系,而無需啟動任何東西。一個簡單的命令:

db.user |> Redis

對用戶的所有查詢都應該神奇地被 Redis 緩存。

實現的草圖

好吧,這些需求聽起來很神奇。那麼今天滿足它們的實現會是什麼樣子?

Diatomic 和 Datascript

在 Clojure 世界中,人們長期以來一直是 Datomic 的粉絲。Datomic 是一個基于事實的數據庫,可以讓你“看到時間線上的每一個更改”。Nikita Tonsky 還實現了 datascript,這是一個與 Datomic 語義相同的客戶端數據庫和查詢引擎!

它們已被用于構建支持離線的應用程序(如 Roam)或協作應用程序(如 Precursor)。如果我們在后端打包一個類似 Datomic 的數據庫,在前端打包一個類似 datascript 的數據庫,它就可以成為“具有強大查詢語言的客戶端數據庫”!

響應性

Datomic 讓你可以輕松地將新提交的事實訂閱到數據庫。如果我們在頂層創建一個服務,讓它保留查詢并聽取這些事實,是不是會很棒?出現一個更改后,我們將更新相關查詢。突然之間,我們的數據庫變成實時的了!

權限語言

我們的服務器可以接受一些代碼片段,并在獲取數據時運行它們。這些片段將負責處理權限,為我們提供強大的權限語言!

管道

最后,我們可以編寫一些 DSL,讓你可以根據用戶的喜好將數據通過管道傳輸到 Elastic Search、Redis 等。

有了它,我們就有了一個優秀的方案。

注意事項

那麼,為什麼這種方案還不存在呢?那是因為……

Datalog 還不流行

如果我們使用 Datomic 這樣的數據庫,我們就不會再使用 SQL。Datomic 使用一種基于邏輯的查詢語言,稱為 Datalog。現在它與 SQL 一樣強大,甚至更為強大。唯一的問題是,對于外行來說,它看起來非常難上手的樣子:

[:find [(pull ?c [:conversation/user :conversation/message]) ...] :where [?e :session/thread ?thread-id]  [?c :conversation/thread ?thread-id]]

這個查詢將查找當前“會話”中活動線程的所有消息以及用戶信息。不錯!一旦你學會了它,就會意識到它是一種優雅而出色的語言。但我認為這還不夠。原型制作速度需要非常快才行,我們可能沒時間去學這種語言了。

有一些有趣的實驗可以簡化這一過程。例如,Dennis Heihoff嘗試 使用自然語言。這給我們啟發了一種有趣的解決方案:我們能否編寫一種稍微冗長但更加自然的查詢語言,把它編譯為 Datalog?我認同這種想法。

另一個問題是數據建模也與人們習慣的做法不一樣。Firebase 是黃金標準,你可以在不指定任何 schema 的情況下編寫你的第一個更改。

雖然做起來很難,但我認為我們的目標應該是盡可能接近“簡單易用”。Datascript 只要求你指明引用和多值屬性。Datomic 需要一個 schema,但也許如果我們使用開源的、基于 datalog 的數據庫,我們可以增強它來做類似的事情。要麼盡可能少用 schema,要麼是“神奇的可檢測 schema”。

Datalog 很難實現響應性

SQL 和 Datalog 都存在的一個大問題是,它們很難基于一些新的更改來確定哪些查詢需要更新。

我不認為這是不可能解決的障礙。Hasura 可以做輪詢,而且可擴展。我們也可以嘗試使用特定的訂閱語言,類似于 Supabase。如果我們可以證明某些查詢只能通過事實的某些子集來更改,我們可以將它們從輪詢中移出。

這是一個棘手的問題,但我認為它還是可以解決的。

權限語言會減慢速度

讓權限檢查成為一種成熟的語言的話,一個問題是我們容易過度獲取數據。

我認為這個問題是值得考慮的,但如果使用像 Datomic 這樣的數據庫,我們就可以解決它。數據讀取很容易擴展和緩存。因為一切都是事實,我們可以創建一個界面來引導人們只獲取他們需要的值。

Facebook 就做到了這一點。這可能會很難,但終究是可行的。

這個抽象可能太大了

框架通常無法通用化。例如,如果我們想共享鼠標位置怎麼辦?這是短暫的狀態,不適合數據庫,但我們確實需要讓它實時化——我們應該把它保存在哪里?如果你構建這樣的抽象,將會出現很多這樣的事情,并且你很可能會搞錯。

我認為這確實是一個問題。如果有人要解決這個問題,最好的辦法是采用 Rails 方法:使用它構建一個生產應用,并將內部組件提取為產品。我認為他們很有可能找到正確的抽象。

它只會用于玩具項目

這類產品的共同問題是,人們只會將它們用于業余愛好項目,而且里面不會有很多商機。我認為 Heroku 和 Firebase 在這里指明了正確的出路。

大企業都是從業余項目開始起家的。老一輩工程師可能將 Firebase 視為玩具,但現在許多成功的初創公司都在使用 Firebase。它不僅僅是一個數據庫,也許它還會成為一個全新的平臺——甚至是 AWS 的繼任者。

市場競爭非常激烈

市場競爭非常激烈,用戶變化無常。Slava 的《為什麼 RethinkDB 會失敗》描繪了在開發工具市場中獲勝的難度有多大。我不認為他是錯的。這樣做需要對如何構建護城河并擴展成下一個 AWS 給出令人信服的回答。

6結語

好吧,我們涵蓋了痛點,討論了競爭對手,介紹了理想的解決方案,并考慮了諸多問題。謝謝你陪我走過這段旅程!

發文者:鏈站長,轉載請註明出處:https://www.jmb-bio.com/4171.html

讚! (0)
Donate 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Previous 2023 年 2 月 28 日 下午 9:42
Next 2023 年 2 月 28 日 下午 9:50

相關文章

  • LiquiDEX 兩步原子切換式通訊協定解析:掌握最新區塊鏈技術!

    長話短說:LiquiDEX 是一個在 Liquid網絡上執行兩步原子交換(atomic swaps)的協議,它只需要交換方的單次交互,這極大地改善了用戶體驗。而使用該協議,我們可以構建出更復雜系統的構建塊,例如自動 OTC 交易柜臺、拍賣系統甚至去中心化交易所 (DEX)。 注:LiquiDEX的產品還不可用。 簡介:Liquid網絡和原子交換技術 Liqu…

    2023 年 2 月 28 日
  • 乙太坊智慧合約解析:解碼智慧合約資料!

    正如我們在之前的文章中所討論的,智能合約交易類似于智能合約驅動的web3應用程序中的后端API調用。每個智能合約交易和結果應用程序狀態更改的細節都記錄在稱為交易、調用和日志的數據元素中。交易數據元素表示用戶發起的函數調用(更準確地說是EOA),調用數據元素表示智能合約在交易中發起的其他函數調用,而日志數據元素表示交易執行期間發生的事件。 使用這些數據元素,可…

    2023 年 2 月 28 日
  • EVM 存儲機制詳解:深入理解乙太坊技術與安全問題!

    前言 EVM 是一個輕量級的虛擬機,其設計初衷就是提供一種可以忽略硬件、操作系統等兼容性的虛擬的執行環境供以太坊網絡運行智能合約。 簡單來說 EVM 是一個完全獨立的沙盒,在 EVM 中運行的代碼是無法訪問網絡、文件系統和其他進程的,以此來避免錯誤的代碼能讓智能合約毀滅或者影響外部環境。 在此基礎上,知道創宇區塊鏈安全實驗室 帶大家一起深入理解 E…

    2023 年 2 月 28 日
  • Uniswap v3 設計原理詳解(一):掌握 Uniswap 的核心技術!

    剛看完 Uniswap v2 的代碼,本來打算寫一個 Uniswap v2 設計與實現,結果 Uniswap v3 就發布了。趁著這個機會就先寫一個 Uniswap v3 設計與實現吧。 因為 v3 版本的實現復雜度和 v2 已經不在一個量級了,難免會有理解上的偏差,本文權當是拋磚引玉,也希望有更多的人參與討論。因為實現比較復雜,本系列會拆分成多篇文章,持續…

    2023 年 2 月 28 日
  • NFT 資產安全問題:白帽駭客 samczsun 警告攻擊頻繁!

    注:原文作者是擁有“審計上帝”之稱的白帽黑客samczsun,同時他也是Paradigm的研究合伙人,其最近出手拯救了BitDAO MISO荷蘭拍賣資金池中的3.5億美元資產,而在這篇文章中,他提醒了關于NFT代幣標準的潛在安全風險,他還預測稱,隨著ERC-721和ERC-1155代幣標準變得越來越流行,針對NFT的攻擊很可能會越來越頻繁。 如果你從事軟件工…

    2023 年 2 月 28 日
每日鏈頭條給你最新幣圈相關資訊!