## key-manager服务

key-manager是一个助记词账户管理服务，包括助记词创建，助记词加密，钱包派生，钱包查询，白名单机制，交易签名等功能。使用grpc作为服务交互协议，方便多语言之间交互。

功能：

- 设置密码
  - 设置的密码，将作为加密助记词的密码。务必保存好该密码，否则将丢失所有的助记词并且key-manager也将无法启动。（key-manager在启动时会校验密码）
- 创建多个助记词
  - 创建助记词时需指定 name，name全局唯一，是即将要创建的助记词的代号

- 助记词加密
  - 创建的助记词将会被加密存储在mysql中，在运行中要注意对mysql的备份
- 创建eth和tron地址
  - 通过助记词name，network，以及index，可创建对应网络的私钥和地址
- 白名单机制
  - 服务为交易签名时，将识别资金接收地址，只有接收地址在白名单内，服务才会进行签名，否则将会拒绝签名。
  - 白名单地址列表只有在服务启动时进行加载，不会在运行中热加载，因为防止mysql被攻击。如果想要增加白名单，需在mysql中增加地址后，重启key-manager服务。
- 为eth和tron交易签名
  - key-manager接收经过编码的交易，反解码为交易详情，检查交易目的地址是否在白名单内，在白名单内时，将进行签名。并将签名过的交易进行编码返回。



## Proto文件

根据该proto文件，自动生成客户端请求代码

java生成参考，关键字：grpc生成java代码

https://developer.aliyun.com/article/679610

https://zhuanlan.zhihu.com/p/365370775

```
syntax = "proto3";
package service;

option java_package = "proto.keyManager";
option java_outer_classname = "keyManagerProto";

option go_package = "../service";

message CreateMnemonicRequest {
    string name = 1; // 商户名字，名字全局唯一，每个商户只能生成一个助记词
    int64 mnemonicType = 2; // 0 or 1, 0代表12个助记词，1代表24个助记词
}

message CreateMnemonicResponse {
  string code = 1;  // 响应码, 成功是200
  string msg = 2;   // 响应描述信息
}

message CreateKeyRequest {
    string name = 1; // 商户名字，如果该商户未创建助记词，则返回错误
    string network = 2; // 链网络名称，"eth" 或 "tron"
    int64 index = 3; // 派生账户使用的index，如果该index已被使用，则返回错误
}

message GetIndexRequest {
    string network = 1; // 链网络名称，"eth" 或 "tron"
    string address = 2; // 查询该地址对应的商户名字和index
}

message GetAddressRequest {
    string name = 1; // 商户名字，如果该商户未创建助记词，则返回错误
    string network = 2; // 链网络名称，"eth" 或 "tron"
    int64 index = 3; // 派生账户使用的index
}

message KeyResponse {
  string code = 1;  // 响应码, 成功是200
  string msg = 2;   // 响应描述信息
  string network = 3; // 链网络名称，"eth" 或 "tron"
  string name = 4; // 商户名字
  int64 index = 5; // 派生账户使用的index
  string address = 6; // 地址
}

message SignRequest {
   string network = 1; // 链网络名称，"eth" 或 "tron"
   string sender = 2; // 签名地址
   string tx = 3; // 编码的交易，先将eth/tron交易Marshal为字符数组，再编码为hex字符串
}

message SignResponse {
  string code = 1;  // 响应码, 成功是200
  string msg = 2;   // 响应描述信息
  string network = 3; // 链网络名称，"eth" 或 "tron"
  string sender = 4; // 签名地址
  string signedTx = 5; // 编码的已签名交易，先将eth/tron已签名交易Marshal为字符数组，再编码为hex字符串
}

service KeyManager {
    rpc CreateMnemonic(CreateMnemonicRequest) returns(CreateMnemonicResponse) {}
    rpc CreateKey(CreateKeyRequest) returns(KeyResponse) {}
    rpc GetIndex(GetIndexRequest) returns(KeyResponse) {}
    rpc GetAddress(GetAddressRequest) returns(KeyResponse) {}
    rpc Sign(SignRequest) returns(SignResponse) {}
}
```



## 交易编解码规则

对于Sign服务参数的构造，接收三个参数，分别是：

- 网络，必须填写 eth或者 tron
- sender，是交易发送者地址，即签名地址
- tx，是经过编码的交易

```
message SignRequest {
   string network = 1; // 链网络名称，"eth" 或 "tron"
   string sender = 2; // 签名地址
   string tx = 3; // 编码的交易，先将eth/tron交易Marshal为字符数组，再编码为hex字符串
}
```

其中tx的编解码规则如下：

**eth**

编码规则（请求参数构建）：

- 先json编码byte数组，再hex编码为字符串
  - json编码：https://github.com/ethereum/go-ethereum/blob/master/core/types/transaction_marshalling.go#L75
  - hex编码：hex.EncodeToString

解码已签名交易（返回参数解析）：

- 先将字符串hex解码为byte数据，再将byte数组json解码为eth交易Transaction



java的以太坊库可参考 https://github.com/web3j/web3j

- java Transaction：https://github.com/web3j/web3j/blob/master/core/src/main/java/org/web3j/protocol/core/methods/request/Transaction.java#L31



**tron**

编码规则（请求参数构建）：

- 通过proto协议将Transaction编码为byte数组，hex编码为字符串
  - proto编码：https://gist.github.com/miguelmota/25568433ad8cfddb5ea556a5644c9fde
  - hex编码：hex.EncodeToString



解码已签名交易（返回参数解析）：

- 先将字符串hex解码为byte数据，再将byte数组proto解码为tron交易Transaction



tron协议实现就是java，相关交易构建，编解码应该都有

https://github.com/tronprotocol/java-tron



## 请求参数示例

**CreateMnemonic**

`{"name":"test", "mnemonicType": 0}`

**CreateKey**

`{"name":"test4", "network": "eth", "index": 0}`

`{"name":"test4", "network": "tron", "index": 0}`

**GetIndex**

`{"network": "tron", "address": "TQxgjRTVjx6QsK4huSv2Ex3aUDJTs9g6X2"}`

`{"network": "eth", "address": "0x313A1F70aCA7dE919ff2104F50f94985308E38A8"}`

**GetAddress**

`{"name": "test", "network": "tron", "index": 0}`

`{"name": "test4","network": "eth", "index": 0}`

**Sign**

`{"network":"eth","sender":"0x313A1F70aCA7dE919ff2104F50f94985308E38A8","tx":" "}`

`{"network":"tron","sender":"TLZMwPhCvqGt8w4523L7ciMcEG4EWwxWKP","tx":"0ad0010a028042220801a85c6e6c4861f740c8938b95a1315aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a1541dc05f6df15aa25676218932957337f6dadd5fc91121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb0000000000000000000000008405fb55ed44d8212061672a83ddaafecec3388f00000000000000000000000000000000000000000000000000000000000f424070dbcb8795a131900132"}`

