
# 一.Dpos投票合约介绍  
该合约主要是配合Dpos共识，完成：  
（1）候选节点的注册、去注册、投票及查询管理。  
（2）Dpos共识运行过程中，得票数TopN（N为约定的受托节点数量）受托节点的VRF相关信息的分阶段发布管理。  

概要描述如下：  
（1）系统初始运行时，会有默认的几个受托节点进行共识运行。  
（2）系统运行后，可以重新选举受托节点，各个候选节点需要抵押10000个币，注册成为候选节点。  
（3）候选节点可以在社区宣传，让大家为自己投票。  
（4）用户可以为自己支持的候选节点投票。投票后，资金会冻结，3天以后才可以撤销投票(可以调整)。  
（5）系统运行过程中，周期性重新获取当前投票数据，并确定下一个时间段的受托节点。  
（6）受托节点进行共识出块，每个cycle（一个cycle中，各个受托节点轮番出块，直到都轮一遍）分两个阶段进行VRF信息发布：  
     第一个阶段，各个受托节点发布自己的VRF的M信息  
     第二个阶段，各个受托节点发布自己的VRF的R、P信息  
     上述VRF的M、R、P可以验证。  
（7）新的cycle中，使用上述VRF信息进行受托节点的出块顺序的重新洗牌，按洗牌结果决定各受托节点出块的顺序  


# 二.测试准备  
./chain33-cli  --rpc_laddr="${rpcAddr}" seed generate -l 0  
museum company museum put digital march stadium dutch call matter mind error elbow battle avocado  

./chain33-cli  --rpc_laddr="${rpcAddr}" seed save -s "museum company museum put digital march stadium dutch call matter mind error elbow battle avocado" -p zzh123456  


./chain33-cli  --rpc_laddr="${rpcAddr}" wallet unlock -p zzh123456  


./chain33-cli  --rpc_laddr="${rpcAddr}" account create -l zzh  
{  
    "acc": {  
        "balance": "0.0000",  
        "frozen": "0.0000",  
        "addr": "1Efuj3B1LLAiD8xeZbxvjpuUpidDyequ1o"  
    },  
    "label": "zzh"  
}  

./chain33-cli  --rpc_laddr="${rpcAddr}" account import_key -k "CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944" -l genesis  

./chain33-cli  --rpc_laddr="${rpcAddr}" account import_key -k "4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01" -l genesis2  

# 三.导入超级节点的私钥到各个超级节点上  
./chain33-cli  --rpc_laddr="${rpcAddr}" account import_key -k "5A6A14DA6F5A42835E529D75D87CC8904544F59EEE5387A37D87EEAD194D7EB2" -l test1  
./chain33-cli  --rpc_laddr="${rpcAddr}" account import_key -k "754F53FCEA0CB1F528918726A49B3551B7F1284D802A1D6AAF4522E8A8DA1B5B" -l test2  
./chain33-cli  --rpc_laddr="${rpcAddr}" account import_key -k "85CA38F5FB65E5E13403F0704CA6DC479D8D18FFA5D87CE5A966838C9694EAFE" -l test3  

公私钥用secp256k1体系的，无论是共识消息的签名验签，还是账户代币抵押，以及参与VRF运算，都是一套公私钥。  


# 四.超级节点账户转入抵押用的代币
## （1）向各个超级节点的地址上转入代币，用于抵押  
./chain33-cli  --rpc_laddr="${rpcAddr}" coins transfer -a 20000 -t 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b  
./chain33-cli  --rpc_laddr="${rpcAddr}" coins transfer -a 20000 -t 14w5JaGDrXTZwF5Wv51UAtuGgAupenLAok  
./chain33-cli  --rpc_laddr="${rpcAddr}" coins transfer -a 20000 -t 1DQUALqaqPUhJX6FWMCqhvnjrkb6ZfrRmf  

./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -d  

./chain33-cli  --rpc_laddr="${rpcAddr}" wallet send -d  

./chain33-cli  --rpc_laddr="${rpcAddr}" account balance -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt  

## （2）查看账户余额  
./chain33-cli  --rpc_laddr="${rpcAddr}" account balance -a 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b  
./chain33-cli  --rpc_laddr="${rpcAddr}" account balance -a 14w5JaGDrXTZwF5Wv51UAtuGgAupenLAok  
./chain33-cli  --rpc_laddr="${rpcAddr}" account balance -a 1DQUALqaqPUhJX6FWMCqhvnjrkb6ZfrRmf  


## （3）构造交易，从各个超级节点的账户向DPos合约转入抵押抵押用的代币，比如10000个。  
./chain33-cli  --rpc_laddr="${rpcAddr}" coins send_exec -a 15000 -e dpos
0a05636f696e731235180a2a311080b0def7d32b220464706f732a2231435039566e7666534c594e5a75696864424a6e324e587179776d5178487a6d394420a08d0630998ee6f1c7f1afda6e3a2231435039566e7666534c594e5a75696864424a6e324e587179776d5178487a6d3944  

./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b -d  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 14w5JaGDrXTZwF5Wv51UAtuGgAupenLAok -d  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 1DQUALqaqPUhJX6FWMCqhvnjrkb6ZfrRmf -d  

./chain33-cli  --rpc_laddr="${rpcAddr}" wallet send -d  

./chain33-cli  --rpc_laddr="${rpcAddr}" tx query -s 0x41b620574d0717364892799650509b4fd1184383e5d7e6e7668da599d643cc3f  

# 五.通过Dpos合约接口和合约进行交互  


![Dpos投票合约状态示意图](./dpos合约状态变迁.png)  

user@zzh-PC:~/work/dposv2$ ./chain33-cli  --rpc_laddr="${rpcAddr}" dpos
dpos vote management  

Usage:  
  -cli dpos [command]  

Available Commands:  
  cancelRegist    cancel regist for a candidator  
  cancelVote      cancel votes to a candidator  
  candidatorQuery query candidator info  
  reRegist        re regist a canceled candidator  
  regist          regist a new candidator  
  vote            vote for one candidator  
  voteQuery       query vote info  
  vrfMRegist      regist m of vrf  
  vrfQuery        query vrf info  
  vrfRPRegist     regist r,p of vrf  

## （1）转入足够数量的抵押代币后，可以注册为超级节点的候选节点，注册成功代币将被冻结在合约中。  
./chain33-cli  --rpc_laddr="${rpcAddr}" dpos regist -a 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b -i 192.168.0.155 -k 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b -d  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet send -d  


./chain33-cli  --rpc_laddr="${rpcAddr}" dpos regist -a 14w5JaGDrXTZwF5Wv51UAtuGgAupenLAok -k 027848E7FA630B759DB406940B5506B666A344B1060794BBF314EB459D40881BB3  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 14w5JaGDrXTZwF5Wv51UAtuGgAupenLAok -d  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet send -d  

./chain33-cli  --rpc_laddr="${rpcAddr}" dpos regist -a 1DQUALqaqPUhJX6FWMCqhvnjrkb6ZfrRmf -k 03F4AB6659E61E8512C9A24AC385CC1AC4D52B87D10ADBDF060086EA82BE62CDDE  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 1DQUALqaqPUhJX6FWMCqhvnjrkb6ZfrRmf -d  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet send -d  


## （2）可通过查询交易了解具体执行结果  
./chain33-cli  --rpc_laddr="${rpcAddr}"  tx query -s 0xd2649fe7ecf8e3fbd94044a46ee94c82cfc500f55ca63d3ffd314e3bcec6d47b  

## （3）已注册节点可以撤销注册，撤销成功后，抵押冻结的代币将被解除冻结  
./chain33-cli  --rpc_laddr="${rpcAddr}" dpos cancelRegist -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -k 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -d  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet send -d  

./chain33-cli  --rpc_laddr="${rpcAddr}" dpos cancelRegist -a 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b -k 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b -d  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet send -d  

## （4）已撤销注册的节点可以重新注册，再次成为备选节点,抵押代币同样将被冻结  
./chain33-cli  --rpc_laddr="${rcpAddr}" dpos reRegist -a ${addr} -i ${ip} -k ${key}  
./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a ${addr} -d $tx  
./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d "$sig"  

## （5）任意账户地址在Dpos合约中有代币，都可抵押代币（冻结在合约中）向超级节点投票：  
./chain33-cli  --rpc_laddr="${rcpAddr}" dpos vote -k ${key} -v ${votes} -a ${addr}  
./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a ${addr} -d $tx  
./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d "$sig"  

## （6）任意账户地址投票后，可以撤回投票，抵押的代币解除冻结：  
./chain33-cli  --rpc_laddr="${rcpAddr}" dpos cancelVote -k ${key} -v ${votes}  
./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a ${addr} -d $tx  
./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d "$sig"  

## （7）查询备选节点信息（支持按公钥查询，按TOPN(投票数排序)查询）：  
 ./chain33-cli  --rpc_laddr="${rpcAddr}" dpos candidatorQuery   -t pubkeys -k 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4  
 ./chain33-cli  --rpc_laddr="${rpcAddr}" dpos candidatorQuery   -t topN -n 1  
 
## （8）某个地址投票给某个超级节点的票数信息。   
./chain33-cli  --rpc_laddr="${rpcAddr}" dpos voteQuery -a 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt -k 027848E7FA630B759DB406940B5506B666A344B1060794BBF314EB459D40881BB3  


# 六.超级节点切换的逻辑  
如果超级节点数量超过约定数量（比如约定21个，实际100个），则将统计投票数进行切换，共识模块周期检测DPos投票合约，获取TopN（比如得票数前21）的节点，如果发现节点有变化，chain33将重启共识模块，用新的超级节点进行共识。  

![Dpos超级节点替换处理流程](./Dpos超级节点替换处理流程.png)   
这个处理过程可以优化。  

目前采用周期性发起jsonrpc调用，查询合约中的TOPN节点信息的方式。是否有更合适的方式？直接读数据库？  
当超级节点有更新时，采用了重启共识模块的方式，是否有副作用？ 有没有更好的方式？  


# 七.采用VRF算法来确定超级节点的出块顺序  

VRF要点：  
```go
k, pk := GenerateKey() //生成secp256k1公私钥
r, p := k.Evaluate(m)  //私钥对明文m计算出r,p，并对外公布
r' := pk.ProofToHash(m, p) //可以用公钥对m，p进行计算，得到的r'
r == r' //如果与r一致，则得到验证
```

Dpos超级节点MRP发布及节点更替示意图:  
![Dpos超级节点MRP发布流程](./dpos-mrp.png)   

## （1）各个超级节点，在一个Cycle开始时，发布各自的M  
./chain33-cli  --rpc_laddr="${rpcAddr}" dpos vrfMRegist -c 10001 -m data1 -k 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b -d  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet send -d  

## （2）各个超级节点，在一个Cycle的下半周期开始，发布各自的R、P  
./chain33-cli  --rpc_laddr="${rpcAddr}" dpos vrfRPRegist -c 10001 -r 22a58fbbe8002939b7818184e663e6c57447f4354adba31ad3c7f556e153353c -p 5ed22d8c1cc0ad131c1c9f82daec7b99ff25ae5e717624b4a8cf60e0f3dca2c97096680cd8df0d9ed8662ce6513edf5d1676ad8d72b7e4f0e0de687bd38623f404eb085d28f5631207cf97a02c55f835bd3733241c7e068b80cf75e2afd12fd4c4cb8e6f630afa2b7b2918dff3d279e50acab59da1b25b3ff920b69c443da67320 -k 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4  
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet sign -a 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b -d   
./chain33-cli  --rpc_laddr="${rpcAddr}" wallet send -d  

## （3）可以按时间或者时间戳或者cycle来查询某个时间点或者周期内各超级节点生成的VRF信息。  
./chain33-cli  --rpc_laddr="${rpcAddr}" dpos  vrfQuery -t time -d “2019-07-10 18:00:00”  
./chain33-cli  --rpc_laddr="${rpcAddr}" dpos  vrfQuery -t timestamp -s 121212123  
./chain33-cli  --rpc_laddr="${rpcAddr}" dpos  vrfQuery -t cycle -c 10001  

## （4）每个周期的VRF信息，用于新周期的超级节点出块排序。超级节点根据上一周期的VRF信息来决定新一周期的出块顺序  
针对每个超级节点的M，R，P进行计算：hash（上一周期的blockhash+R），结果进行排序，决定节点在新周期的出块顺序。  
问题：  
（1）如果超级节点不变，好处理。  
（2）如果超级节点发生变化，如何处理比较合适？仍然直接使用？  
（3）对于m、r、p验证不通过或者未提交、未提交完整的节点，如何惩罚？ 暂不允许出块吗？  
 (4) 目前对于激励还缺乏整体设计，没有加入挖矿，超级节点如何收益？如何激励投票？
（5）整体上还有不少细节场景需要考虑。

///////////////  
# 八.附录1：  

以下为使用快捷脚本init.sh的命令，减少命令输入，方便测试使用。  
./init.sh init  

./init.sh sendExec  
./init.sh reg 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b 192.168.0.155 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4  
./init.sh reg 14w5JaGDrXTZwF5Wv51UAtuGgAupenLAok 192.168.0.194 027848E7FA630B759DB406940B5506B666A344B1060794BBF314EB459D40881BB3  
./init.sh reg 1DQUALqaqPUhJX6FWMCqhvnjrkb6ZfrRmf 192.168.0.100 03F4AB6659E61E8512C9A24AC385CC1AC4D52B87D10ADBDF060086EA82BE62CDDE  

./init.sh  qtx 0x0258f26e52c7baa96478eac6e1f84b07c2c457f3c2ec594b1f135040ac437f45  
./init.sh qn 1  
./init.sh vote 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt 027848E7FA630B759DB406940B5506B666A344B1060794BBF314EB459D40881BB3 30  
./init.sh vote 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4 100  
./init.sh vote 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt 03F4AB6659E61E8512C9A24AC385CC1AC4D52B87D10ADBDF060086EA82BE62CDDE 200  

./init.sh reReg 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b 192.168.0.155 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4  

./init.sh qk 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4  
./init.sh qk 027848E7FA630B759DB406940B5506B666A344B1060794BBF314EB459D40881BB3  
./init.sh qk 03F4AB6659E61E8512C9A24AC385CC1AC4D52B87D10ADBDF060086EA82BE62CDDE  
./init.sh qk 03F4AB6659E61E8512C9A24AC385CC1AC4D52B87D10ADBDF060086EA82BE62CDDE;03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4;027848E7FA630B759DB406940B5506B666A344B1060794BBF314EB459D40881BB3  

./init.sh qv 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt 027848E7FA630B759DB406940B5506B666A344B1060794BBF314EB459D40881BB3  
./init.sh qv 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt 03EF0E1D3112CF571743A3318125EDE2E52A4EB904BCBAA4B1F75020C2846A7EB4  
./init.sh qv 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt 03F4AB6659E61E8512C9A24AC385CC1AC4D52B87D10ADBDF060086EA82BE62CDDE  


./init.sh cancelVote 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt 03F4AB6659E61E8512C9A24AC385CC1AC4D52B87D10ADBDF060086EA82BE62CDDE 200  

# 九.附录2：
以下为方便测试使用的init.sh脚本的内容：  
```shells
rcpAddr="http://192.168.0.155:9801"
function impKey() {
	key=$1
	lab=$2
	./chain33-cli  --rpc_laddr="${rcpAddr}" account import_key -k "${key}" -l "${lab}"
}

function trans() {
	src=$1
	dst=$2
	coins=$3

	tx=`./chain33-cli  --rpc_laddr="${rcpAddr}" coins transfer -a $coins -t $dst`
        echo $tx
        sig=`./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a $src -d "$tx"`
        echo $sig
        ./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d "$sig"
        sleep 3
        ./chain33-cli  --rpc_laddr="${rcpAddr}" account balance -a $dst
}

function init() {
	seed=`./chain33-cli  --rpc_laddr="${rcpAddr}" seed generate -l 0`
	echo $seed
	echo "save seed..."
	./chain33-cli  --rpc_laddr="${rcpAddr}" seed save -s "${seed}" -p zzh123456
	sleep 1

	echo "unlock wallet..."
	./chain33-cli  --rpc_laddr="${rcpAddr}" wallet unlock -p zzh123456
	sleep 1

	echo "import key..."
	impKey "CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944" "genesis"
	impKey "4257D8692EF7FE13C68B65D6A52F03933DB2FA5CE8FAF210B5B8B80C721CED01" "genesis2"
	impKey "5A6A14DA6F5A42835E529D75D87CC8904544F59EEE5387A37D87EEAD194D7EB2" "test1"
	impKey "754F53FCEA0CB1F528918726A49B3551B7F1284D802A1D6AAF4522E8A8DA1B5B" "test2"
	impKey "85CA38F5FB65E5E13403F0704CA6DC479D8D18FFA5D87CE5A966838C9694EAFE" "test3"
	sleep 1

	echo "transfer coins to test1 account..."
        trans "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt" "15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b" 20000

	echo "transfer coins to test2 account..."
        trans "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt" "14w5JaGDrXTZwF5Wv51UAtuGgAupenLAok" 20000

	echo "transfer coins to test3 account..."
        trans "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt" "1DQUALqaqPUhJX6FWMCqhvnjrkb6ZfrRmf" 20000
}

function send_exec(){
	addr=$1
	coins=$2
	tx=`./chain33-cli  --rpc_laddr="${rcpAddr}" coins send_exec -a $coins -e dpos`
	sig=`./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a ${addr} -d ${tx}`
	./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d ${sig}
}

function reg(){
	addr=$1
	ip=$2
	key=$3
	echo "dpos regist -a ${addr} -i ${ip} -k ${key}"
	tx=`./chain33-cli  --rpc_laddr="${rcpAddr}" dpos regist -a ${addr} -i ${ip} -k ${key}`
	sig=`./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a ${addr} -d $tx`
	./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d "$sig"
	sleep 3
}

function reReg(){
	addr=$1
	ip=$2
	key=$3
	echo "dpos reRegist -a ${addr} -i ${ip} -k ${key}"
	tx=`./chain33-cli  --rpc_laddr="${rcpAddr}" dpos reRegist -a ${addr} -i ${ip} -k ${key}`
	sig=`./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a ${addr} -d $tx`
	./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d "$sig"
	sleep 3
}
function cancelReg(){
        addr=$1
        key=$2
        echo "dpos cancelRegist -a ${addr} -k ${key}"
        tx=`./chain33-cli  --rpc_laddr="${rcpAddr}" dpos cancelRegist -a ${addr} -k ${key}`
        sig=`./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a ${addr} -d $tx`
        ./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d "$sig"
        sleep 3
}
function vote(){
	addr=$1
	key=$2
	votes=$3
	echo "dpos vote from addr:${addr} to key:${key} $votes votes"
	tx=`./chain33-cli  --rpc_laddr="${rcpAddr}" dpos vote -k ${key} -v ${votes} -a ${addr}`
        sig=`./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a ${addr} -d $tx`
        ./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d "$sig"
        sleep 3
}
function cancelVote(){
        addr=$1
        key=$2
        votes=$3
        echo "dpos cancel vote from addr:${addr} to key:${key} $votes votes"
        tx=`./chain33-cli  --rpc_laddr="${rcpAddr}" dpos cancelVote -k ${key} -v ${votes}`
        sig=`./chain33-cli  --rpc_laddr="${rcpAddr}" wallet sign -a ${addr} -d $tx`
        ./chain33-cli  --rpc_laddr="${rcpAddr}" wallet send -d "$sig"
        sleep 3
}

function qtx(){
	tx=$1
	./chain33-cli  --rpc_laddr="${rcpAddr}" tx query -s ${tx}
}
function qn(){
	 ./chain33-cli  --rpc_laddr="${rcpAddr}" dpos candidatorQuery   -t topN -n $1
}

function qk(){
	./chain33-cli  --rpc_laddr="${rcpAddr}" dpos candidatorQuery   -t pubkeys -k $1
}

function qv(){
	./chain33-cli  --rpc_laddr="${rcpAddr}" dpos voteQuery -a $1 -k $2 
}

function unlock(){
	./chain33-cli  --rpc_laddr="${rcpAddr}" wallet unlock -p zzh123456
}

#main

	para="$1"
	if [ "$para" == "init" ];then
		init
	elif [ "$para" == "sendExec" ];then
		send_exec 15LsTP6tkYGZcN7tc1Xo2iYifQfowxot3b 15000
        	send_exec 14w5JaGDrXTZwF5Wv51UAtuGgAupenLAok 15000
        	send_exec 1DQUALqaqPUhJX6FWMCqhvnjrkb6ZfrRmf 15000
	elif [ "$para" == "reg" ];then
		reg "$2" "$3" "$4"
	elif [ "$para" == "cancelReg" ];then
		cancelReg "$2" "$3"
	elif [ "$para" == "reReg" ];then
		reReg "$2" "$3" "$4"
	elif [ "$para" == "vote" ];then
		vote "$2" "$3" "$4"
	elif [ "$para" == "cancelVote" ];then
		cancelVote "$2" "$3" "$4"
	elif [ "$para" == "qtx" ];then
		qtx "$2"
	elif [ "$para" == "qtx" ];then
		qtx "$2"
	elif [ "$para" == "sendDpos" ];then
		send_exec $2 $3
	elif [ "$para" == "qn" ];then
		qn $2
	elif [ "$para" == "qv" ];then
		qv $2 $3
	elif [ "$para" == "qk" ];then
		qk $2
	elif [ "$para" == "unlock" ];then
		unlock
	fi
```

