IPFS身份管理和初始化本地仓库
由于IPFS网络是没有中心服务器的,各个节点之间的数据传输是需要识别各个节点的,并且要求各个节点的ID是唯一的,如果没有一定的生成规则,就带来了挑战。在IPFS中,IPFS节点ID是这样规定的。
1。节点要自己生成一个基于PKI(https://en.wikipedia.org/wiki/Public_key_infrastructure)的秘钥对。
2.对密钥对中的公钥做hash也就是HASH(节点公钥),就得到了节点的ID
默认生成的节点秘钥配置放在文件夹:~/.ipfs/config ,如果你没有自定义IPFS_PATH的话。
例如我本机的
"Identity":{
**"PeerID"**:**"QmQeJWckGKS9C56NtyvqA3APsq4gbtS8YwPnLTb9ZT3dd4"**,
**"PrivKey"**:**"privateKey"**
},
说明:~/.ipfs/config内容狠多,只是抽取identity
疑问:
这里如果节点作恶了,我从新生成一对密钥对就OK拉 !!!怎么办?
节点ID的使用,当两个节点需要通信的时候
1.交换两个节点的公钥
2.检测HASH(节点公钥)是否等于节点ID
3.如果检测不相等,就退出。
IPFS command 结构
IPFS每一个命令的结构大致如下
[图片上传失败...(image-f0edd7-1532334776759)]
IPFS 初始化流程
初始化命令
ipfs init
命令代码分析,主要入口文件:/Users/zhang/go/src/github.com/ipfs/go-ipfs/cmd/ipfs/init.go
init命令运行的时候
1.在postRun中检测是否配置文件所在的repo在是否存在repo.lock文件,有就代表ipfs的deamon进程存在,就退出(代码init.go 61行)
[图片上传失败...(image-7a1152-1532334776759)]
2.根据输入的options参数(可选参数中值得注意的是--bits,指定生成的秘钥的长度,默认2048 ,profile,指定生成的配置文件名称),执行doInit方法.
A。 在doInit先检测IPFS所在文件系统的读写权限。
B。 检测fsrepo是否存在了节点config文件
C。如果没有存在config,执行初始化流程如下:
细节:加密秘钥长度必须最少是2048,如果太小报错
a。调用libp2p-crypto库的GenerateKeyPair生成密钥对,加密方法RSA。其中私钥使用base64.StdEncoding.EncodeToString方法转换为字符串。公钥调用go-libp2p-peer的IDFromPublicKey方法得到字符串x,最终字符串x调用libp2p的IDB58Encode方法编码为字符串hash,这个hash就是节点ID
b。读取启动节点,也就是bootstrap peer,这些节点决定了本地节点启动的时候链接谁的问题。默认系统默认硬编码了如下节点。这些节点由IPFS官方来维护。
var DefaultBootstrapAddresses = []string{
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
"/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io
"/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io
"/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io
"/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io
"/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io
"/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", // pluto.i.ipfs.io
"/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", // saturn.i.ipfs.io
"/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", // venus.i.ipfs.io
"/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", // earth.i.ipfs.io
}
c。读取数据存储默认配置文件DefaultDatastoreConfig,代码: src/github.com/ipfs/go-ipfs/repo/config/init.go 25行。
数据存储
数据存储是数据存储和数据库访问的通用抽象层。它是一个简单的API,其目的是使应用程序开发以数据不可知的方式进行,允许在不改变应用程序代码的情况下无缝地交换数据存储。因此,您可以利用具有不同强度的不同数据存储,而无需将应用程序在整个生命周期内提交给一个数据存储。
代码库
https://github.com/ipfs/go-datastore
配置文件如下
func DefaultDatastoreConfig() Datastore {
return Datastore{
StorageMax: "10GB",
StorageGCWatermark: 90, // 90%
GCPeriod: "1h",
BloomFilterSize: 0,
Spec: map[string]interface{}{
"type": "mount",
"mounts": []interface{}{
map[string]interface{}{
"mountpoint": "/blocks",
"type": "measure",
"prefix": "flatfs.datastore",
"child": map[string]interface{}{
"type": "flatfs",
"path": "blocks",
"sync": true,
"shardFunc": "/repo/flatfs/shard/v1/next-to-last/2",
},
},
map[string]interface{}{
"mountpoint": "/",
"type": "measure",
"prefix": "leveldb.datastore",
"child": map[string]interface{}{
"type": "levelds",
"path": "datastore",
"compression": "none",
},
},
},
},
}
}
默认存储空间10G,每小时一次GC,挂载点2个,一个是leveldb一个是flatfs,应该也是可以配置的。
d。读取本地地址默认配置,代码位置 src/github.com/ipfs/go-ipfs/repo/config/init.go 101行。
配置如下
func addressesConfig() Addresses {
return Addresses{
Swarm: []string{
"/ip4/0.0.0.0/tcp/4001",
// "/ip4/0.0.0.0/udp/4002/utp", // disabled for now.
"/ip6/::/tcp/4001",
},
Announce: []string{},
NoAnnounce: []string{},
API: "/ip4/127.0.0.1/tcp/5001",
Gateway: "/ip4/127.0.0.1/tcp/8080",
}
}
可见,本地Swarm监听4001端口,使用这个端口和其他节点通信。支持IPV4和IPV6,默认不支持UDP方式。本地Api网关,127.0.0.1:5001 ,本地资源网关127.0.0.1:8080 。
e。配置组播配置
Discovery: Discovery{
MDNS: MDNS{
Enabled: true,
Interval: 10,
},
},
使用MDNS协议来组网。在一个没有常规DNS服务器的小型网络内,可以使用mDNS来实现类似DNS的编程接口、包格式和操作语义。具体:https://www.cnblogs.com/yuweifeng/p/6409182.html
f。设置路由
Routing: Routing{
Type: "dht",
},
g。设置挂载点
Mounts: Mounts{
IPFS: "/ipfs",
IPNS: "/ipns",
},
h。设置资源网管headers等信息
Gateway: Gateway{
RootRedirect: "",
Writable: false,
PathPrefixes: []string{},
HTTPHeaders: map[string][]string{
"Access-Control-Allow-Origin": []string{"*"},
"Access-Control-Allow-Methods": []string{"GET"},
"Access-Control-Allow-Headers": []string{"X-Requested-With", "Range"},
},
},
i。读取和设置swarm配置
Swarm: SwarmConfig{
ConnMgr: ConnMgr{
LowWater: DefaultConnMgrLowWater,
HighWater: DefaultConnMgrHighWater,
GracePeriod: DefaultConnMgrGracePeriod.String(),
Type: "basic",
},
},
D。解析配置文件
E。真正调用:fsrepo.Init(repoRoot, conf) 代码:161行。
a。写入C步骤生成的config文件到repo路径下面
b。初始化datastore空间
c。在repo下面写入版本WriteVersion
F。如果参数默认,调用addDefaultAssets写入默认readme文件到本地repo
到此为止,infs init 流程结束。
Multihash
https://github.com/multiformats/multihash
https://multiformats.io/multihash/#implementations
为何要有multihash?
本质上为了升级方便,现有的各种加密算法,不能保证以后不出问题。第三方如果依赖于使用的hash算法的名字和长度,以后升级就会带来各种各样的问题。为此,multihash就出来了,它采用TLV (type-length-value) 的方式抽象了Hash的使用~ 解决了依赖于hash 函数和 长度的问题。
在IPFS中使用multihas的地方主要是ipfs object分块和地址这里。