Swarm
Swarm是以太坊的去中心化和分布式的存儲解決方案,與IPFS類似。 Swarm是一種點對點數據共享網絡,其中文件通過其內容的哈希來尋址。與Bittorrent類似,可以同時從多個節點獲取數據,只要單個節點承載分發數據,它就可以隨處被訪問。這種方法可以在不必依靠托管任何類型服務器的情況下分發數據 - 數據可訪問性與位置無關。可以激勵網絡中的其他節點自己復制和存儲數據,從而在原節點未連接到網絡時避免了對托管服務的依賴。
Swarm的激勵機制Swap(Swarm Accounting Protocol)是一種協議,通過該協議,Swarm網絡中的個體可以跟蹤傳送和接收的數據塊,以及由此產生相應的(微)付款。 SWAP本身可以在更廣泛的背景下運行,但它通常表現為適用于點對點之間成對會計的通用微支付方案。雖然設計通用,但它的第一個用途是將帶寬計算作為Swarm去中心化的點對點存儲網絡中數據傳輸的激勵的一部分。
搭建 Swarm 節點
要運行swarm,首先需要安裝geth
和bzzd
,這是swarm背景進程。
go get -d github.com/ethereum/go-ethereum
go install github.com/ethereum/go-ethereum/cmd/geth
go install github.com/ethereum/go-ethereum/cmd/swarm
然后我們將生成一個新的geth帳戶。
$ geth account new
Your new account is locked with a password. Please give a password. Do not forget this password.
Passphrase:
Repeat passphrase:
Address: {970ef9790b54425bea2c02e25cab01e48cf92573}
將環境變量BZZKEY
導出,并設定為我們剛剛生成的geth帳戶地址。
export BZZKEY=970ef9790b54425bea2c02e25cab01e48cf92573
然后使用設定的帳戶運行swarm,并作為我們的swarm帳戶。 默認情況下,Swarm將在端口“8500”上運行。
$ swarm --bzzaccount $BZZKEY
Unlocking swarm account 0x970EF9790B54425BEA2C02e25cAb01E48CF92573 [1/3]
Passphrase:
WARN [06-12|13:11:41] Starting Swarm service
現在swarm進程已經可以運行了,那么我們會在下個章節
完整代碼
Commands
go get -d github.com/ethereum/go-ethereum
go install github.com/ethereum/go-ethereum/cmd/geth
go install github.com/ethereum/go-ethereum/cmd/swarm
geth account new
export BZZKEY=970ef9790b54425bea2c02e25cab01e48cf92573
swarm --bzzaccount $BZZKEY
上傳文件到Swarm
在上個章節我們在端口“8500”上運行了一個作為背景進程的swarm節點。 接下來就導入swarm包go-ethereumswearm/api/client
。 我將把包裝別名為bzzclient
。
import (
bzzclient "github.com/ethereum/go-ethereum/swarm/api/client"
)
調用NewClient
函數向它傳遞swarm背景程序的url。
client := bzzclient.NewClient("http://127.0.0.1:8500")
用內容 hello world 創建示例文本文件hello.txt
。 我們將會把這個文件上傳到swarm。
hello world
在我們的Go應用程序中,我們將使用Swarm客戶端軟件包中的“Open”打開我們剛剛創建的文件。 該函數將返回一個File
類型,它表示swarm清單中的文件,用于上傳和下載swarm內容。
file, err := bzzclient.Open("hello.txt")
if err != nil {
log.Fatal(err)
}
現在我們可以從客戶端實例調用Upload
函數,為它提供文件對象。 第二個參數是一個可選添的現有內容清單字符串,用于添加文件,否則它將為我們創建。 第三個參數是我們是否希望我們的數據被加密。
返回的哈希值是文件的內容清單的哈希值,其中包含hello.txt文件作為其唯一條目。 默認情況下,主要內容和清單都會上傳。 清單確保您可以使用正確的mime類型檢索文件。
manifestHash, err := client.Upload(file, "", false)
if err != nil {
log.Fatal(err)
}
fmt.Println(manifestHash) // 2e0849490b62e706a5f1cb8e7219db7b01677f2a859bac4b5f522afd2a5f02c0
然后我們就可以在這里查看上傳的文件 bzz://2e0849490b62e706a5f1cb8e7219db7b01677f2a859bac4b5f522afd2a5f02c0
,具體如何下載,我們會在下個章節介紹。
完整代碼
Commands
geth account new
export BZZKEY=970ef9790b54425bea2c02e25cab01e48cf92573
swarm --bzzaccount $BZZKEY
hello world
package main
import (
"fmt"
"log"
bzzclient "github.com/ethereum/go-ethereum/swarm/api/client"
)
func main() {
client := bzzclient.NewClient("http://127.0.0.1:8500")
file, err := bzzclient.Open("hello.txt")
if err != nil {
log.Fatal(err)
}
manifestHash, err := client.Upload(file, "", false)
if err != nil {
log.Fatal(err)
}
fmt.Println(manifestHash) // 2e0849490b62e706a5f1cb8e7219db7b01677f2a859bac4b5f522afd2a5f02c0
}
從Swarm下載文件
在上個章節 我們將一個hello.txt文件上傳到swarm,作為返回值,我們得到了一個內容清單哈希。
manifestHash := "f9192507e2e8e118bfedac428c3aa1dec4ae156e954128ec5fb27f63ee67bcac"
讓我們首先通過調用“DownloadManfest”來下載它,并檢查清單的內容。
manifest, isEncrypted, err := client.DownloadManifest(manifestHash)
if err != nil {
log.Fatal(err)
}
我們可以遍歷清單條目,看看內容類型,大小和內容哈希是什么。
for _, entry := range manifest.Entries {
fmt.Println(entry.Hash) // 42179060941352ba7b400b16c40f1e1290423a826de2a70587034dc14bc4ab2f
fmt.Println(entry.ContentType) // text/plain; charset=utf-8
fmt.Println(entry.Path) // ""
}
如果您熟悉swarm url,它們的格式為bzz:/ <hash> / <path>
,因此為了下載文件,我們指定了清單哈希和路徑。 在這個例子里,路徑是一個空字符串。 我們將這些數據傳遞給Download
函數并返回一個文件對象。
file, err := client.Download(manifestHash, "")
if err != nil {
log.Fatal(err)
}
我們現在可以閱讀并打印返回的文件閱讀器的內容。
content, err := ioutil.ReadAll(file)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(content)) // hello world
正如預期的那樣,它記錄了我們原始文件所包含的 hello world。
完整代碼
Commands
geth account new
export BZZKEY=970ef9790b54425bea2c02e25cab01e48cf92573
swarm --bzzaccount $BZZKEY
package main
import (
"fmt"
"io/ioutil"
"log"
bzzclient "github.com/ethereum/go-ethereum/swarm/api/client"
)
func main() {
client := bzzclient.NewClient("http://127.0.0.1:8500")
manifestHash := "2e0849490b62e706a5f1cb8e7219db7b01677f2a859bac4b5f522afd2a5f02c0"
manifest, isEncrypted, err := client.DownloadManifest(manifestHash)
if err != nil {
log.Fatal(err)
}
fmt.Println(isEncrypted) // false
for _, entry := range manifest.Entries {
fmt.Println(entry.Hash) // 42179060941352ba7b400b16c40f1e1290423a826de2a70587034dc14bc4ab2f
fmt.Println(entry.ContentType) // text/plain; charset=utf-8
fmt.Println(entry.Size) // 12
fmt.Println(entry.Path) // ""
}
file, err := client.Download(manifestHash, "")
if err != nil {
log.Fatal(err)
}
content, err := ioutil.ReadAll(file)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(content)) // hello world
}