# venus 链服务组件间签名机制
# 背景介绍
venus 的 account 体系中,各角色的关系如下:
sophon-auth为指定的用户(account)生成所需权限的token,SP用户用此token访问链服务接口;sophon-auth保存account-minerIDs,即一个用户可以拥有对个minerID;- 链服务组件之间的接口访问没有用到用户的
token, 是系统内置的共享token
# 用户请求的签名机制
以 sophon-cluster 推送消息的过程为例:
- 以
token请求sophon-messager的接口:
PushMessage(ctx context.Context, msg *shared.Message, meta *types.SendSpec) (string, error)
sophon-messager处理rpcapi请求,从token中解析获得在sophon-auth中生成的account, 然后调用sophon-gateway中的签名接口:
WalletSign(ctx context.Context, account string, addr address.Address, toSign []byte, meta venusTypes.MsgMeta) (*crypto.Signature, error)
sophon-gateway根据account找到对应的venus-wallet服务进行签名。
# 链服务内部的签名机制
链服务组件之间的接口访问用的是内置的 share token,故无法通过 token 解析出 account, 这样就需要依赖 sophon-auth 的 保存 account-minerIDs 体系。以 venus-miner 请求 sophon-gateway 为例进行说明。
venus-miner从sophon-auth获取account-miners列表;- 先从
account-miners列表中查找minerID对应的account, 然后调用sophon-gateway的WalletSign接口。
# 问题分析
本问题以接入 venus 链服务的场景进行分析
- 链服务中没有
signer address与account的关系表,而依赖链服务的签名接口需要account参数,droplet需要额外扩展signer-account关系,如下:
假设 f0128788 的可签名地址有: f3wylwd6pclppme4qmbgwled5xpsbgwgqbn2alxa7yahg2gnbfkipsdv6m764xm5coizujmwdmkxeugplmorha, f3r47fkdzfmtex5ic3jnwlzc7bkpbj7s4d6limyt4f57t3cuqq5nuvhvwv2cu2a6iga2s64vjqcxjqiezyjooq。
初始 miner-account, sophon-auth 中实现的关系:
f0128788-test
扩展后,droplet 中的扩展:
f0128788-test
f3wylwd6pclppme4qmbgwled5xpsbgwgqbn2alxa7yahg2gnbfkipsdv6m764xm5coizujmwdmkxeugplmorha-test
f3r47fkdzfmtex5ic3jnwlzc7bkpbj7s4d6limyt4f57t3cuqq5nuvhvwv2cu2a6iga2s64vjqcxjqiezyjooq-test
- 存储市场跟踪订单或扇区状态产生了不必要的工作量,会把非
miner Actor的地址也进行遍历,如下:
func (dealTracker *DealTracker) scanDeal(ctx metrics.MetricsCtx) {
addrs, err := dealTracker.minerMgr.ActorAddress(ctx)
if err != nil {
log.Errorf("get miners list %w", err)
}
head, err := dealTracker.fullNode.ChainHead(ctx)
if err != nil {
log.Errorf("get chain head %w", err)
}
for _, addr := range addrs {
dealTracker.checkSlash(ctx, addr, head.Key())
dealTracker.checkPreCommitAndCommit(ctx, addr, head.Key())
}
}
# Specification (feature Spec)
本次重构涉及组件包括:sophon-auth,sophon-gateway,sophon-messager, venus-miner, droplet等,接下来将一一介绍修改内容。
# sophon-auth
sophon-auth 提供接口将签名地址和账号进行绑定,并提供查询接口,保障链服务可以安全地支持多用户相互签名,接口如下:
type IAuthClient interface {
GetUserBySigner(signer string) (auth.ListUsersResponse, error)
RegisterSigners(user string, addrs []string) error
UnregisterSigners(user string, addrs []string) error
}
# sophon-gateway
签名接口重构:
type IWalletClient interface {
WalletHas(ctx context.Context, addr address.Address, accounts []string) (bool, error) //perm:admin
WalletSign(ctx context.Context, addr address.Address, accounts []string, toSign []byte, meta types.MsgMeta) (*crypto.Signature, error) //perm:admin
}
sophon-gateway签名接口只开放对具有admin权限的token访问,也就是只能被链服务内部访问,如:venus-miner,sophon-messager;- 在调用
sophon-gateway的签名接口前需要完成权限的检查,这样做为了避免构造消息,调用别人账号下的私钥签名; - 在调用
sophon-gateway的签名接口时需要带上密钥绑定的账号,这样做是为了多个账号的venus-wallet可以相互签名;
自动注册/注销签名地址:
- 在
venus-wallet建立连接时将其保存的私钥和支持的账号进行校验,通过后调用接口保存到sophon-auth。如 某个venus-wallet终端管理的私钥有: w1,w2;配置的支持账号有:user01,user02;那么绑定的关系有: user01-w1,user01-w2,user02-w1,user02-w2; - 在
venus-wallet连接端口或通过接口删除某个地址时自动注销签名地址和账号的绑定关系。
# sophon-messager
删除强制推送消息的接口,SP统一消息推送接口。
type IMessager interface {
- ForcePushMessage(ctx context.Context, account string, msg *types.Message, meta *mtypes.SendSpec) (string, error) //perm:admin
- ForcePushMessageWithId(ctx context.Context, id string, account string, msg *types.Message, meta *mtypes.SendSpec) (string, error) //perm:write
}
推送消息流程修改:
- SP组件调用链服务通常是 [
sign,read,write] 权限的token,sophon-messager首先要检查接口带的token权限是否满足:token对应的的账号与消息中的签名地址msg.From是绑定的;token具有sign权限(待定);
- 给签名接口提供签名地址绑定的所有账号,这样只要有一个连接到
sophon-gateway的签名终端(venus-wallet)支持对此密钥签名则可以签名此条消息,也就是多个账号相互帮助签名;
# venus-miner
无逻辑变化,只需匹配新的接口调用即可。
# droplet
- 取消额外扩展
signer-account关系的逻辑; - 消息签名前先检查请求
token的权限,通过后调用sophon-gateway的签名接口。
这里要注意的是 droplet-client 组件,其实现和 droplet 在同一项目,但是其本质是SP类组件,过程中的签名不能通过sophon-gateway, 其签名逻辑:
- 对于deals的签名需要额外的签名终端(
venus-wallet或lotus/venus); - 交易过程中的消息推送到
sophon-messager, 和sophon-cluster等推送消息一致;
所以
droplet-client组件代码独立为一个项目比较好?从droplet中剥离?