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.txt
hello world
swarm_upload.go
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:/
,因此为了下载文件,我们指定了清单哈希和路径。 在这个例子里,路径是一个空字符串。 我们将这些数据传递给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
swarm_download.go
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
}