# venus 链服务组件间签名机制

# 背景介绍

venusaccount 体系中,各角色的关系如下:

  • sophon-auth 为指定的用户(account)生成所需权限的 tokenSP 用户用此 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-minersophon-auth 获取 account-miners 列表;
  • 先从account-miners 列表中查找 minerID 对应的 account, 然后调用 sophon-gatewayWalletSign 接口。

# 问题分析

本问题以接入 venus 链服务的场景进行分析

  • 链服务中没有 signer addressaccount 的关系表,而依赖链服务的签名接口需要 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] 权限的 tokensophon-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-walletlotus/venus);
  • 交易过程中的消息推送到 sophon-messager, 和 sophon-cluster等推送消息一致;

所以 droplet-client 组件代码独立为一个项目比较好?从 droplet 中剥离?