# 平行链超级节点创建和超级账户管理介绍

> 平行链只有创建了超级账户组才能完成跨链资产的转移，包括从主链往平行链转移和从平行链向主链转移资产

## １．搭建超级节点过程介绍

### 1. 确定超级节点数量和每个超级节点分配的账户

- 每个超级节点的账户不同，配置到平行链配置文件里面的配置项: authAccount=””

  ```
    authAccount="1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"
  ```

- 超级节点的数量需要满足3f+1个(f=0,1,2,3…)，即可以建１，４，７…个超级节点

### ２. 修改平行链配置文件`chain33.para.toml`,以平行链`user.p.para.`为例

- 修改title

   ```
    Title="user.p.para."
   ```

- 修改平行链创世token

   ```
    CoinSymbol="para"
   ```

- 修改rpc 监控端口,如果不在一个节点上部署，可以不用修改

   ```
    [rpc]
    # 避免与主链配置冲突
    jrpcBindAddr="localhost:8901"
    grpcBindAddr="localhost:8902"
   ```

- 确定主链起始高度

   ```
     [consensus.sub.para]
      #主链指定高度的区块开始同步
      startHeight=345850
   ```

- 修改每个平行链配置文件的authAccount

   ```
     [consensus.sub.para]
    #验证账户，验证节点需要配置自己的账户，并且钱包导入对应种子，非验证节点留空
    authAccount="1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"
   ```

- 修改创世token数量和空块间隔（可选）

   ```
    #创世地址额度
  genesisAmount=100000000
  #主链每隔几个没有相关平行链交易的区块，平行链上打包空区块，缺省从平行链blockHeight=0开始，依次增长，空块间隔不能为0,50为缺省值，也可以调整
  emptyBlockInterval=["0:50"]
   ```

### ３. 每个平行链节点导入种子和私钥

> 根据如上jrpcBindAddr，平行链节点的端口号与主链不同，比如修改为8901端口，./chain33-cli 需要特别指定 —rpc_laddr [http://localhost:8901](http://localhost:8901/)

1. 钱包导入种子

   ```
    ./chain33-cli --rpc_laddr http://localhost:8901 seed save -p 1234password -s "tortoise main civil member grace happy century convince father cage beach hip maid merry rib"
   ```

2. 解锁钱包

   > 钱包必须在解锁状态超级账户才能发送共识
   >
   > ```
   >  ./chain33-cli --rpc_laddr http://localhost:8901 wallet unlock -p 1234password -t 0
   > ```

3. 导入超级账户私钥

   > 即导入每个超级账户的私钥，发送共识并挖矿

   ```
    ./chain33-cli --rpc_laddr http://localhost:8901  account import_key -k "$prikey" -l "$lable"
   ```

### 4. 创建超级账户组

> 只有主链的超级管理员账户能审批超级账户组申请，只有超级账户组成员才能发送共识交易

1. 申请超级账户组

   > 申请需要冻结一定的主链币，签名账户需要预先转入不少于规定的冻结数量的币到paracross合约，签名账户可以为第三方账户,多个超级账户可以一次同时申请，冻结币的数量为申请超级账户数量*单个账户冻结数量，目前支持fozen_coin为0，但是需要approve步骤超级管理员的允许

   ```
    chain33-cli --paraName user.p.para. para nodegroup apply -a "1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4,1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR,1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k,1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs" -c $fozen_coin
   ```

   或参考后面rpc接口创建,注意：这里只是构建原始交易，构建好之后，需要“签名”和“发送“才能查看到交易

2. 查询申请id

   > 申请交易id即上一步申请超级账户组的交易hash，也可以通过如下命令查看申请id
   >
   > ```
   >  chain33-cli --paraName user.p.para. para nodegroup list -s 1
   > ```

3. 批准超级账户组,id为申请超级账户组id，frozen_coin为主链超级管理员希望冻结的币，批准需要主链超级管理员批准，这个fozen_coin是apply单个账户frozen的数量，如果apply时候为0，这里也是0

   ```
    chain33-cli --paraName user.p.para. para nodegroup approve -i "$id" -c $frozen_coin
   ```

### 5. 使用自动化脚本

> 使用自动化脚本可以在一个宿主机上同时开启多个超级节点，监控不同端口，使用docker-compose工具，需要事先安装
> 参考如下文件夹下面的readme文件配置
>
> ```
> https://github.com/33cn/plugin/tree/master/plugin/dapp/paracross/cmd/scripts/autodeploy
> ```

## ２． 超级节点账户组创建交易结构详细介绍

> 超级节点账户组用于平行链超级节点共识的确认管理，只有在账户组内部的账户可以参与共识和得到挖矿奖励

**账户组创建提供了如下操作**

- 申请创建超级节点账户组
- 超级账户批准账户组的申请
- 取消正在申请的超级节点账户组
- 修改超级账户组参数

**说明**

- 账户组的申请者需要预先在paracross合约存一定量的币，申请后即冻结
- 超级账户批准所带的冻结币数量为准入币数量，申请者的冻结币不得少于审批者的币数量，否则申请者需取消申请，重新提交申请
- 在账户组的申请未批准之前，申请者可以取消申请，冻结币释放
- 超级账户组批准后也允许修改参数，比如冻结币数量，也需要超级管理员审批

### rpc 接口

1. 生成 申请创建账户组 的交易（未签名）

```
{
    "method" : "Chain33.CreateTransaction",
    "params" : [
        {
        "execer" : "{user.p.para}.paracross",
        "actionName" : "NodeGroupConfig",
        "payload" : {
　　　　　　　"title":"{user.p.para.}"
            "op" : "1",
            "addrs" : "1Ka7EPFRqerwerwuswpow7Qs,1G6qA4RQbNmbPJCZPjsfspopoowhe3T",
            "coinsFrozen":"500000000"
        }
        }
    ],
}
```

**参数说明：**

| 参数        | 类型   | 说明                                       |
| :---------- | :----- | :----------------------------------------- |
| method      | string | Chain33.CreateTransaction                  |
| execer      | string | 必须是平行链的执行器,user.p.para.paracross |
| actionName  | string | NodeConfig                                 |
| title       | string | 平行链title名字                            |
| op          | string | 配置类型：join：申请加入                   |
| addrs       | string | 申请账户，可以有多个                       |
| coinsFrozen | string | 冻结币数量                                 |

1. 审批 申请的创建账户组 的交易（未签名)

```
 {
    "method" : "Chain33.CreateTransaction",
    "params" : [
        {
            "execer" : "｛user.p.para｝.paracross",
            "actionName" : "NodeGroupConfig",
            "payload" : {
                "title":"{user.p.para.｝"
                "op" : "2",
                "id" : "0x1f2fsdfsfsdfsdfasadfsdfesiwiwoirwer",
                "coinsFrozen":"500000000"
            }
        }
    ],
    }
```

**参数说明：**

| 参数        | 类型   | 说明                                         |
| :---------- | :----- | :------------------------------------------- |
| method      | string | Chain33.CreateTransaction                    |
| execer      | string | paracross                                    |
| actionName  | string | NodeGroupConfig                              |
| op          | string | 配置类型：1:申请, 2:审批, 3:取消申请, 4:修改 |
| id          | string | 须与申请创建的id一致,或者就是申请的交易hash  |
| coinsFrozen | string | 审批要求的币数量                             |

1. 取消 申请的创建账户组 的交易（未签名）

```
{
    "method" : "Chain33.CreateTransaction",
    "params" : [
        {
            "execer" : "{user.p.para}.paracross",
            "actionName" : "NodeGroupConfig",
            "payload" : {
            "title":"｛user.p.para}."
            "op" : "3",
            "id" : "0xf2fsdfsfsdfsdfasadfsdfesiwiwoirwer",
            }
        }
    ],
    "jsonrpc" : "2.0"
}
```

**参数说明：**

| 参数       | 类型   | 说明                                              |
| :--------- | :----- | :------------------------------------------------ |
| method     | string | Chain33.CreateTransaction                         |
| execer     | string | paracross                                         |
| actionName | string | NodeGroupConfig                                   |
| op         | string | 配置类型：1：申请，2：审批通过,3:取消申请,4：修改 |
| id         | string | 须与申请创建的账户完全一致                        |

1. 修改 创建账户组参数 的交易（未签名）

```
{
    "method" : "Chain33.CreateTransaction",
    "params" : [
        {
            "execer" : "{user.p.para}.paracross",
            "actionName" : "NodeGroupConfig",
            "payload" : {
            "title":"{user.p.para}."
            "op" : "4",
            "coinFrozen" : "600000000",
            }
        }
    ],
}
```

**参数说明：**

| 参数       | 类型   | 说明                                           |
| :--------- | :----- | :--------------------------------------------- |
| method     | string | Chain33.CreateTransaction                      |
| execer     | string | paracross                                      |
| actionName | string | NodeGroupConfig                                |
| op         | string | 配置类型：1：申请，2：审批,3:取消申请，4：修改 |
| coinFrozen | int64  | 修改的冻结币的数量                             |

1. 查询 账户组的账户信息

```
{
    "method" : "Chain33.Query",
    "params" : [
        {
            "execer":"paracross",
            "funcName": "GetNodeGroupAddrs"
            "payload":{"title" : "user.p.para."}
        }
    ],
}
```

**参数说明：**

| 参数   | 类型   | 说明              |
| :----- | :----- | :---------------- |
| method | string | Chain33.Query     |
| title  | string | 平行链的title名字 |

**响应数据：**

```
{
        "key": "mavl-paracross-nodes-title-user.p.para.",
        "value": "[1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4 1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs]"
}
```

- 查询 账户组的当前状态

```
{
    "method" : "Chain33.Query",
    "params" : [
        {
            "execer":"paracross",
            "funcName": "GetNodeGroupStatus"
            "payload":{"title" : "user.p.para."}
        }
    ],
}
```

**参数说明：**

| 参数   | 类型   | 说明              |
| :----- | :----- | :---------------- |
| method | string | Chain33.Query     |
| title  | string | 平行链的title名字 |

**响应数据：**

```
    {
        "status": 2,
        "title": "user.p.para.",
        "applyAddr": "1E5saiXVb9mW8wcWUUZjsHJPZs5GmdzuSY,1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4,1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR,1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k,1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs",
        "coinsFrozen": 500000000,
        "fromAddr": "1Ka7EPFRqs3v9yreXG6qA4RQbNmbPJCZPj",
        "height": 550,
    }
```

- 查询 按状态查询账户组的申请信息

```
{
    "method" : "Chain33.Query",
    "params" : [
        {
            "execer":"paracross",
            "funcName": "ListNodeGroupStatus"
            "payload":{"status" : 1}
        }
    ],
}
```

**参数说明：**

| 参数   | 类型   | 说明                                        |
| :----- | :----- | :------------------------------------------ |
| method | string | paracross.GetNodeGroupAddrs                 |
| status | int    | 0: 全部，1：申请，2：批准，3：退出，4：修改 |

- 超级节点账户组管理

**账户组管理提供了如下操作**

- 申请加入超级节点账户组
- 对申请的账户投票，当前账户组超过2/3账户投票通过或否决
- 申请退出超级节点账户组
- 申请在未投票通过前撤销

**说明**

- 加入账户组的申请者需要预先在paracross合约存一定量的币，币数量不少于账户组申请冻结币数量，申请后即冻结
- 当前超级账户组成员投票同意或否决新节点的加入
- 当前超级账户组成员申请退出账户组
- 申请加入和退出都是针对某个账户提的提案，可以对此提案投票或撤销

### rpc 接口

1.　生成 申请加入账户组 的交易（未签名）

```
{
    "method" : "Chain33.CreateTransaction",
    "params" : [
    {
        "execer" : "{user.p.para}.paracross",
        "actionName" : "NodeConfig",
        "payload" : {
            "title":"{user.p.para}."
            "op" : "1",
            "addr" : "1E5saiXVb9mW8wwypiZjsHJPZs5GmdzuSY",
            "coinsFrozen":"500000000"
        }
    }
    ],
}
```

**参数说明：**

| 参数        | 类型   | 说明                                                 |
| :---------- | :----- | :--------------------------------------------------- |
| method      | string | Chain33.CreateTransaction                            |
| execer      | string | paracross                                            |
| actionName  | string | NodeConfig                                           |
| op          | string | 配置类型：1：申请加入，2：投票，3：申请退出，4：撤销 |
| addrs       | string | 申请账户，只允许一个                                 |
| coinsFrozen | string | 冻结币数量                                           |

1. 生成 对申请加入账户组的账户投票 的交易（未签名）

```
{
    "method" : "Chain33.CreateTransaction",
    "params" : [
        {
        "execer" : "{user.p.para}.paracross",
        "actionName" : "NodeConfig",
        "payload" : {
            "title":"{user.p.para}."
            "op" : "2",
            "id" : "0xf2fsdfsfsdfsdfasadfsdfesiwiwoirwer",
            "value":"1"
        }
        }
    ],
}
```

**参数说明：**

| 参数       | 类型   | 说明                      |
| :--------- | :----- | :------------------------ |
| method     | string | Chain33.CreateTransaction |
| execer     | string | paracross                 |
| actionName | string | NodeConfig                |
| op         | uint32 | 配置类型：2：投票         |
| id         | string | 申请的账户的申请id        |
| value      | uint32 | 1：yes,2:no               |

1. 生成 退出账户组 的交易（未签名）

```
{
    "method" : "Chain33.CreateTransaction",
    "params" : [
        {
        "execer" : "{user.p.para}.paracross",
        "actionName" : "NodeConfig",
        "payload" : {
            "title":"{user.p.para}."
            "op" : "3",
            "addr" : "1E5saiXVb9mW8wwypiZjsHJPZs5GmdzuSY",
        }
        }
    ],
    "jsonrpc" : "2.0"
}
```

**参数说明：**

| 参数       | 类型   | 说明                       |
| :--------- | :----- | :------------------------- |
| method     | string | Chain33.CreateTransaction  |
| execer     | string | paracross                  |
| actionName | string | NodeConfig                 |
| op         | uint32 | 配置类型：3：退出账户组    |
| addrs      | string | 申请退出的账户，只允许一个 |

1. 查询 按状态查询账户的申请信息

```
{
    "method" : "Chain33.Query",
    "params" : [
        {
            "execer":"paracross",
            "funcName": "ListNodeStatus"
            "payload":{"title" : "{user.p.para}.","status" : 4}
        }
    ],
}
```

**参数说明：**

| 参数   | 类型   | 说明                                                        |
| :----- | :----- | :---------------------------------------------------------- |
| method | string | Chain33.Query                                               |
| title  | string | 平行链的title名字                                           |
| status | int    | 0：全部，1：申请加入，2：申请退出，3：申请关闭，4：申请撤销 |

*响应数据：*

```
{
        "status": 4,
        "title": "user.p.para.",
        "targetAddr": "1E5saiXVb9mW8wcWUUZjsHJPZs5GmdzuSY",
        "coinsFrozen": 500000000,
        "votes": {
            "addrs": [
                "1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4",
                "1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR",
                "1E5saiXVb9mW8wcWUUZjsHJPZs5GmdzuSY",
                "1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"
            ],
            "votes": [
                "yes",
                "yes",
                "yes",
                "yes"
            ]
        },
        "fromAddr": "1Ka7EPFRqs3v9yreXG6qA4RQbNmbPJCZPj"
    }
```

1. 查询 按账户查询账户的申请信息

> 说明：status：10：joined， 11： quited

```
{
    "method" : "Chain33.Query",
    "params" : [
        {
            "execer":"paracross",
            "funcName": "GetNodeAddrStatus"
            "payload":{"title" : "{user.p.para}.","addr" : “1E5saiXVb9mW8wcWUUZjsHJPZs5GmdzuSY”}
        }
    ],
}
```

**参数说明：**

| 参数   | 类型   | 说明                      |
| :----- | :----- | :------------------------ |
| method | string | Chain33.GetNodeAddrStatus |
| title  | string | 平行链的title名字         |
| addr   | string | 申请的账户信息            |

**响应数据：**

```
{
        "addr": "1E5saiXVb9mW8wcWUUZjsHJPZs5GmdzuSY",
        "title": "user.p.para.",
        "proposalId": "0xf2fsdfsfsdfsdfasadfsdfesiwiwoirwer",
        "quitId": "0xf2fsdfsfsdfsdfasadfsdfesiwiwoirwer",
        "status": 11,
    }
```

1. 查询 按申请id查询信息

   > 说明：status：1：申请加入， 2： 申请退出，3：申请关闭，4：申请撤销

```
{
    "method" : "Chain33.Query",
    "params" : [
        {
            "execer":"paracross",
            "funcName": "GetNodeAddrStatus"
            "payload":{"title" : "{user.p.para}.",""id" : “0xf2fsdfsfsdfsdfasadfsdfesiwiwoirwer”,}
        }
    ],
}
```

**参数说明:**

| 参数   |   类型 | 说明                      |
| :----- | -----: | :------------------------ |
| method | string | Chain33.GetNodeAddrStatus |
| title  | string | 平行链的title名字         |
| id     | string | 申请的id                  |

**响应数据：**

```
    {
        "status": 4,
        "title": "user.p.para.",
        "applyAddr": "1E5saiXVb9mW8wcWUUZjsHJPZs5GmdzuSY",
        "coinsFrozen": 500000000,
        "votes": {
            "addrs": [
                "1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4",
                "1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR",
                "1E5saiXVb9mW8wcWUUZjsHJPZs5GmdzuSY",
                "1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"
            ],
            "votes": [
                "yes",
                "yes",
                "yes",
                "yes"
            ]
        },
        "fromAddr": "1Ka7EPFRqs3v9yreXG6qA4RQbNmbPJCZPj"，
        "height": 100
    }
```

## ４. 共识问题的排查

### １. 是否共识账户组已经配好

```
平行链上查询共识账户组账户，如果返回错误说明没配置好，查询之前的para nodegroup apply和 approve 步骤的交易是否执行成功
./chain33-cli  --rpc_laddr http://ip:8901  --paraName user.p.game.  para nodegroup addrs
{
    "key": "mavl-paracross-nodes-title-user.p.game.",
    "value": "[1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR 1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k 1MCftFynyvG2F4ED5mdHYgziDxx6vDrScs 1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4]"
}
```

### 2. 是否平行链钱包解锁状态

```
./bityuan-cli --rpc_laddr http://ip:8901 wallet status
{
    "isWalletLock": false,  ----- 需要是false
    "isAutoMining": true,
    "isHasSeed": true,
    "isTicketLock": true
}
```

### 3. 是否当前节点共识账户配置在配置文件

```
[consensus.sub.para]
authAccount="1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4"  ---不可为空
```

### 4. 当前共识高度的查看

```
./chain33-cli --rpc_laddr http://ip:8901 para height
或
 {
       "method" : "Chain33.Query",
       "params" : [
          {
             "execer":"paracross",
             "funcName": "GetHeight"
             "payload":{"data" : "{user.p.para}."}
          }
       ],
 }
```

**响应:**

```
{"id":null,"result":{
    "title":"user.p.para.",
    "chainHeight":1765,
    "consensHeight":1765,
    "consensBlockHash":"0xd53b73cd97710fa626cda543f4fbaaa10aac480ca355d2520e0477b9c53fe4bc"},
    "error":null
}
```

**说明:**

> 如果是在主链查询，chainHeight 和consensHeight 都是平行链共识到的高度，如果是在平行链查询，如下说明：

- chainHeight: 当前链的高度
- consensHeight: 当前链共识到的高度

### 5. 查看某个高度共识发送情况

> 如果共识到某个高度不再增长，可以查看下一个高度超级账户发送共识细节

```
./bityuan-cli --rpc_laddr http://ip:8901 --paraName user.p.para. para consens_status -g 1
1是待共识的高度
或
curl -ksd  '{"method":"Chain33.Query","params":[{ "execer":"paracross", "funcName": "GetTitleHeight", "payload" : {"title":"user.p.para.","height":1}}]}' http://172.20.0.3:8801
```

**响应:**

```
{"id":null,"result":{
    "title":"user.p.para.",
    "height":1,
    "mainHeight":4,
    "mainHash":"0x53ee765d89f34be70f60227339d45c425599902973201286219e327191f11114",
    "commitAddrs":[
        "1KSBd17H7ZK8iT37aJztFB22XGwsPTdwE4",
        "1JRNjdEqp4LJ5fqycUBm9ayCKSeeskgMKR","
        1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k"],
    "commitBlockHash":[
        "0x59c5b9b657a3438634a91f1a56f7f18f71c3918e52dbfc22477580df25260fb2","0x59c5b9b657a3438634a91f1a56f7f18f71c3918e52dbfc22477580df25260fb2","0x77c5b9b657a3438634a91f1a56f7f18f71c3918e52dbfc22477580df25260fb2"]},
    "error":null}
```

**说明:**

- height: 平行链高度
- mainHeight: 平行链高度对应主链高度
- commitAddrs: 在此高度有哪些超级账户发送了共识
- commitBlockHash: 对应超级账户发送的共识块hash
- 可以看到“1NLHPEcbTWWxxU3dGUZBhayjrCHD3psX7k”　发送的共识hash是“0x77c5b9b657a3438634a91f1a56f7f18f71c3918e52dbfc22477580df25260fb2”　和其他账户发送不同，是导致共识不过的原因

### 6. 如果主链是联盟链且Title=local场景

> 由于主链是联盟链，所有fork都跟BTY不一致，平行链两个配置项需要相应修改

```
[consensus.sub.para]
mainForkParacrossCommitTx=10
mainLoopCheckCommitTxDoneForkHeight=60
这两个高度和local的主链场景下的fork高度保持一致，如果联盟链Title不是local, 可以 mainForkParacrossCommitTx=1，mainLoopCheckCommitTxDoneForkHeight=1（不能为0，否则代码会解析为最大高度），同时配置文件的startHeight需要大于1.
```

