2021-07-07-sector状态机

2021-07-07-sector状态机 Block Chain Lotus Sector 状态机 状态机什么时候启动? 启动 miner,创建全局唯一Sealing对象(lotus/extern/storage-sealing/sealing.go:145) Sealing 对象run,会定期的检查是否开启刷单,如果刷单会调用一个 PledgeSector(lotus/extern/storage-sealing/garbage.go:13),承诺一个新的扇区 在 PledgeSector 的结束会调用 Sealing.sectors.Send(id, evt)(github.com/filecoin-project/go-statemachine@v0.0.0-20200925024713-05bd7c71fbfe/group.go:85),这个方法非常重要,几乎所有的状态变更都依赖这个。(tips:Sealing内部的sectors,类型是statemachine.StateGroup,这个 StateGroup 就负责所有sector的状态机管理) 第一次调用 Send 时,会通过id先在 StateGroup.sms(map[datastore.Key]*StateMachine),理论上这时候是没有这个状态机的,只有走到StateGroup.loadOrCreate(id, userState)(github.com/filecoin-project/go-statemachine@v0.0.0-20200925024713-05bd7c71fbfe/group.go:102)中加载或者创建一个状态机,然后一个 go res.run(),状态机就运行起来了 状态机如何变化状态? 先看一下状态机的结构: type StateMachine struct { planner Planner eventsIn chan Event name interface{} st *statestore.StoredState stateType reflect.Type stageDone chan struct{} closing chan struct{} closed chan struct{} busy int32 } planner 是计划处理函数,它返回状态变化函数和已经处理的事件数量,可以看下面的tips eventsIn 是一个管道,在其他地方传递数据过来,在 ## 状态机什么时候启动? 提到的 go res.run() 里每次循环出输出给一个切片 stageDone 和 closing 是两个标志位,在状态机运行中会循环检测 busy 是一个会被原子操作的值,可以理解为一个锁。 其他数据就是状态机的元数据 # planner // Planner processes in queue events // It returns: // 1. a handler of type -- func(ctx Context, st <T>) (func(*<T>), error), where <T> is the typeOf(User) param // 2. the number of events processed // 3. an error if occured # 状态机变化图 // Now decide what to do next /* UndefinedSectorState (start) v | *<- WaitDeals <-> AddPiece | | | /--------------------/ | v v *<- Packing <- incoming committed capacity | | | v | GetTicket | | ^ | v | *<- PreCommit1 <--> SealPreCommit1Failed | | ^ ^^ | | *----------++----\ | v v || | *<- PreCommit2 --------++--> SealPreCommit2Failed | | || | v /-------/| * PreCommitting <-----+---> PreCommitFailed | | | ^ | v | | *<- WaitSeed -----------+-----/ | ||| ^ | | ||| \--------*-----/ | ||| | | vvv v----+----> ComputeProofFailed *<- Committing | | | ^--> CommitFailed | v ^ | SubmitCommit | | | | | v | *<- CommitWait ---/ | | | v | FinalizeSector <--> FinalizeFailed | | | v *<- Proving | v FailedUnrecoverable */ 其实状态改变的函数是在 (github.com/filecoin-project/go-statemachine@v1.0.1/machine.go:103)实现的,通过反射实现的。只有当状态改变完成后才会修改fsm.busy。 ...

January 16, 2026

2021-07-06-minio 与其他分布式系统的异同点

2021-07-06-minio 与其他分布式系统的异同点 file system [[MinIO]] minio 与其他(开源)分布式系统的异同点 关键信息总揽 文件系统 易用性 团队技术需求 存储利用率 推荐 MinIO 易 中 75%/87% 推荐 Ceph 中 高,尤其是初期 75%或87%或1/n 推荐 HDFS 难 中 1/n 不推荐 NFS+裸机 易 低 87% 推荐 整体对比 文件系统 开发者 开发语言 开源协议 易用性 适用场景 特性 缺点 MinIO MinIO Inc go GNU AGPLv3 简单 混合云场景/裸机 云原生、有弹性、纠删码机制、加密、防篡改 存储利用率 GFS Google 不开源 - - - - HDFS Apache Java Apache 安装简单,官方文档专业化 存储非常大的文件 大数据批量读写,吞吐量高;一次写入,多次读取,顺序读写 难以满足毫秒级别的低延时数据访问;不支持多用户并发写相同文件;不适用于大量小文件 Ceph 加州大学圣克鲁兹分校Sage Weil C++ LGPL 安装简单,官方文档专业化 单集群的大中小文件 分布式,没有单点依赖,用C编写,性能较好 基于不成熟的btrfs,自身也不够成熟稳定,不推荐在生产环境使用 TFS Alibaba C++ GPL V2 安装复杂,官方文档少 跨集群的小文件 针对小文件量身定做,随机IO性能比较高;实现了软RAID,增强系统的并发处理能力及数据容错恢复能力;支持主备热倒换,提升系统的可用性;支持主从集群部署,从集群主要提供读/备功能 不适合大文件的存储;不支持POSIX,通用性较低;不支持自定义目录结构与文件权限控制;通过API下载,存在单点的性能瓶颈;官方文档少,学习成本高 Lustre SUN C GPL 复杂,而且严重依赖内核,需要重新编译内核 大文件读写 企业级产品,非常庞大,对内核和ext3深度依赖 MooseFS Core Sp. z o.o. C GPL V3 安装简单,官方文档多,且提供Web界面的方式进行管理与监控 大量小文件读写 比较轻量级,用perl编写,国内用的人比较多 对master服务器有单点依赖,性能相对较差 MogileFS Danga Interactive Perl GPL 主要用在web领域处理海量小图片 key-value型元文件系统;效率相比mooseFS高很多 不支持FUSE FastDFS 国内开发者余庆 C GPL V3 安装简单,社区相对活跃 单集群的中小文件 系统无需支持POSIX,降低了系统的复杂度,处理效率更高;实现了软RAID,增强系统的并发处理能力及数据容错恢复能力;支持主从文件,支持自定义扩展名;主备Tracker服务,增强系统的可用性 不支持断点续传,不适合大文件存储;不支持POSIX,通用性较低;对跨公网的文件同步,存在较大延迟,需要应用做相应的容错策略;同步机制不支持文件正确性校验;通过API下载,存在单点的性能瓶颈 GlusterFS Z RESEARCH C GPL V3 安装简单,官方文档专业化 适合大文件,小文件性能还存在很大优化空间 无元数据服务器,堆栈式架构(基本功能模块可以进行堆栈式组合,实现强大功能),具有线性横向扩展能力;比mooseFS庞大 由于没有元数据服务器,因此增加了客户端的负载,占用相当的CPU和内存;但遍历文件目录时,则实现较为复杂和低效,需要搜索所有的存储节点,不建议使用较深的路径 GridFS MongoDB C++ 安装简单 通常用来处理大文件(超过16M) 可以访问部分文件,而不用向内存中加载全部文件,从而保持高性能;文件和元数据自动同步 选型参考 适合做通用文件系统的有:MinIO,Ceph,Lustre,MooseFS,GlusterFS; 适合做小文件存储的文件系统有:MinIO,Ceph,MooseFS,MogileFS,FastDFS,TFS; 适合做大文件存储的文件系统有:MinIO,HDFS,Ceph,Lustre,GlusterFS,GridFS; 轻量级文件系统有:MooseFS,FastDFS; 简单易用,用户数量活跃的文件系统有:MooseFS,MogileFS,FastDFS,GlusterFS; 支持FUSE挂载的文件系统有:HDFS,Ceph,Lustre,MooseFS,GlusterFS。 分布式实现方案 MinIO:纠删码机制 Ceph:RADOS,RADOS系统主要由两部分组成,分别是OSD和Monitor。 HDFS:master/slave架构,数据分块,添加副本 推荐主机硬件 fs CPU memory network drives MinIO Dual Intel® Xeon® Scalable GoId CPUs (minimum 8 cores per socket). 128GB RAM 25GbE for high-density and 100GbE NICs for high-performance. SATA/SAS HDDs for high-density and NVMe SSDs for high-performance (minimum of 8 drives per server). HDFS-NameNode 2 个 4/8/16 核心处理器,主频至少为 2-2.5GHz 64 - 128G 内存 千兆网卡或万兆网卡 4-6块 1TB 硬盘(1块给操作系统,2块给FS image [RAID 1],1块给Zookeeper , 一块给Journal Node) HDFS-DataNode 2个 4/8/16核心处理器,主频至少2-2.5GHz 64-512BG 内存 千兆或万兆网卡(存储密度越高,需要的网络网络吞吐越高) 12-24块1-4TB硬盘 Ceph-MDS 4 核或更强悍的 CPU 至少每进程 1GB 双千兆 ssd Ceph-Monitor 单核/双核CPU 至少每进程 1GB 双千兆 ssd Ceph-OSD 双核 CPU 1GB/TB,存储多大,内存需求多大 双万兆 日志写入ssd,数据写入hdd,hdd可以很大 存储利用率以及可用性 先做一个基于NFS的基准数据。单盘16TB,单节点36盘,双raid5方案,对于单机来说,利用率为:(16*(36/2-1-1)*2)/(16*36) *100 = 88.89%。相对的,在双GHS情况下,36块盘允许2块盘故障,双DHS下,36块盘分成的2个raid各允许1块盘故障。 ...

January 16, 2026

2021-07-05-MineOne过程

2021-07-05-MineOne过程 Block Chain Lotus MineOne 过程 step1 :compute ticket func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, base *MiningBase, mbi *api.MiningBaseInfo) (*types.Ticket, error) { // 序列化 miner id buf := new(bytes.Buffer) if err := m.address.MarshalCBOR(buf); err != nil { return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err) } // round 为实际要计算的高度 round := base.TipSet.Height() + base.NullRounds + 1 if round > build.UpgradeSmokeHeight { buf.Write(base.TipSet.MinTicket().VRFProof) } // 根据 beccon miner round 随机生成 input 数据 // 采用 black2b hash 算法 input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { return nil, err } // 计算 vrf 数据 // bls wallet 对 input 签名的结果 vrfOut, err := gen.ComputeVRF(ctx, m.api.WalletSign, mbi.WorkerKey, input) if err != nil { return nil, err } return &types.Ticket{ VRFProof: vrfOut, }, nil } step2:判断在回合中是否胜出 func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch, miner address.Address, brand types.BeaconEntry, mbi *api.MiningBaseInfo, a MiningCheckAPI) (*types.ElectionProof, error) { buf := new(bytes.Buffer) if err := miner.MarshalCBOR(buf); err != nil { return nil, xerrors.Errorf("failed to cbor marshal address: %w", err) } electionRand, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_ElectionProofProduction, round, buf.Bytes()) if err != nil { return nil, xerrors.Errorf("failed to draw randomness: %w", err) } log.Infof("IsRoundWinner DrawRandomness: brand= %x, stage= ElectionProofProduction, round= %v, beacon= %x, electionRand= %x, WorkerKey= %s", brand.Data, round, buf.Bytes(), electionRand, mbi.WorkerKey.String()) vrfout, err := ComputeVRF(ctx, a.WalletSign, mbi.WorkerKey, electionRand) if err != nil { return nil, xerrors.Errorf("failed to compute VRF: %w", err) } // 进入ComputeWinCount ep := &types.ElectionProof{VRFProof: vrfout} j := ep.ComputeWinCount(mbi.MinerPower, mbi.NetworkPower) ep.WinCount = j log.Infof("IsRoundWinner ComputeWinCount: vrfout= %x, mPower= %x, nPower= %x, winCount= %v", vrfout, mbi.MinerPower, mbi.NetworkPower, ep.WinCount) if j < 1 { return nil, nil } return ep, nil } // 计算 wincount // ComputeWinCount uses VRFProof to compute number of wins // The algorithm is based on Algorand's Sortition with Binomial distribution // replaced by Poisson distribution. func (ep *ElectionProof) ComputeWinCount(power BigInt, totalPower BigInt) int64 { h := blake2b.Sum256(ep.VRFProof) lhs := BigFromBytes(h[:]).Int // 256bits, assume Q.256 so [0, 1) // We are calculating upside-down CDF of Poisson distribution with // rate λ=power*E/totalPower // Steps: // 1. calculate λ=power*E/totalPower // 2. calculate elam = exp(-λ) // 3. Check how many times we win: // j = 0 // pmf = elam // rhs = 1 - pmf // for h(vrf) < rhs: j++; pmf = pmf * lam / j; rhs = rhs - pmf // 求得泊松分布的 lambda // lam = (power * 5) << 256) / total lam := lambda(power.Int, totalPower.Int) // Q.256 // 根据 miner 算力和全网算力求得 k=0 时的泊松分布 p, rhs := newPoiss(lam) var j int64 // Max Wincount = 15 for lhs.Cmp(rhs) < 0 && j < MaxWinCount { rhs = p.next() j++ } return j } step3:compute proof 首先调用 store.DrawRandomness 产生需要进行计算证明的数据,和 step 中调用该方法时传入的参数一致 然后调用 ComputeProof() 进行计算,将 store.DrawRandomness 产生的源数据和 sector 信息传入,进行一些列处理后,调用 rust 计算 func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []builtin.SectorInfo, rand abi.PoStRandomness) ([]builtin.PoStProof, error) { if build.InsecurePoStValidation { return []builtin.PoStProof{{ProofBytes: []byte("valid proof")}}, nil } log.Infof("Computing WinningPoSt ;%+v; %v", ssi, rand) start := build.Clock.Now() proof, err := wpp.prover.GenerateWinningPoSt(ctx, wpp.miner, ssi, rand) if err != nil { return nil, err } log.Infof("GenerateWinningPoSt took %s", time.Since(start)) return proof, nil } step4:mpool select func (a *MpoolAPI) MpoolSelect(ctx context.Context, tsk types.TipSetKey, ticketQuality float64) ([]*types.SignedMessage, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) } return a.Mpool.SelectMessages(ctx, ts, ticketQuality) } func (mp *MessagePool) SelectMessages(ctx context.Context, ts *types.TipSet, tq float64) (msgs []*types.SignedMessage, err error) { mp.curTsLk.Lock() defer mp.curTsLk.Unlock() mp.lk.Lock() defer mp.lk.Unlock() // if the ticket quality is high enough that the first block has higher probability // than any other block, then we don't bother with optimal selection because the // first block will always have higher effective performance // 两种 select messages 的方式 // 1. 贪婪:获取 mpool pending 中的全部消息,将 message 组装成 message chain,只受 block 的最大 gas limit 限制 // 2. 择优:获取 mpool pending 中的全部消息,将 message 组装成 message chain,受 message chain 的最大数量(15个)、最大gas limit、评优计算限制 if tq > 0.84 { msgs, err = mp.selectMessagesGreedy(ctx, mp.curTs, ts) } else { msgs, err = mp.selectMessagesOptimal(ctx, mp.curTs, ts, tq) } if err != nil { return nil, err } // MaxBlockMessages = 16000 if len(msgs) > MaxBlockMessages { msgs = msgs[:MaxBlockMessages] } return msgs, nil } step5:create block 把 ticket 数据、IsRoundWinner 产生的数据、beacon、ComputeProof 产生的数据、msgs 进行打包 func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, eproof *types.ElectionProof, bvals []types.BeaconEntry, wpostProof []proof2.PoStProof, msgs []*types.SignedMessage) (*types.BlockMsg, error) { uts := base.TipSet.MinTimestamp() + build.BlockDelaySecs*(uint64(base.NullRounds)+1) nheight := base.TipSet.Height() + base.NullRounds + 1 // why even return this? that api call could just submit it for us return m.api.MinerCreateBlock(context.TODO(), &api.BlockTemplate{ Miner: addr, Parents: base.TipSet.Key(), Ticket: ticket, Eproof: eproof, BeaconValues: bvals, Messages: msgs, Epoch: nheight, Timestamp: uts, WinningPoStProof: wpostProof, }) }

January 16, 2026

2021-07-02-lotus使用mysql

2021-07-02-lotus使用mysql Block Chain Lotus Lotus 使用 MySQL 替代本地扫描 创建 mysql 服务 docker run --name lotus-mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql 创建数据库 # 需要等待一会,等待mysql服务启动 sleep 30 docker exec -it lotus-mysql bash mysql -u root -p CREATE DATABASE IF NOT EXISTS SL DEFAULT CHARSET utf8 COLLATE utf8_general_ci; 获取数据,生成dump.sql #! /bin/bash storage_path_array=("" "/minio/" "/nfs/store03/t07637_32G_newtest") # create file file_name=/tmp/dump.sql touch ${file_name} # create table cat>"${file_name}"<<EOF SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_storage_path -- ---------------------------- DROP TABLE IF EXISTS \`t_storage_path\`; CREATE TABLE \`SL\`.\`t_storage_path\` ( \`id\` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', \`storage_path\` varchar(255) NOT NULL DEFAULT '' COMMENT '存储路径', \`create_time\` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', \`update_time\` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (\`id\`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='存储路径表'; -- ---------------------------- -- Table structure for t_sector_storage -- ---------------------------- DROP TABLE IF EXISTS \`t_sector_storage\`; CREATE TABLE \`SL\`.\`t_sector_storage\` ( \`id\` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', \`sector_id\` varchar(255) NOT NULL DEFAULT '' COMMENT '扇区id', \`storage_path_id\` int(11) unsigned NOT NULL DEFAULT 1 COMMENT '存储路径id', \`state\` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态 1:正常 0:已删除', \`worker_name\` varchar(255) NOT NULL DEFAULT '' COMMENT 'worker名称', \`create_time\` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', \`update_time\` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (\`id\`), INDEX \`index_sector_id\`(\`sector_id\`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='扇区与存储路径关系表'; EOF # insert storage path cat>>"${file_name}"<<EOF -- ---------------------------- -- Records of t_storage_path -- ---------------------------- EOF echo "BEGIN;" >> "${file_name}" for element in ${storage_path_array[*]} do if [ -z $element ]; then continue fi printf "INSERT INTO t_storage_path(storage_path) VALUES(\"%s\");\n" ${element} >> "${file_name}" done echo "COMMIT;" >> "${file_name}" echo "SET FOREIGN_KEY_CHECKS = 1;" >> "${file_name}" echo "" >> "${file_name}" # insert sector path cat>>"${file_name}"<<EOF -- ---------------------------- -- Records of t_sector_storage -- ---------------------------- EOF echo "BEGIN;" >> "${file_name}" for i in "${!storage_path_array[@]}"; do if [ $i -eq 0 ]; then continue fi sector_arr=`ls -F ${storage_path_array[$i]}/sealed` for sector in ${sector_arr[*]} do sector_id=`echo $sector | sed "s/*//"` if [[ ${sector_id} == "fetching/" ]] then continue fi if [[ ${sector_id} =~ "st-base" ]] then continue fi printf "INSERT INTO t_sector_storage(sector_id, storage_path_id, state, worker_name) VALUES(\"%s\",%d, 1,\"null\");\n" ${sector_id} ${i} >> "${file_name}" done done echo "COMMIT;" >> "${file_name}" echo "SET FOREIGN_KEY_CHECKS = 1;" >> "${file_name}" mysql source docker cp /tmp/dump.sql lotus-mysql:/tmp/ docker exec -it lotus-mysql bash mysql -u root -p SL < /tmp/dump.sql

January 16, 2026

2021-07-01-lotus代理实现文档

2021-07-01-lotus代理实现文档 Block Chain Lotus Lotus 代理实现文档 内部数据传输框架 lotus 会启动 rpcServer; lotus-miner 会创建一个和lotus的基于websocket的jsonrpc连接,同时会通过 gorilla/mux 启动http服务; lotus-worker 会创建一个和miner的基于http的jsonrpc连接。 websocket vs socket 尽管它们(在一般情况下)实现了类似的事情,但是它们确实是不同的。WebSockets 通常由浏览器通过类似于在 TCP/IP 上运行的 HTTP 的协议连接到应用服务器。因此,它们主要用于需要与服务器永久连接的 Web 应用程序。另一方面,普通 Socket 是更强大和通用的。它们在 TCP/IP 上运行,但它们不限于浏览器或 HTTP 协议。它们可以用来实现任何种类的通信。 http/https 代理实现方案 监听端口,for循环等待连接进入,go新开一个协程进行处理 解析数据头,获取方法和请求路径 拨号进行连接,通过io.Copy的方法进行数据转发(实际这样处理不好,但确实可行) 上述是一个比较简单的方案,没有考虑超时等一些异常情况,但确实可以做到数据被代理进行转发,详情参考文档:http/https正向代理。 上述方案有一个更优秀的处理,可以参考:gist.github.com/hellojukay/proxy_server.go http/https 反向代理实现方案 httputil.NewSingleHostReverseProxy(url) 创建一个反向代理实例 *httputil.ReverseProxy 把HandleFunc第二个参数导向到 proxy,proxy本身就实现了 ServeHTTP 上述方案实现非常简单,但只实现反向代理,对于负载均衡,缓存等优秀特性没有实现,详情参考文档:Go 简单而强大的反向代理(Reverse Proxy) websocket 反向代理实现方案 使用 github.com/gorilla/websocket 实现反向代理 自定义 WebsocketProxy,实现 ServeHTTP 方法,也就是 proxy 当作 handler 使用 建立客户端和后端的websocket请求后就不再断开,直到信息传递不在通畅就断开链接 以上是 websocketproxy.go 的实现。在这个实现中做到了客户端http请求升级到websocket请求,头数据传递,但仅适用于单点对单点(单个client对后台单个backend)的情况。 Lotus 代理难点 websocket 反向代理 jsonrpc 通信 认证信息(header信息) 保证第一次连接的backend不变,其他请求可以选择优秀的backend 解: ...

January 16, 2026

2021-06-30-lotus 消息同步过程

2021-06-30-lotus 消息同步过程 Block Chain Lotus lotus 消息同步过程 lotus 在创建过程启动了什么服务? 消息同步需要 chain 组件,chain 组件的运行需要依赖 libp2p 的组件。在 lotus/node/builder_chain.go 中提到了 chain 组件的构造过程: 检测配置 网络引导 检测加密依赖 VM创建 链存储以及链状态管理器启动 链同步服务启动 链网络接入p2p 链与矿工的API依赖 消息池服务启动 钱包服务启动 交易频道服务开启 三类市场服务开启 上述服务的部分方法根据 lotus 节点类型的区别选择是否启动 关于同步相关的逻辑,主要是在 “链同步服务启动” 和 “上述服务的部分方法根据 lotus 节点类型的区别选择是否启动(数据进入)”。只有 lotus 节点为 FULLNODE 时才会有链同步。 lotus 同步 启动 libp2p 服务 将 Syncer.Sync 作为参数创建一个 Sync.SyncManager 通过 NewSyncer+Sync.SyncManager 创建一个 Syncer 启动 Syncer,启动 Sync.SyncManager 开启对新网络的消息订阅(这里就会提到,如果在强制升级中没有升级,那么网络名不会更新,就不能获得最新的出块信息) 对过来的消息进行 Sync 处理 NewSyncer 在创建新的同步器之前先创建了 SyncManagerCtor, 它的类型如下所示,在 Syncer 创建中会使用到,它的主要作用就是返回 SyncManager,但生成过程中需要用到 Syncer 的 Sync 实现,这里有点回调的意思。 ...

January 16, 2026

2021-06-29-关于IP暴露相关问题

2021-06-29-关于IP暴露相关问题 Block Chain Lotus 关于IP暴露相关问题 lotus项目中,一般情况下只有lotus会与外界进行通信(开启了market功能的miner也会通信),lotus和外界的通信是通过 p2p 方式进行的,有加密处理。 lotus 内关于对外连接的代码在 lotus/cli/net.go 和 lotus/node/modules/lp2p/ 下 p2p的实现在:github.com/libp2p 下,相关内容非常多 先对几个常用指令进行解释: lotus net peers:查看内存中的连接体的信息 lotus net connect addr:连接给定的地址,创建p2p连接 lotus net listen:查看本地的监听信息,即监听地址 lotus net id:查看本地的peer id lotus net findpeer peer-id:查找给定的 peer id,判断能否连接,给出连接过程的网络连接信息 lotus net scores: 给出本地lotus进行p2p连接对象的本地评分 lotus net reachability:给出本地lotus是否可被其他节点连接 lotus net bandwidth:查看p2p网络占用的流量 lotus net block:暂未使用 默认的配置下,lotus是Private的,除非在 config.toml 下配置 Libp2p:AnnounceAddresses。 至于IP暴露问题,结论是:会暴露IP,但属于被动发现,也就是无法主动发现。从两个角度来看都会: 从三方 lotus net peers 获取的 peer 中如果出现了目标节点的连接,那么是可以看到ip地址 从系统层面可以直接查找跟 lotus 的连接,只是无法知道是否为目标节点 上述第二点,作为执法者,可以设计 ip 检测池,如果在多个lotus相关连接中多次出现一个ip,那么就可能被打击。 lotus 启动时会创建 p2p 连接,暂时还没找到初始连接的peer,无论是什么p2p方案,在启动的时候都需要连接指定的peer,然后启动本地的DHT网络,创建一个本地的路由。 ...

January 16, 2026

2021-06-28-1.13版本lotus-miner的配置文件说明

2021-06-28-1.13版本lotus-miner的配置文件说明 s Block Chain Lotus [API] # Binding address for the Lotus API # 绑定Lotus API的地址 # type: string # env var: LOTUS_API_LISTENADDRESS #ListenAddress = "/ip4/127.0.0.1/tcp/2345/http" # type: string # env var: LOTUS_API_REMOTELISTENADDRESS #RemoteListenAddress = "127.0.0.1:2345" # type: Duration # env var: LOTUS_API_TIMEOUT #Timeout = "30s" [Backup] # Note that in case of metadata corruption it might be much harder to recover # your node if metadata log is disabled # 注意,在元数据损坏的情况下,如果禁用元数据日志,要恢复你的节点可能会更难。如果元数据日志被禁用,你的节点可能更难恢复。 # type: bool # env var: LOTUS_BACKUP_DISABLEMETADATALOG #DisableMetadataLog = false [Libp2p] # Binding address for the libp2p host - 0 means random port. # libp2p主机的绑定地址 - 0表示随机端口 # Format: multiaddress; see https://multiformats.io/multiaddr/ # # type: []string # env var: LOTUS_LIBP2P_LISTENADDRESSES #ListenAddresses = ["/ip4/0.0.0.0/tcp/0", "/ip6/::/tcp/0"] # Addresses to explicitally announce to other peers. If not specified, # all interface addresses are announced # 向其他对等体明确宣布的地址。如果不指定,所有接口地址都被公布 # Format: multiaddress # # type: []string # env var: LOTUS_LIBP2P_ANNOUNCEADDRESSES #AnnounceAddresses = [] # Addresses to not announce # 不公布的地址 # Format: multiaddress # # type: []string # env var: LOTUS_LIBP2P_NOANNOUNCEADDRESSES #NoAnnounceAddresses = [] # When not disabled (default), lotus asks NAT devices (e.g., routers), to # open up an external port and forward it to the port lotus is running on. # When this works (i.e., when your router supports NAT port forwarding), # it makes the local lotus node accessible from the public internet # 当没有禁用时(默认),lotus要求NAT设备(如路由器),打开一个外部端口,并将其转发到lotus正在运行的端口上。当这样做时(即,当你的路由器支持NAT端口转发时),它使本地lotus节点可以从公共互联网上访问。 # # type: bool # env var: LOTUS_LIBP2P_DISABLENATPORTMAP #DisableNatPortMap = false # ConnMgrLow is the number of connections that the basic connection manager # will trim down to. # ConnMgrLow是基本连接管理器的连接数将会减少到的连接数。 # # type: uint # env var: LOTUS_LIBP2P_CONNMGRLOW #ConnMgrLow = 150 # ConnMgrHigh is the number of connections that, when exceeded, will trigger # a connection GC operation. Note: protected/recently formed connections don't # count towards this limit. # ConnMgrHigh是连接数,当超过这个数字时,将触发连接GC操作。注意:受保护的/最近形成的连接不 计入这个限制。 # type: uint # env var: LOTUS_LIBP2P_CONNMGRHIGH #ConnMgrHigh = 180 # ConnMgrGrace is a time duration that new connections are immune from being # closed by the connection manager. # ConnMgrGrace是一个时间长度。新的连接可以不被连接管理器关闭。 # type: Duration # env var: LOTUS_LIBP2P_CONNMGRGRACE #ConnMgrGrace = "20s" [Pubsub] # Run the node in bootstrap-node mode # 在引导-节点模式下运行节点 # type: bool # env var: LOTUS_PUBSUB_BOOTSTRAPPER #Bootstrapper = false # type: string # env var: LOTUS_PUBSUB_REMOTETRACER #RemoteTracer = "" [Subsystems] # miner 拥有的子系统 # type: bool # env var: LOTUS_SUBSYSTEMS_ENABLEMINING #EnableMining = true # type: bool # env var: LOTUS_SUBSYSTEMS_ENABLESEALING #EnableSealing = true # type: bool # env var: LOTUS_SUBSYSTEMS_ENABLESECTORSTORAGE #EnableSectorStorage = true # type: bool # env var: LOTUS_SUBSYSTEMS_ENABLEMARKETS # EnableMarkets = true # type: string # env var: LOTUS_SUBSYSTEMS_SEALERAPIINFO #SealerApiInfo = "" # type: string # env var: LOTUS_SUBSYSTEMS_SECTORINDEXAPIINFO #SectorIndexApiInfo = "" [Dealmaking] # When enabled, the miner can accept online deals # 启用后,矿工可以接受在线交易 # type: bool # env var: LOTUS_DEALMAKING_CONSIDERONLINESTORAGEDEALS #ConsiderOnlineStorageDeals = true # When enabled, the miner can accept offline deals # 启用后,矿工可以接受离线交易 # type: bool # env var: LOTUS_DEALMAKING_CONSIDEROFFLINESTORAGEDEALS #ConsiderOfflineStorageDeals = true # When enabled, the miner can accept retrieval deals # 启用后,矿工可以接受检索交易 # type: bool # env var: LOTUS_DEALMAKING_CONSIDERONLINERETRIEVALDEALS #ConsiderOnlineRetrievalDeals = true # When enabled, the miner can accept offline retrieval deals # 启用后,矿工可以接受离线检索交易 # type: bool # env var: LOTUS_DEALMAKING_CONSIDEROFFLINERETRIEVALDEALS #ConsiderOfflineRetrievalDeals = true # When enabled, the miner can accept verified deals # 启用后,矿工可以接受验证交易 # type: bool # env var: LOTUS_DEALMAKING_CONSIDERVERIFIEDSTORAGEDEALS #ConsiderVerifiedStorageDeals = true # When enabled, the miner can accept unverified deals # 启用后,矿工可以接受未经验证的交易 # type: bool # env var: LOTUS_DEALMAKING_CONSIDERUNVERIFIEDSTORAGEDEALS #ConsiderUnverifiedStorageDeals = true # A list of Data CIDs to reject when making deals # 进行交易时要拒绝的数据CID列表 # type: []cid.Cid # env var: LOTUS_DEALMAKING_PIECECIDBLOCKLIST #PieceCidBlocklist = [] # Maximum expected amount of time getting the deal into a sealed sector will take # This includes the time the deal will need to get transferred and published # before being assigned to a sector # 将交易放入一个密封的扇区所需的最大预期时间 这包括交易在被分配到一个扇区之前需要转移和公布的时间 # type: Duration # env var: LOTUS_DEALMAKING_EXPECTEDSEALDURATION #ExpectedSealDuration = "24h0m0s" # Maximum amount of time proposed deal StartEpoch can be in future # 提议的交易起始纪元可以在未来的最长时间内 # type: Duration # env var: LOTUS_DEALMAKING_MAXDEALSTARTDELAY #MaxDealStartDelay = "336h0m0s" # When a deal is ready to publish, the amount of time to wait for more # deals to be ready to publish before publishing them all as a batch # 当一个交易准备好要发布时,等待更多的交易准备好发布,然后再把它们作为一个批次发布。 # type: Duration # env var: LOTUS_DEALMAKING_PUBLISHMSGPERIOD #PublishMsgPeriod = "1h0m0s" # The maximum number of deals to include in a single PublishStorageDeals # message # 在单个PublishStorageDeals消息中包含的最大交易数 # type: uint64 # env var: LOTUS_DEALMAKING_MAXDEALSPERPUBLISHMSG #MaxDealsPerPublishMsg = 8 # The maximum collateral that the provider will put up against a deal, # as a multiplier of the minimum collateral bound # 提供者将为交易提供的最大抵押品,是最低抵押品界限的乘数。 # type: uint64 # env var: LOTUS_DEALMAKING_MAXPROVIDERCOLLATERALMULTIPLIER #MaxProviderCollateralMultiplier = 2 # The maximum allowed disk usage size in bytes of staging deals not yet # passed to the sealing node by the markets service. 0 is unlimited. # 允许的最大磁盘使用量,以字节为单位,是指尚未被市场服务传递到密封节点的暂存交易。0是无限制 # type: int64 # env var: LOTUS_DEALMAKING_MAXSTAGINGDEALSBYTES #MaxStagingDealsBytes = 0 # The maximum number of parallel online data transfers for storage deals # 存储交易的最大并行在线数据传输数 # type: uint64 # env var: LOTUS_DEALMAKING_SIMULTANEOUSTRANSFERSFORSTORAGE #SimultaneousTransfersForStorage = 20 # The maximum number of parallel online data transfers for retrieval deals # 检索交易的最大并行在线数据传输数 # type: uint64 # env var: LOTUS_DEALMAKING_SIMULTANEOUSTRANSFERSFORRETRIEVAL #SimultaneousTransfersForRetrieval = 20 # Minimum start epoch buffer to give time for sealing of sector with deal. # 最小的开始时间缓冲,以便有时间将扇区与交易密封起来。 # type: uint64 # env var: LOTUS_DEALMAKING_STARTEPOCHSEALINGBUFFER #StartEpochSealingBuffer = 480 # A command used for fine-grained evaluation of storage deals # see https://docs.filecoin.io/mine/lotus/miner-configuration/#using-filters-for-fine-grained-storage-and-retrieval-deal-acceptance for more details # 用于细化评估存储交易的命令 # type: string # env var: LOTUS_DEALMAKING_FILTER #Filter = "" # A command used for fine-grained evaluation of retrieval deals # see https://docs.filecoin.io/mine/lotus/miner-configuration/#using-filters-for-fine-grained-storage-and-retrieval-deal-acceptance for more details # 用于细化评估检索交易的命令 # type: string # env var: LOTUS_DEALMAKING_RETRIEVALFILTER #RetrievalFilter = "" [Dealmaking.RetrievalPricing] # env var: LOTUS_DEALMAKING_RETRIEVALPRICING_STRATEGY #Strategy = "default" [Dealmaking.RetrievalPricing.Default] # env var: LOTUS_DEALMAKING_RETRIEVALPRICING_DEFAULT_VERIFIEDDEALSFREETRANSFER #VerifiedDealsFreeTransfer = true [Dealmaking.RetrievalPricing.External] # env var: LOTUS_DEALMAKING_RETRIEVALPRICING_EXTERNAL_PATH #Path = "" [Sealing] # Upper bound on how many sectors can be waiting for more deals to be packed in it before it begins sealing at any given time. # If the miner is accepting multiple deals in parallel, up to MaxWaitDealsSectors of new sectors will be created. # If more than MaxWaitDealsSectors deals are accepted in parallel, only MaxWaitDealsSectors deals will be processed in parallel # Note that setting this number too high in relation to deal ingestion rate may result in poor sector packing efficiency # 0 = no limit # 在任何时候,在它开始封装之前,有多少扇区可以等待更多的交易被装入其中的上限。 # 如果矿工同时接受多笔交易,将创建最多为MaxWaitDealsSectors的新扇区。 # 如果平行接受的交易超过MaxWaitDealsSectors,则只有MaxWaitDealsSectors的交易将被平行处理。 # 请注意,相对于交易吸收率而言,将这个数字设置得太高,可能会导致扇区打包效率低下。 # 0 = 无限制 # type: uint64 # env var: LOTUS_SEALING_MAXWAITDEALSSECTORS #MaxWaitDealsSectors = 2 # Upper bound on how many sectors can be sealing at the same time when creating new CC sectors (0 = unlimited) # 在创建新的CC区时,可以同时封装多少个区的上限(0 = 无限)。 # type: uint64 # env var: LOTUS_SEALING_MAXSEALINGSECTORS #MaxSealingSectors = 0 # Upper bound on how many sectors can be sealing at the same time when creating new sectors with deals (0 = unlimited) # 当用交易创建新的扇区时,有多少扇区可以同时被封装,这是一个上限(0 = 无限)。 # type: uint64 # env var: LOTUS_SEALING_MAXSEALINGSECTORSFORDEALS #MaxSealingSectorsForDeals = 0 # CommittedCapacitySectorLifetime is the duration a Committed Capacity (CC) sector will # live before it must be extended or converted into sector containing deals before it is # terminated. Value must be between 180-540 days inclusive # 承诺容量部门寿命是指承诺容量(CC)部门在必须延长或在终止前转换为包含交易的部门之前的生存时间。该值必须在180-540天之间(含)。 # type: Duration # env var: LOTUS_SEALING_COMMITTEDCAPACITYSECTORLIFETIME #CommittedCapacitySectorLifetime = "12960h0m0s" # Period of time that a newly created sector will wait for more deals to be packed in to before it starts to seal. # Sectors which are fully filled will start sealing immediately # 新创建的扇区在开始封存之前,将等待更多的交易进入的时间。已经完全填充的扇区将立即开始封装。 # type: Duration # env var: LOTUS_SEALING_WAITDEALSDELAY #WaitDealsDelay = "6h0m0s" # Whether to keep unsealed copies of deal data regardless of whether the client requested that. This lets the miner # avoid the relatively high cost of unsealing the data later, at the cost of more storage space # 是否保留交易数据的非封装副本,无论客户是否要求这样做。这让矿工避免了后来解封数据的相对高成本,代价是更多的存储空间。 # type: bool # env var: LOTUS_SEALING_ALWAYSKEEPUNSEALEDCOPY #AlwaysKeepUnsealedCopy = true # Run sector finalization before submitting sector proof to the chain # 在向产业链提交部门证明之前,运行部门定稿 # type: bool # env var: LOTUS_SEALING_FINALIZEEARLY #FinalizeEarly = false # Whether to use available miner balance for sector collateral instead of sending it with each message # 是否使用可用的矿工余额进行扇区质押,而不是在每条信息中发送它 # type: bool # env var: LOTUS_SEALING_COLLATERALFROMMINERBALANCE #CollateralFromMinerBalance = false # Minimum available balance to keep in the miner actor before sending it with messages # 在向矿工角色发送消息之前,在矿工角色中保持的最小可用余额 # type: types.FIL # env var: LOTUS_SEALING_AVAILABLEBALANCEBUFFER #AvailableBalanceBuffer = "0 FIL" # Don't send collateral with messages even if there is no available balance in the miner actor # 即使矿工角色中没有可用的余额,也不要用信息发送质押 # type: bool # env var: LOTUS_SEALING_DISABLECOLLATERALFALLBACK #DisableCollateralFallback = false # enable / disable precommit batching (takes effect after nv13) # 开启/关闭 预提交批处理(在nv13之后生效) # type: bool # env var: LOTUS_SEALING_BATCHPRECOMMITS #BatchPreCommits = true # maximum precommit batch size - batches will be sent immediately above this size # 最大的预提交批处理量 - 批处理量超过这个大小将立即被发送 # type: int # env var: LOTUS_SEALING_MAXPRECOMMITBATCH #MaxPreCommitBatch = 256 # how long to wait before submitting a batch after crossing the minimum batch size # 越过最小批处理量后,要等多长时间才能批处理 预提交 # type: Duration # env var: LOTUS_SEALING_PRECOMMITBATCHWAIT #PreCommitBatchWait = "24h0m0s" # time buffer for forceful batch submission before sectors/deal in batch would start expiring # 在批次中的扇区/交易开始到期之前,为强制提交批次提供时间缓冲。 # type: Duration # env var: LOTUS_SEALING_PRECOMMITBATCHSLACK #PreCommitBatchSlack = "3h0m0s" # enable / disable commit aggregation (takes effect after nv13) # 启用/禁用提交聚合(在nv13之后生效)。 # type: bool # env var: LOTUS_SEALING_AGGREGATECOMMITS #AggregateCommits = true # maximum batched commit size - batches will be sent immediately above this size # 最大的分批提交规模--超过此规模的分批将被立即发送。 # type: int # env var: LOTUS_SEALING_MINCOMMITBATCH #MinCommitBatch = 4 # type: int # env var: LOTUS_SEALING_MAXCOMMITBATCH #MaxCommitBatch = 819 # how long to wait before submitting a batch after crossing the minimum batch size # 越过最小批处理量后,要等多长时间才能批处理 提交 # type: Duration # env var: LOTUS_SEALING_COMMITBATCHWAIT #CommitBatchWait = "24h0m0s" # time buffer for forceful batch submission before sectors/deals in batch would start expiring # 在批次中的部门/交易开始到期之前,为强行提交批次提供时间缓冲。 # type: Duration # env var: LOTUS_SEALING_COMMITBATCHSLACK #CommitBatchSlack = "1h0m0s" # network BaseFee below which to stop doing precommit batching, instead # sending precommit messages to the chain individually # 网络 BaseFee,低于此值时,停止进行预提交批处理,而是 向链上单独发送预提交信息 # type: types.FIL # env var: LOTUS_SEALING_BATCHPRECOMMITABOVEBASEFEE #BatchPreCommitAboveBaseFee = "0.00000000032 FIL" # network BaseFee below which to stop doing commit aggregation, instead # submitting proofs to the chain individually # 网络BaseFee,低于此值将停止进行提交聚合,而是 向链上单独提交证明 # type: types.FIL # env var: LOTUS_SEALING_AGGREGATEABOVEBASEFEE #AggregateAboveBaseFee = "0.00000000032 FIL" # type: uint64 # env var: LOTUS_SEALING_TERMINATEBATCHMAX #TerminateBatchMax = 100 # type: uint64 # env var: LOTUS_SEALING_TERMINATEBATCHMIN #TerminateBatchMin = 1 # type: Duration # env var: LOTUS_SEALING_TERMINATEBATCHWAIT #TerminateBatchWait = "5m0s" [Storage] # env var: LOTUS_STORAGE_PARALLELFETCHLIMIT #ParallelFetchLimit = 10 # env var: LOTUS_STORAGE_ALLOWADDPIECE #AllowAddPiece = true # env var: LOTUS_STORAGE_ALLOWPRECOMMIT1 #AllowPreCommit1 = true # env var: LOTUS_STORAGE_ALLOWPRECOMMIT2 #AllowPreCommit2 = true # env var: LOTUS_STORAGE_ALLOWCOMMIT #AllowCommit = true # env var: LOTUS_STORAGE_ALLOWUNSEAL #AllowUnseal = true # env var: LOTUS_STORAGE_RESOURCEFILTERING #ResourceFiltering = "hardware" [Fees] # type: types.FIL # env var: LOTUS_FEES_MAXPRECOMMITGASFEE #MaxPreCommitGasFee = "0.025 FIL" # type: types.FIL # env var: LOTUS_FEES_MAXCOMMITGASFEE #MaxCommitGasFee = "0.05 FIL" # type: types.FIL # env var: LOTUS_FEES_MAXTERMINATEGASFEE #MaxTerminateGasFee = "0.5 FIL" # WindowPoSt is a high-value operation, so the default fee should be high. # WindowPoSt是一项高价值的操作,所以默认费用应该很高 # type: types.FIL # env var: LOTUS_FEES_MAXWINDOWPOSTGASFEE #MaxWindowPoStGasFee = "5 FIL" # type: types.FIL # env var: LOTUS_FEES_MAXPUBLISHDEALSFEE #MaxPublishDealsFee = "0.05 FIL" # type: types.FIL # env var: LOTUS_FEES_MAXMARKETBALANCEADDFEE #MaxMarketBalanceAddFee = "0.007 FIL" [Fees.MaxPreCommitBatchGasFee] # type: types.FIL # env var: LOTUS_FEES_MAXPRECOMMITBATCHGASFEE_BASE #Base = "0 FIL" # type: types.FIL # env var: LOTUS_FEES_MAXPRECOMMITBATCHGASFEE_PERSECTOR #PerSector = "0.02 FIL" [Fees.MaxCommitBatchGasFee] # type: types.FIL # env var: LOTUS_FEES_MAXCOMMITBATCHGASFEE_BASE #Base = "0 FIL" # type: types.FIL # env var: LOTUS_FEES_MAXCOMMITBATCHGASFEE_PERSECTOR #PerSector = "0.03 FIL" [Addresses] # Addresses to send PreCommit messages from # 用于发送PreCommit信息的地址 # type: []string # env var: LOTUS_ADDRESSES_PRECOMMITCONTROL #PreCommitControl = [] # Addresses to send Commit messages from # 用于发送Commit信息的地址 # type: []string # env var: LOTUS_ADDRESSES_COMMITCONTROL #CommitControl = [] # type: []string # env var: LOTUS_ADDRESSES_TERMINATECONTROL #TerminateControl = [] # type: []string # env var: LOTUS_ADDRESSES_DEALPUBLISHCONTROL #DealPublishControl = [] # DisableOwnerFallback disables usage of the owner address for messages # sent automatically # DisableOwnerFallback禁止使用自动发送的信息的所有者地址。 # type: bool # env var: LOTUS_ADDRESSES_DISABLEOWNERFALLBACK #DisableOwnerFallback = false # DisableWorkerFallback disables usage of the worker address for messages # sent automatically, if control addresses are configured. # A control address that doesn't have enough funds will still be chosen # over the worker address if this flag is set. # 如果配置了控制地址,DisableWorkerFallback会禁止使用自动发送的消息的工作者地址。如果这个标志被设置,没有足够资金的控制地址仍然会被选择,而不是工作者地址。 # type: bool # env var: LOTUS_ADDRESSES_DISABLEWORKERFALLBACK #DisableWorkerFallback = false [DAGStore] # Path to the dagstore root directory. This directory contains three # subdirectories, which can be symlinked to alternative locations if # need be: # - ./transients: caches unsealed deals that have been fetched from the # storage subsystem for serving retrievals. # - ./indices: stores shard indices. # - ./datastore: holds the KV store tracking the state of every shard # known to the DAG store. # Default value: <LOTUS_MARKETS_PATH>/dagstore (split deployment) or # <LOTUS_MINER_PATH>/dagstore (monolith deployment) # dagstore根目录的路径。这个目录包含三个子目录,如果需要,可以用符号链接到其他位置。 # - ./transients:缓存从存储子系统获取的未封存交易,为检索服务。 # - ./indices:存储分片索引。 # - ./datastore:持有跟踪DAG存储中已知的每个分片状态的KV存储。 # 默认值。<LOTUS_MARKETS_PATH>/dagstore(分裂部署)或 # <LOTUS_MINER_PATH>/dagstore (单片部署) # type: string # env var: LOTUS_DAGSTORE_ROOTDIR #RootDir = "" # The maximum amount of indexing jobs that can run simultaneously. # 0 means unlimited. # Default value: 5. # 可以同时运行的索引工作的最大数量。 # type: int # env var: LOTUS_DAGSTORE_MAXCONCURRENTINDEX #MaxConcurrentIndex = 5 # The maximum amount of unsealed deals that can be fetched simultaneously # from the storage subsystem. 0 means unlimited. # Default value: 0 (unlimited). # 可以同时从存储子系统中获取的未封存交易的最大数量。 # type: int # env var: LOTUS_DAGSTORE_MAXCONCURRENTREADYFETCHES #MaxConcurrentReadyFetches = 0 # The maximum number of simultaneous inflight API calls to the storage # subsystem. # Default value: 100. # 对存储子系统同时进行的机内API调用的最大数量。 # type: int # env var: LOTUS_DAGSTORE_MAXCONCURRENCYSTORAGECALLS #MaxConcurrencyStorageCalls = 100 # The time between calls to periodic dagstore GC, in time.Duration string # representation, e.g. 1m, 5m, 1h. # Default value: 1 minute. # 定期调用dagstore GC的时间间隔,用time.Duration字符串表示,如1m、5m、1h。 # type: Duration # env var: LOTUS_DAGSTORE_GCINTERVAL #GCInterval = "1m0s"

January 16, 2026

2021-06-25-2.4blockchain-cn

2021-06-25-2.4blockchain-cn 2.4 Blockchain Block Chain Lotus Filecoin区块链是一个分布式虚拟机,在Filecoin协议中实现共识、处理信息、核算存储和维护安全。它是连接Filecoin系统中各种行为者的主要接口。 Filecoin区块链系统包括: 一个消息池系统,节点用来跟踪和传播矿工宣布要纳入区块链的消息 一个虚拟机子系统,用于解释和执行信息,以更新系统状态。 一个状态树子系统,管理状态树(系统状态)的创建和维护,这些状态树是由vm从一个给定的子链中确定性地生成的。 一个链同步(ChainSync)子系统跟踪和传播经过验证的消息块,维护矿工可以开采的候选链集,并对进入的块进行语法验证。 一个存储算力共识子系统,它跟踪给定链的存储状态(即存储子系统),并帮助区块链系统选择子链来扩展和区块来包括在其中。 区块链系统还包括: 链管理器,维护一个给定的链的状态,为其他区块链子系统提供设施,这些子系统将查询关于最新的链的状态,以便运行,并确保传入的区块在纳入链之前得到语义验证。 区块生产者,在领导者选举成功的情况下被调用,以产生一个新的区块,在将其转发给同步器传播之前,将扩展当前最重的链。 在高层次上,Filecoin区块链通过连续几轮领导人选举而成长,其中一些矿工被选举产生一个区块,该区块被纳入链中将为他们赢得区块奖励。Filecoin的区块链依靠存储能力运行。也就是说,它的共识算法,即矿工同意开采哪个子链,是以支持该子链的存储量为前提的。在高层次上,存储算力共识子系统维护一个算力表,跟踪存储矿工演员通过扇区承诺和时空证明对网络贡献的存储量。 2.4.1 Blocks 区块是Filecoin区块链的主要单位,大多数其他区块链也是如此。区块信息与Tipsets直接相关,Tipsets是由区块信息组成的组,本节后面将详细介绍。在下文中,我们将讨论区块信息的主要结构以及在Filecoin区块链中验证区块信息的过程。 2.4.1.1 Block 区块是Filecoin区块链的主要单位。 Filecoin区块链中的区块结构由以下部分组成:i)区块头,ii)区块内的信息列表,以及iii)已签署的信息。这在FullBlock的抽象中得到了体现。这些消息表明,为了达到链的确定状态,需要应用的一组变化。 该区块的Lotus实现有以下结构: type FullBlock struct { Header *BlockHeader BlsMessages []*Message SecpkMessages []*SignedMessage } 备注:一个区块在功能上与Filecoin协议中的区块头是一样的。虽然区块头包含完整的系统状态、消息和消息收据的Merkle链接,但一个区块可以被认为是这些信息的完整集合(不仅仅是Merkle根,而是状态树、消息树、收据树等的完整数据)。因为一个完整的区块大小很大,所以Filecoin区块链由区块头而不是完整的区块组成。我们经常交替使用区块和区块头这两个术语。 BlockHeader是一个区块的典型代表。BlockHeaders在矿工节点之间传播。从BlockHeader消息中,矿工拥有应用相关FullBlock的状态和更新链的所有必要信息。为了能够做到这一点,需要包含在BlockHeader中的最小信息项目集如下所示,其中包括:矿工的地址、Ticket、SpaceTime证明、IPLD DAG中该区块演化而来的父类的CID,以及消息本身的CID。 Lotus实现的区块头有以下结构: type BlockHeader struct { Miner address.Address // 0 unique per block/miner Ticket *Ticket // 1 unique per block/miner: should be a valid VRF ElectionProof *ElectionProof // 2 unique per block/miner: should be a valid VRF BeaconEntries []BeaconEntry // 3 identical for all blocks in same tipset WinPoStProof []proof2.PoStProof // 4 unique per block/miner Parents []cid.Cid // 5 identical for all blocks in same tipset ParentWeight BigInt // 6 identical for all blocks in same tipset Height abi.ChainEpoch // 7 identical for all blocks in same tipset ParentStateRoot cid.Cid // 8 identical for all blocks in same tipset ParentMessageReceipts cid.Cid // 9 identical for all blocks in same tipset Messages cid.Cid // 10 unique per block BLSAggregate *crypto.Signature // 11 unique per block: aggrregate of BLS messages from above Timestamp uint64 // 12 identical for all blocks in same tipset / hard-tied to the value of Height above BlockSig *crypto.Signature // 13 unique per block/miner: miner signature ForkSignaling uint64 // 14 currently unused/undefined ParentBaseFee abi.TokenAmount // 15 identical for all blocks in same tipset: the base fee after executing parent tipset validated bool // internal, true if the signature has been validated } type Ticket struct { VRFProof []byte } type ElectionProof struct { WinCount int64 VRFProof []byte } type BeaconEntry struct { Round uint64 Data []byte } BlockHeader结构必须引用当前轮次的TicketWinner,以确保正确的赢家被传递给ChainSync。 ...

January 16, 2026

2021-06-24-lotus代码关于gossipsub-score

2021-06-24-lotus代码关于gossipsub-score lotus代码关于gossipsub-score Block Chain Lotus 需要专注于:业务中哪些地方会用到这个评分?哪些地方会影响到这些评分? 得分说明 Score(p) = TopicCap(Σtᵢ*(w₁(tᵢ)*P₁(tᵢ) + w₂(tᵢ)*P₂(tᵢ) + w₃(tᵢ)*P₃(tᵢ) + w₃b(tᵢ)*P₃b(tᵢ) + w₄(tᵢ)*P₄(tᵢ))) + w₅*P₅ + w₆*P₆ + w₇*P₇ 其中 tᵢ 是主题本身的权重,由应用程序指定。 P₁: Time in Mesh。一个主题在Mesh中的时间。这是一个对等体在Mesh中的时间,上限为一个小值,并与一个小的正数权重混合。这是为了提高已经在网状结构中的对等体,这样他们就不会因为超额订阅而过早地被剪除。 P₂: First Message Deliveries for a topic。一个主题的首次消息传递量。这是该主题中对等体首次传递的消息数量,与一个正的权重混合。这旨在奖励首先转发有效消息的对等体。 P₃: Mesh Message Delivery Rate for a topic。一个主题的网状消息传递率。该参数是该主题中网状结构内预期消息传递率的阈值。如果交付数量高于阈值,则其值为0。如果数量低于阈值,则参数值为赤字的平方。这样做的目的是为了惩罚网状结构中没有交付预期数量信息的对等体,以便将其从网状结构中删除。该参数与负权重混合。 P₃b。Mesh Message Delivery Failures for a topic。一个主题的网状信息传递失败率。这是一个粘性参数,计算网状消息传递失败的数量。每当一个对等体以负分修剪时,该参数就会被修剪时的比率赤字所增加。这样做的目的是为了保持修剪的历史,这样一个因为传递不足而被修剪的对等体就不能很快被重新嫁接到网格中。该参数与负权重混合。 P₄: Invalid Messages for a topic。一个主题的无效消息。这是在主题中交付的无效消息的数量。这是为了根据特定应用的验证规则,惩罚传送无效信息的对等体。它与一个负的权重混合。 上面四个是针对 topic 的,下面三个是属于程序定义的。 P₅: Application-Specific score。特定应用的得分。这是由应用程序本身使用特定的应用程序规则分配给对等体的分数成分。权重是正的,但参数本身有一个任意的实值,因此应用程序可以用负的分数发出错误行为的信号,或者在特定于应用程序的握手完成之前对对等体进行屏蔽。 P₆: IP Colocation Factor。IP同位因子。该参数是使用同一IP地址的对等体数量的阈值。如果同一IP的对等体数量超过阈值,那么该值为盈余的平方,否则为0。这是为了使使用少量IP的对等体难以进行Sybil攻击。该参数与负权重混合。 P₇: Behavioural Penalty。行为惩罚。该参数反映了对不当行为的惩罚。该参数有一个相关的(衰减的)计数器,由路由器在特定事件中明确增加。该参数的值是计数器的平方,并与负权重混合。 GossipSub 基础属性配置 # 非引导节点 # 每个peer自身的网状结构至少有的数量,对于一个peer,至少保持有8个full-message peering pubsub.GossipSubD = 8 # peer进行修剪时必须保证6个对等点是高分的 pubsub.GossipSubDscore = 6 # peer修剪时保证3个对外连接,防止日蚀攻击,一般小于GossipSubDlo,且小于GossipSubD/2 pubsub.GossipSubDout = 3 # peer自身的网络的对等体下限和上限,如果缺少/超过,则在下次心跳中进行嫁接/修剪 pubsub.GossipSubDlo = 6 pubsub.GossipSubDhi = 12 # peer要向12个对等体传递流言 pubsub.GossipSubDlazy = 12 # peer直接连接对等体前的初始延迟,可以理解为手动配置peer pubsub.GossipSubDirectConnectInitialDelay = 30 * time.Second # 在 IHAVE 广播之后,等待通过 IWANT 请求的消息的时间。如果在这个窗口内消息没被peer接收到,就会宣布该peer违背承诺,路由器可能会对其进行行为处罚。 pubsub.GossipSubIWantFollowupTime = 5 * time.Second # 窗口数,消息缓存的量 pubsub.GossipSubHistoryLength = 10 # 流言传播的动态因子,按照一个消息会被IHAVE发送三轮,那么 1-0.9*0.9*0.9 =0.27,peer大致27%的概率获得新消息 pubsub.GossipSubGossipFactor = 0.1 相比于 GossipSub 的默认设置,Lotus的网络做了更严格的要求,可以从GossipSubD和GossipSubDscore看出,这主要是为了提升消息的传递效率。 ...

January 16, 2026