Commit 4596d426 authored by hezhengjun's avatar hezhengjun

Merge branch 'x2eth_200507' of github.com:zhengjunhe/plugin into x2eth_200507

parents a4adaa12 f1803086
#!/usr/bin/env bash
# shellcheck disable=SC2128
# shellcheck source=/dev/null
set -x
set +e
source "./publicTest.sh"
CLIA="./ebcli_A"
CLIB="./ebcli_B"
CLIC="./ebcli_C"
CLID="./ebcli_D"
chain33SenderAddr="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
chain33SenderAddrKey="CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944"
# validatorsAddr=["0x92c8b16afd6d423652559c6e266cbe1c29bfd84f", "0x0df9a824699bc5878232c9e612fe1a5346a5a368", "0xcb074cb21cdddf3ce9c3c0a7ac4497d633c9d9f1", "0xd9dab021e74ecf475788ed7b61356056b2095830"]
ethValidatorAddrKeyA="3fa21584ae2e4fd74db9b58e2386f5481607dfa4d7ba0617aaa7858e5025dc1e"
ethValidatorAddrKeyB="a5f3063552f4483cfc20ac4f40f45b798791379862219de9e915c64722c1d400"
ethValidatorAddrKeyC="bbf5e65539e9af0eb0cfac30bad475111054b09c11d668fc0731d54ea777471e"
ethValidatorAddrKeyD="c9fa31d7984edf81b8ef3b40c761f1847f6fcd5711ab2462da97dc458f1f896b"
# 新增地址 chain33 需要导入地址 转入 10 bty当收费费
chain33Validator1="1GTxrmuWiXavhcvsaH5w9whgVxUrWsUMdV"
chain33Validator2="155ooMPBTF8QQsGAknkK7ei5D78rwDEFe6"
chain33Validator3="13zBdQwuyDh7cKN79oT2odkxYuDbgQiXFv"
chain33Validator4="113ZzVamKfAtGt9dq45fX1mNsEoDiN95HG"
chain33ValidatorKey1="0xd627968e445f2a41c92173225791bae1ba42126ae96c32f28f97ff8f226e5c68"
chain33ValidatorKey2="0x9d539bc5fd084eb7fe86ad631dba9aa086dba38418725c38d9751459f567da66"
chain33ValidatorKey3="0x0a6671f101e30a2cc2d79d77436b62cdf2664ed33eb631a9c9e3f3dd348a23be"
chain33ValidatorKey4="0x3818b257b05ee75b6e43ee0e3cfc2d8502342cf67caed533e3756966690b62a5"
ethReceiverAddr1="0xa4ea64a583f6e51c3799335b28a8f0529570a635"
ethReceiverAddrKey1="355b876d7cbcb930d5dfab767f66336ce327e082cbaa1877210c1bae89b1df71"
ethReceiverAddr2="0x0c05ba5c230fdaa503b53702af1962e08d0c60bf"
ethReceiverAddrKey2="9dc6df3a8ab139a54d8a984f54958ae0661f880229bf3bdbb886b87d58b56a08"
maturityDegree=10
tokenAddrBty=""
function kill_ebrelayerC() {
kill_ebrelayer "./C/ebrelayer"
}
function kill_ebrelayerD() {
kill_ebrelayer "./D/ebrelayer"
}
function start_ebrelayerC() {
start_ebrelayer "./C/ebrelayer" "./C/ebrelayer.log"
${CLIC} relayer unlock -p 123456hzj
sleep 5
eth_block_wait 1 https://ropsten-rpc.linkpool.io/
sleep 1
}
function start_ebrelayerD() {
start_ebrelayer "./D/ebrelayer" "./D/ebrelayer.log"
${CLID} relayer unlock -p 123456hzj
sleep 5
eth_block_wait 1 https://ropsten-rpc.linkpool.io/
sleep 1
}
function InitAndDeploy() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
result=$(${CLIA} relayer set_pwd -n 123456hzj -o kk)
cli_ret "${result}" "set_pwd"
result=$(${CLIA} relayer unlock -p 123456hzj)
cli_ret "${result}" "unlock"
result=$(${CLIA} relayer ethereum deploy)
cli_ret "${result}" "deploy"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function StartRelayerAndDeploy() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
for name in A B C D; do
local ebrelayer="./$name/ebrelayer"
kill_ebrelayer "${ebrelayer}"
done
sleep 1
rm -rf './A' './B' './C' './D' './datadir' './ebrelayer.log' './logs'
mkdir './A' './B' './C' './D'
cp './relayer.toml' './A/relayer.toml'
cp './ebrelayer' './A/ebrelayer'
#start_trufflesuite
#start_ebrelayer "./A/ebrelayer" "./A/ebrelayer.log"
# 部署合约
#InitAndDeploy
# 获取 BridgeRegistry 地址
#result=$(${CLIA} relayer ethereum bridgeRegistry)
#BridgeRegistry=$(cli_ret "${result}" "bridgeRegistry" ".addr")
BridgeRegistry="0x212ae3c705DA7E3568a85595E8e16268FE7F6448"
#kill_ebrelayer "./A/ebrelayer"
# 修改 relayer.toml 配置文件
updata_relayer_toml_ropston ${BridgeRegistry} ${maturityDegree} "./A/relayer.toml"
updata_all_relayer_toml2
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
# chian33 添加验证着及权重
function InitChain33Vilators() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
# 导入 chain33Validators 私钥生成地址
result=$(${Chain33Cli} account import_key -k ${chain33ValidatorKey1} -l validator1)
check_addr "${result}" ${chain33Validator1}
result=$(${Chain33Cli} account import_key -k ${chain33ValidatorKey2} -l validator2)
check_addr "${result}" ${chain33Validator2}
result=$(${Chain33Cli} account import_key -k ${chain33ValidatorKey3} -l validator3)
check_addr "${result}" ${chain33Validator3}
result=$(${Chain33Cli} account import_key -k ${chain33ValidatorKey4} -l validator4)
check_addr "${result}" ${chain33Validator4}
# SetConsensusThreshold
hash=$(${Chain33Cli} send x2ethereum setconsensus -p 80 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
# add a validator
hash=$(${Chain33Cli} send x2ethereum add -a ${chain33Validator1} -p 25 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
hash=$(${Chain33Cli} send x2ethereum add -a ${chain33Validator2} -p 25 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
hash=$(${Chain33Cli} send x2ethereum add -a ${chain33Validator3} -p 25 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
hash=$(${Chain33Cli} send x2ethereum add -a ${chain33Validator4} -p 25 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
# query Validators
totalPower=$(${Chain33Cli} send x2ethereum query totalpower -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv | jq .totalPower | sed 's/\"//g')
check_number 100 ${totalPower}
# cions 转帐到 x2ethereum 合约地址
hash=$(${Chain33Cli} send coins send_exec -e x2ethereum -a 200 -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum)
balance_ret "${result}" "200.0000"
# chain33Validator 要有手续费
hash=$(${Chain33Cli} send coins transfer -a 10 -t "${chain33Validator1}" -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} account balance -a "${chain33Validator1}" -e coins)
balance_ret "${result}" "10.0000"
hash=$(${Chain33Cli} send coins transfer -a 10 -t "${chain33Validator2}" -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} account balance -a "${chain33Validator2}" -e coins)
balance_ret "${result}" "10.0000"
hash=$(${Chain33Cli} send coins transfer -a 10 -t "${chain33Validator3}" -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} account balance -a "${chain33Validator3}" -e coins)
balance_ret "${result}" "10.0000"
hash=$(${Chain33Cli} send coins transfer -a 10 -t "${chain33Validator4}" -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} account balance -a "${chain33Validator4}" -e coins)
balance_ret "${result}" "10.0000"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function StartAllEbrelayer() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
# 重启 ebrelayer 并解锁
for name in A B C D; do
start_ebrelayer "./"$name"/ebrelayer" "./"$name"/ebrelayer.log"
# 导入测试地址私钥
CLI="./ebcli_$name"
result=$(${CLI} relayer set_pwd -n 123456hzj -o kk)
result=$(${CLI} relayer unlock -p 123456hzj)
cli_ret "${result}" "unlock"
done
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function EthImportKey() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
result=$(${CLIA} relayer ethereum import_chain33privatekey -k "${chain33ValidatorKey1}")
cli_ret "${result}" "import_chain33privatekey"
result=$(${CLIB} relayer ethereum import_chain33privatekey -k "${chain33ValidatorKey2}")
cli_ret "${result}" "import_chain33privatekey"
result=$(${CLIC} relayer ethereum import_chain33privatekey -k "${chain33ValidatorKey3}")
cli_ret "${result}" "import_chain33privatekey"
result=$(${CLID} relayer ethereum import_chain33privatekey -k "${chain33ValidatorKey4}")
cli_ret "${result}" "import_chain33privatekey"
result=$(${CLIA} relayer ethereum import_ethprivatekey -k "${ethValidatorAddrKeyA}")
cli_ret "${result}" "import_ethprivatekey"
result=$(${CLIB} relayer ethereum import_ethprivatekey -k "${ethValidatorAddrKeyB}")
cli_ret "${result}" "import_ethprivatekeyB"
result=$(${CLIC} relayer ethereum import_ethprivatekey -k "${ethValidatorAddrKeyC}")
cli_ret "${result}" "import_ethprivatekeyC"
result=$(${CLID} relayer ethereum import_ethprivatekey -k "${ethValidatorAddrKeyD}")
cli_ret "${result}" "import_ethprivatekeyD"
result=$(${CLIA} relayer chain33 import_privatekey -k "${ethValidatorAddrKeyA}")
cli_ret "${result}" "A relayer chain33 import_privatekey"
result=$(${CLIB} relayer chain33 import_privatekey -k "${ethValidatorAddrKeyB}")
cli_ret "${result}" "B relayer chain33 import_privatekey"
result=$(${CLIC} relayer chain33 import_privatekey -k "${ethValidatorAddrKeyC}")
cli_ret "${result}" "C relayer chain33 import_privatekey"
result=$(${CLID} relayer chain33 import_privatekey -k "${ethValidatorAddrKeyD}")
cli_ret "${result}" "D relayer chain33 import_privatekey"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function TestChain33ToEthAssets() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
# token4chain33 在 以太坊 上先有 bty
result=$(${CLIA} relayer ethereum token4chain33 -s bty)
tokenAddrBty=$(cli_ret "${result}" "token4chain33" ".addr")
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr1}" -t "${tokenAddrBty}")
cli_ret "${result}" "balance" ".balance" "0"
# chain33 lock bty
hash=$(${Chain33Cli} send x2ethereum lock -a 5 -t bty -r ${ethReceiverAddr1} -q ${tokenAddrBty} -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
block_wait "${Chain33Cli}" $((maturityDegree + 2))
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum)
balance_ret "${result}" "195.0000"
eth_block_wait $((maturityDegree + 2)) https://ropsten-rpc.linkpool.io/
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr1}" -t "${tokenAddrBty}")
cli_ret "${result}" "balance" ".balance" "5"
# eth burn
result=$(${CLIA} relayer ethereum burn -m 5 -k "${ethReceiverAddrKey1}" -r "${chain33SenderAddr}" -t "${tokenAddrBty}")
cli_ret "${result}" "burn"
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr1}" -t "${tokenAddrBty}")
cli_ret "${result}" "balance" ".balance" "0"
# eth 等待 10 个区块
eth_block_wait $((maturityDegree + 2)) https://ropsten-rpc.linkpool.io/
result=$(${Chain33Cli} account balance -a "${chain33SenderAddr}" -e x2ethereum)
balance_ret "${result}" "5"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
# eth to chain33
# 在以太坊上锁定资产,然后在 chain33 上铸币,针对 eth 资产
function TestETH2Chain33Assets() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
${CLIA} relayer unlock -p 123456hzj
result=$(${CLIA} relayer ethereum bridgeBankAddr)
bridgeBankAddr=$(cli_ret "${result}" "bridgeBankAddr" ".addr")
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}")
cli_ret "${result}" "balance" ".balance" "0"
# eth lock 0.1
result=$(${CLIA} relayer ethereum lock -m 0.1 -k "${ethReceiverAddrKey1}" -r 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
cli_ret "${result}" "lock"
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}")
cli_ret "${result}" "balance" ".balance" "0.1"
# eth 等待 10 个区块
eth_block_wait $((maturityDegree + 2)) https://ropsten-rpc.linkpool.io/
result=$(${Chain33Cli} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]")
balance_ret "${result}" "0.1"
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr2}")
balance=$(cli_ret "${result}" "balance" ".balance")
hash=$(${Chain33Cli} send x2ethereum burn -a 0.01 -t eth -r ${ethReceiverAddr2} -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
block_wait "${Chain33Cli}" $((maturityDegree + 2))
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]")
balance_ret "${result}" "0"
eth_block_wait 2 https://ropsten-rpc.linkpool.io/
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}")
cli_ret "${result}" "balance" ".balance" "0"
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr2}")
cli_ret "${result}" "balance" ".balance" $(echo "${balance}+0.1" | bc)
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function TestETH2Chain33Erc20() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
${CLIA} relayer unlock -p 123456hzj
# token4erc20 在 chain33 上先有 token,同时 mint
tokenSymbol="testc"
# result=$(${CLIA} relayer ethereum token4erc20 -s "${tokenSymbol}")
# tokenAddr=$(cli_ret "${result}" "token4erc20" ".addr")
tokenAddr="0x47F62ba65bCa4150BE98F31566DC559b9b04fc2D"
# 先铸币 1000
result=$(${CLIA} relayer ethereum mint -m 1000 -o "${ethReceiverAddr1}" -t "${tokenAddr}")
cli_ret "${result}" "mint"
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr1}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "1000"
result=$(${CLIA} relayer ethereum bridgeBankAddr)
bridgeBankAddr=$(cli_ret "${result}" "bridgeBankAddr" ".addr")
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "0"
# lock 100
result=$(${CLIA} relayer ethereum lock -m 100 -k "${ethReceiverAddrKey1}" -r "${chain33Validator1}" -t "${tokenAddr}")
cli_ret "${result}" "lock"
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr1}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "900"
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "100"
# eth 等待 10 个区块
eth_block_wait $((maturityDegree + 2)) https://ropsten-rpc.linkpool.io/
result=$(${Chain33Cli} x2ethereum balance -s "${chain33Validator1}" -t "${tokenSymbol}" -a "${tokenAddr}" | jq ".res" | jq ".[]")
balance_ret "${result}" "100"
# chain33 burn 100
hash=$(${Chain33Cli} send x2ethereum burn -a 100 -t "${tokenSymbol}" -r ${ethReceiverAddr2} -q ${tokenAddr} -k "${chain33Validator1}")
block_wait "${Chain33Cli}" $((maturityDegree + 2))
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} x2ethereum balance -s "${chain33Validator1}" -t "${tokenSymbol}" -a "${tokenAddr}" | jq ".res" | jq ".[]")
balance_ret "${result}" "0"
eth_block_wait 2 https://ropsten-rpc.linkpool.io/
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr2}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "100"
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "0"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function TestChain33ToEthAssetsKill() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
if [ "${tokenAddrBty}" == "" ]; then
# token4chain33 在 以太坊 上先有 bty
result=$(${CLIA} relayer ethereum token4chain33 -s bty)
tokenAddrBty=$(cli_ret "${result}" "token4chain33" ".addr")
fi
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr1}" -t "${tokenAddrBty}")
cli_ret "${result}" "balance" ".balance" "0"
kill_ebrelayerC
kill_ebrelayerD
# chain33 lock bty
hash=$(${Chain33Cli} send x2ethereum lock -a 5 -t bty -r ${ethReceiverAddr2} -q ${tokenAddrBty} -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
block_wait "${Chain33Cli}" $((maturityDegree + 2))
check_tx "${Chain33Cli}" "${hash}"
eth_block_wait $((maturityDegree + 2)) https://ropsten-rpc.linkpool.io/
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr2}" -t "${tokenAddrBty}")
cli_ret "${result}" "balance" ".balance" "0"
start_ebrelayerC
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr2}" -t "${tokenAddrBty}")
cli_ret "${result}" "balance" ".balance" "5"
# eth burn
result=$(${CLIA} relayer ethereum burn -m 5 -k "${ethReceiverAddrKey2}" -r "${chain33Validator1}" -t "${tokenAddrBty}")
cli_ret "${result}" "burn"
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr2}" -t "${tokenAddrBty}")
cli_ret "${result}" "balance" ".balance" "0"
# eth 等待 10 个区块
eth_block_wait $((maturityDegree + 2)) https://ropsten-rpc.linkpool.io/
result=$(${Chain33Cli} account balance -a "${chain33Validator1}" -e x2ethereum)
balance_ret "${result}" "0"
start_ebrelayerD
result=$(${Chain33Cli} account balance -a "${chain33Validator1}" -e x2ethereum)
balance_ret "${result}" "5"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
# eth to chain33
# 在以太坊上锁定资产,然后在 chain33 上铸币,针对 eth 资产
function TestETH2Chain33AssetsKill() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
${CLIA} relayer unlock -p 123456hzj
result=$(${CLIA} relayer ethereum bridgeBankAddr)
bridgeBankAddr=$(cli_ret "${result}" "bridgeBankAddr" ".addr")
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}")
cli_ret "${result}" "balance" ".balance" "0"
kill_ebrelayerC
kill_ebrelayerD
# eth lock 0.1
result=$(${CLIA} relayer ethereum lock -m 0.1 -k "${ethReceiverAddrKey1}" -r 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
cli_ret "${result}" "lock"
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}")
cli_ret "${result}" "balance" ".balance" "0.1"
# eth 等待 10 个区块
eth_block_wait $((maturityDegree + 2)) https://ropsten-rpc.linkpool.io/
result=$(${Chain33Cli} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]")
balance_ret "${result}" "0"
start_ebrelayerC
start_ebrelayerD
result=$(${Chain33Cli} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]")
balance_ret "${result}" "0.1"
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr2}")
balance=$(cli_ret "${result}" "balance" ".balance")
kill_ebrelayerC
kill_ebrelayerD
hash=$(${Chain33Cli} send x2ethereum burn -a 0.1 -t eth -r ${ethReceiverAddr2} -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
block_wait "${Chain33Cli}" $((maturityDegree + 2))
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]")
balance_ret "${result}" "0"
eth_block_wait 2 https://ropsten-rpc.linkpool.io/
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}")
cli_ret "${result}" "balance" ".balance" "0.1"
start_ebrelayerC
start_ebrelayerD
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr2}")
cli_ret "${result}" "balance" ".balance" $(echo "${balance}+0.1" | bc)
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function TestETH2Chain33Erc20Kill() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
${CLIA} relayer unlock -p 123456hzj
# token4erc20 在 chain33 上先有 token,同时 mint
tokenSymbol="testcc"
result=$(${CLIA} relayer ethereum token4erc20 -s "${tokenSymbol}")
tokenAddr=$(cli_ret "${result}" "token4erc20" ".addr")
# 先铸币 1000
result=$(${CLIA} relayer ethereum mint -m 1000 -o "${ethReceiverAddr1}" -t "${tokenAddr}")
cli_ret "${result}" "mint"
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr1}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "1000"
result=$(${CLIA} relayer ethereum bridgeBankAddr)
bridgeBankAddr=$(cli_ret "${result}" "bridgeBankAddr" ".addr")
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "0"
kill_ebrelayerC
kill_ebrelayerD
# lock 100
result=$(${CLIA} relayer ethereum lock -m 100 -k "${ethReceiverAddrKey1}" -r "${chain33Validator1}" -t "${tokenAddr}")
cli_ret "${result}" "lock"
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr1}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "900"
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "100"
# eth 等待 10 个区块
eth_block_wait $((maturityDegree + 2)) https://ropsten-rpc.linkpool.io/
result=$(${Chain33Cli} x2ethereum balance -s "${chain33Validator1}" -t "${tokenSymbol}" -a "${tokenAddr}" | jq ".res" | jq ".[]")
balance_ret "${result}" "0"
start_ebrelayerC
start_ebrelayerD
result=$(${Chain33Cli} x2ethereum balance -s "${chain33Validator1}" -t "${tokenSymbol}" -a "${tokenAddr}" | jq ".res" | jq ".[]")
balance_ret "${result}" "100"
kill_ebrelayerC
kill_ebrelayerD
# chain33 burn 100
hash=$(${Chain33Cli} send x2ethereum burn -a 100 -t "${tokenSymbol}" -r ${ethReceiverAddr2} -q ${tokenAddr} -k "${chain33Validator1}")
block_wait "${Chain33Cli}" $((maturityDegree + 2))
check_tx "${Chain33Cli}" "${hash}"
result=$(${Chain33Cli} x2ethereum balance -s "${chain33Validator1}" -t "${tokenSymbol}" -a "${tokenAddr}" | jq ".res" | jq ".[]")
balance_ret "${result}" "0"
eth_block_wait 2 https://ropsten-rpc.linkpool.io/
start_ebrelayerC
result=$(${CLIA} relayer ethereum balance -o "${ethReceiverAddr2}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "100"
result=$(${CLIA} relayer ethereum balance -o "${bridgeBankAddr}" -t "${tokenAddr}")
cli_ret "${result}" "balance" ".balance" "0"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function AllRelayerMainTest() {
set +e
# docker cp ${GOPATH}/src/github.com/33cn/plugin/build/ci/x2Ethereum build_chain33_1:/root/x2Ethereum
Chain33Cli="./../chain33-cli"
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
if [[ ${1} != "" ]]; then
maturityDegree=${1}
echo -e "${GRE}maturityDegree is ${maturityDegree} ${NOC}"
fi
# init
#StartRelayerAndDeploy
#InitChain33Vilators
StartAllEbrelayer
EthImportKey
# test
# TestChain33ToEthAssets
TestETH2Chain33Assets
TestETH2Chain33Erc20
#
# # kill relayer and start relayer
# TestChain33ToEthAssetsKill
# TestETH2Chain33AssetsKill
# TestETH2Chain33Erc20Kill
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
AllRelayerMainTest 1
......@@ -42,6 +42,7 @@ ethReceiverAddr2="0x0c05ba5c230fdaa503b53702af1962e08d0c60bf"
ethReceiverAddrKey2="9dc6df3a8ab139a54d8a984f54958ae0661f880229bf3bdbb886b87d58b56a08"
maturityDegree=10
tokenAddrBty=""
tokenAddr=""
function kill_ebrelayerC() {
kill_ebrelayer "./C/ebrelayer"
......
......@@ -2,13 +2,12 @@
set -x
source "./publicTest.sh"
source "./allRelayerTest.sh"
CLIA="./ebcli_A"
Chain33_CLI=""
Ethsender="0xa4ea64a583f6e51c3799335b28a8f0529570a635"
tokenAddr="0x9C3D40A44a2F61Ef8D46fa8C7A731C08FB16cCEF"
testcAddr="0xb43393f9f588fC18Bbd8E99716c25291dB804b41"
ethSender0PrivateKey="3fa21584ae2e4fd74db9b58e2386f5481607dfa4d7ba0617aaa7858e5025dc1e"
......@@ -40,7 +39,7 @@ loop_send_lock_eth() {
#while 遍历数组
# ======================== Ethereum Lock =========================================
echo -e "${GRE}=========== Ethereum Lock begin ===========${NOC}"
preChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]" | jq ".balance")
preChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]" | jq ".balance" | sed 's/\"//g')
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
......@@ -55,9 +54,7 @@ loop_send_lock_eth() {
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
nowEthBalance=$(curl -ksd '{"jsonrpc":"2.0","method":"eth_getBalance","params":["'${ethAddress[i]}'", "latest"],"id":1}' http://localhost:7545 | jq -r ".result")
res=$(gawk -M 'BEGIN{printf "%d\n", \
'${preEthBalance[i]}' - \
'${nowEthBalance}'}')
res=$((preEthBalance[i] - nowEthBalance))
echo ${i} "preBalance" ${preEthBalance[i]} "nowBalance" ${nowEthBalance} "diff" ${res}
if [[ $res -le 100000000000000000 ]]; then
echo -e "${RED}error number, expect greater than 100000000000000000, get ${res}${NOC}"
......@@ -66,10 +63,8 @@ loop_send_lock_eth() {
let i++
done
nowChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]" | jq ".balance")
diff=$(gawk -M 'BEGIN{printf "%d\n", \
'${nowChain33Balance}' - \
'${preChain33Balance}'}')
nowChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]" | jq ".balance" | sed 's/\"//g')
diff=$((nowChain33Balance - preChain33Balance))
check_number "${diff}" 1
}
......@@ -77,7 +72,7 @@ loop_send_burn_eth() {
# =========================== Chain33 Burn ========================================
echo -e "${GRE}=========== Chain33 Burn begin ===========${NOC}"
preChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]" | jq ".balance")
preChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]" | jq ".balance" | sed 's/\"//g')
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
......@@ -92,9 +87,7 @@ loop_send_burn_eth() {
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
nowEthBalance=$(curl -ksd '{"jsonrpc":"2.0","method":"eth_getBalance","params":["'${ethAddress[i]}'", "latest"],"id":1}' http://localhost:7545 | jq -r ".result")
res=$(gawk -M 'BEGIN{printf "%d\n", \
'${nowEthBalance}' - \
'${preEthBalance[i]}'}')
res=$((nowEthBalance - preEthBalance[i]))
echo ${i} "preBalance" ${preEthBalance[i]} "nowBalance" ${nowEthBalance} "diff" ${res}
if [[ $res -gt 100000000000000000 ]]; then
echo -e "${RED}error number, expect greater than 100000000000000000, get ${res}${NOC}"
......@@ -102,10 +95,8 @@ loop_send_burn_eth() {
fi
let i++
done
nowChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]" | jq ".balance")
diff=$(gawk -M 'BEGIN{printf "%d\n", \
'${preChain33Balance}' - \
'${nowChain33Balance}'}')
nowChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t eth | jq ".res" | jq ".[]" | jq ".balance" | sed 's/\"//g')
diff=$((preChain33Balance - nowChain33Balance))
check_number "${diff}" 1
}
......@@ -115,12 +106,12 @@ loop_send_lock_bty() {
# =========================== Chain33 Lock =========================================
echo -e "${GRE}=========== Chain33 Lock begin ===========${NOC}"
preChain33Balance=$(${Chain33_CLI} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum | jq -r ".balance")
preChain33Balance=$(${Chain33_CLI} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum | jq -r ".balance" | sed 's/\"//g')
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
preEthBalance[$i]=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddr}" | jq -r ".balance")
ethTxHash=$(${Chain33_CLI} send x2ethereum lock -q "${tokenAddr}" -a 1 -r ${ethAddress[i]} -t bty -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
preEthBalance[$i]=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddrBty}" | jq -r ".balance")
ethTxHash=$(${Chain33_CLI} send x2ethereum lock -q "${tokenAddrBty}" -a 1 -r ${ethAddress[i]} -t bty -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
echo ${i} "lock chain33 tx hash:" ${ethTxHash}
let i++
done
......@@ -129,18 +120,14 @@ loop_send_lock_bty() {
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
nowEthBalance=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddr}" | jq -r ".balance")
res=$(gawk -M 'BEGIN{printf "%d\n", \
'${nowEthBalance}' - \
'${preEthBalance[i]}'}')
nowEthBalance=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddrBty}" | jq -r ".balance")
res=$((nowEthBalance - preEthBalance[i]))
echo ${i} "preBalance" ${preEthBalance[i]} "nowBalance" ${nowEthBalance} "diff" ${res}
check_number "${res}" 1
let i++
done
nowChain33Balance=$(${Chain33_CLI} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum | jq -r ".balance")
diff=$(gawk -M 'BEGIN{printf "%d\n", \
'${preChain33Balance}' - \
'${nowChain33Balance}'}')
nowChain33Balance=$(${Chain33_CLI} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum | jq -r ".balance" | sed 's/\"//g')
diff=$((preChain33Balance - nowChain33Balance))
check_number "${diff}" 10
}
......@@ -150,13 +137,13 @@ loop_send_burn_bty() {
# =========================== Ethereum Burn ========================================
echo -e "${GRE}=========== Ethereum Burn begin ===========${NOC}"
preChain33Balance=$(${Chain33_CLI} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum | jq -r ".balance")
preChain33Balance=$(${Chain33_CLI} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum | jq -r ".balance" | sed 's/\"//g')
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
preEthBalance[$i]=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddr}" | jq -r ".balance")
approveTxHash=$(${CLIA} relayer ethereum approve -m 1 -k "${privateKeys[i]}" -t "${tokenAddr}")
ethTxHash=$(${CLIA} relayer ethereum burn-async -m 1 -k "${privateKeys[i]}" -r 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t "${tokenAddr}")
preEthBalance[$i]=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddrBty}" | jq -r ".balance")
approveTxHash=$(${CLIA} relayer ethereum approve -m 1 -k "${privateKeys[i]}" -t "${tokenAddrBty}")
ethTxHash=$(${CLIA} relayer ethereum burn-async -m 1 -k "${privateKeys[i]}" -r 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t "${tokenAddrBty}")
echo ${i} "burn-async tx hash:" ${ethTxHash}
let i++
done
......@@ -165,18 +152,14 @@ loop_send_burn_bty() {
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
nowEthBalance=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddr}" | jq -r ".balance")
res=$(gawk -M 'BEGIN{printf "%d\n", \
'${preEthBalance[i]}' - \
'${nowEthBalance}'}')
nowEthBalance=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddrBty}" | jq -r ".balance")
res=$((preEthBalance[i] - nowEthBalance))
echo ${i} "preBalance" ${preEthBalance[i]} "nowBalance" ${nowEthBalance} "diff" ${res}
check_number "${res}" 1
let i++
done
nowChain33Balance=$(${Chain33_CLI} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum | jq -r ".balance")
diff=$(gawk -M 'BEGIN{printf "%d\n", \
'${nowChain33Balance}' - \
'${preChain33Balance}'}')
nowChain33Balance=$(${Chain33_CLI} account balance -a 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -e x2ethereum | jq -r ".balance" | sed 's/\"//g')
diff=$((nowChain33Balance - preChain33Balance))
check_number "${diff}" 10
}
......@@ -185,33 +168,29 @@ loop_send_lock_erc20() {
# ======================== Ethereum Lock Erc20 =========================================
echo -e "${GRE}=========== Ethereum Lock Erc20 begin ===========${NOC}"
preChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t testc | jq ".res" | jq ".[]" | jq ".balance")
preChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t testc | jq ".res" | jq ".[]" | jq ".balance" | sed 's/\"//g')
i=0
preEthBalance=$(${CLIA} relayer ethereum balance -o "${Ethsender}" -t "${testcAddr}" | jq -r ".balance")
preEthBalance=$(${CLIA} relayer ethereum balance -o "${Ethsender}" -t "${tokenAddr}" | jq -r ".balance")
approveTxHash=$(${CLIA} relayer ethereum approve -m 10 -k "${privateKeys[8]}" -t "${testcAddr}")
approveTxHash=$(${CLIA} relayer ethereum approve -m 10 -k "${privateKeys[8]}" -t "${tokenAddr}")
echo ${i} "lock-async erc20 approve tx hash:" ${approveTxHash}
while [[ i -lt ${#privateKeys[@]} ]]; do
ethTxHash=$(${CLIA} relayer ethereum lock-async -m 1 -k "${privateKeys[8]}" -r 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t "${testcAddr}")
ethTxHash=$(${CLIA} relayer ethereum lock-async -m 1 -k "${privateKeys[8]}" -r 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t "${tokenAddr}")
echo ${i} "lock-async erc20 tx hash:" ${ethTxHash}
let i++
done
eth_block_wait $((maturityDegree + 2))
nowEthBalance=$(${CLIA} relayer ethereum balance -o "${Ethsender}" -t "${testcAddr}" | jq -r ".balance")
res=$(gawk -M 'BEGIN{printf "%d\n", \
'${preEthBalance}' - \
'${nowEthBalance}'}')
nowEthBalance=$(${CLIA} relayer ethereum balance -o "${Ethsender}" -t "${tokenAddr}" | jq -r ".balance")
res=$((preEthBalance - nowEthBalance))
echo ${i} "preBalance" ${preEthBalance} "nowBalance" ${nowEthBalance} "diff" ${res}
check_number "${diff}" 10
nowChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t testc | jq ".res" | jq ".[]" | jq ".balance")
diff=$(gawk -M 'BEGIN{printf "%d\n", \
'${nowChain33Balance}' - \
'${preChain33Balance}'}')
nowChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t testc | jq ".res" | jq ".[]" | jq ".balance" | sed 's/\"//g')
diff=$((nowChain33Balance - preChain33Balance))
check_number "${diff}" 10
}
......@@ -221,12 +200,12 @@ loop_send_burn_erc20() {
# =========================== Chain33 Burn Erc20 ========================================
echo -e "${GRE}=========== Chain33 Burn Erc20 begin ===========${NOC}"
preChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t testc | jq ".res" | jq ".[]" | jq ".balance")
preChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t testc | jq ".res" | jq ".[]" | jq ".balance" | sed 's/\"//g')
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
preEthBalance[i]=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${testcAddr}" | jq -r ".balance")
ethTxHash=$(${Chain33_CLI} send x2ethereum burn -a 1 -r ${ethAddress[i]} -t testc -q "${testcAddr}" -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
preEthBalance[i]=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddr}" | jq -r ".balance")
ethTxHash=$(${Chain33_CLI} send x2ethereum burn -a 1 -r ${ethAddress[i]} -t testc -q "${tokenAddr}" -k 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv)
echo ${i} "burn chain33 tx hash:" ${ethTxHash}
let i++
done
......@@ -235,19 +214,15 @@ loop_send_burn_erc20() {
i=0
while [[ i -lt ${#privateKeys[@]} ]]; do
nowEthBalance=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${testcAddr}" | jq -r ".balance")
res=$(gawk -M 'BEGIN{printf "%d\n", \
'${nowEthBalance}' - \
'${preEthBalance[i]}'}')
nowEthBalance=$(${CLIA} relayer ethereum balance -o "${ethAddress[i]}" -t "${tokenAddr}" | jq -r ".balance")
res=$((nowEthBalance - preEthBalance[i]))
echo ${i} "preBalance" ${preEthBalance[i]} "nowBalance" ${nowEthBalance} "diff" ${res}
check_number "${res}" 1
let i++
done
nowChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t testc | jq ".res" | jq ".[]" | jq ".balance")
diff=$(gawk -M 'BEGIN{printf "%d\n", \
'${preChain33Balance}' - \
'${nowChain33Balance}'}')
nowChain33Balance=$(${Chain33_CLI} x2ethereum balance -s 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -t testc | jq ".res" | jq ".[]" | jq ".balance" | sed 's/\"//g')
diff=$((preChain33Balance - nowChain33Balance))
check_number "${diff}" 10
}
......
......@@ -94,9 +94,6 @@ func addEth2Chain33Flags(cmd *cobra.Command) {
cmd.Flags().Int64("claimtype", 0, "the type of this claim,lock=1,burn=2")
_ = cmd.MarkFlagRequired("claimtype")
cmd.Flags().Int64("decimal", 0, "the decimal of this token")
_ = cmd.MarkFlagRequired("decimal")
}
func Eth2Chain33(cmd *cobra.Command, args []string) {
......@@ -111,7 +108,13 @@ func Eth2Chain33(cmd *cobra.Command, args []string) {
validator, _ := cmd.Flags().GetString("validator")
amount, _ := cmd.Flags().GetFloat64("amount")
claimtype, _ := cmd.Flags().GetInt64("claimtype")
decimal, _ := cmd.Flags().GetInt64("decimal")
nodeAddr, _ := cmd.Flags().GetString("node_addr")
decimal, err := utils.GetDecimalsFromNode(tcontract, nodeAddr)
if err != nil {
fmt.Println("get decimal error")
return
}
params := &types3.Eth2Chain33{
EthereumChainID: ethid,
......@@ -123,7 +126,7 @@ func Eth2Chain33(cmd *cobra.Command, args []string) {
EthereumSender: sender,
Chain33Receiver: receiver,
ValidatorAddress: validator,
Amount: strconv.FormatFloat(types3.MultiplySpecifyTimes(amount, decimal), 'f', 4, 64),
Amount: strconv.FormatFloat(amount*1e8, 'f', 4, 64),
ClaimType: claimtype,
Decimals: decimal,
}
......@@ -157,7 +160,13 @@ func WithdrawEth(cmd *cobra.Command, args []string) {
validator, _ := cmd.Flags().GetString("validator")
amount, _ := cmd.Flags().GetFloat64("amount")
claimtype, _ := cmd.Flags().GetInt64("claimtype")
decimal, _ := cmd.Flags().GetInt64("decimal")
nodeAddr, _ := cmd.Flags().GetString("node_addr")
decimal, err := utils.GetDecimalsFromNode(tcontract, nodeAddr)
if err != nil {
fmt.Println("get decimal error")
return
}
params := &types3.Eth2Chain33{
EthereumChainID: ethid,
......@@ -226,7 +235,7 @@ func burn(cmd *cobra.Command, args []string) {
params := &types3.Chain33ToEth{
TokenContract: contract,
EthereumReceiver: receiver,
Amount: types3.TrimZeroAndDot(strconv.FormatFloat(types3.MultiplySpecifyTimes(amount, decimal), 'f', 4, 64)),
Amount: types3.TrimZeroAndDot(strconv.FormatFloat(amount*1e8, 'f', 4, 64)),
LocalCoinSymbol: csymbol,
Decimals: decimal,
}
......@@ -319,7 +328,7 @@ func CreateRawAddValidatorTxCmd() *cobra.Command {
}
addValidatorFlags(cmd)
cmd.Flags().Int64P("power", "p", 0, "validator power set")
cmd.Flags().Int64P("power", "p", 0, "validator power set,must be 1-100")
_ = cmd.MarkFlagRequired("power")
return cmd
}
......@@ -377,7 +386,7 @@ func CreateRawModifyValidatorTxCmd() *cobra.Command {
addValidatorFlags(cmd)
cmd.Flags().Int64P("power", "p", 0, "validator power set")
cmd.Flags().Int64P("power", "p", 0, "validator power set,must be 1-100")
_ = cmd.MarkFlagRequired("power")
return cmd
}
......@@ -409,7 +418,7 @@ func CreateRawSetConsensusTxCmd() *cobra.Command {
}
func addSetConsensusFlags(cmd *cobra.Command) {
cmd.Flags().Int64P("power", "p", 0, "the power you want to set consensus need")
cmd.Flags().Int64P("power", "p", 0, "the power you want to set consensus need,must be 1-100")
_ = cmd.MarkFlagRequired("power")
}
......
......@@ -122,7 +122,7 @@ func queryConsensus(cmd *cobra.Command, args []string) {
FuncName: types2.FuncQueryConsensusThreshold,
}
channel := &types2.ReceiptSetConsensusThreshold{}
channel := &types2.ReceiptQueryConsensusThreshold{}
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.Query", query, channel)
ctx.Run()
}
......
......@@ -13,9 +13,6 @@ import (
"github.com/spf13/cobra"
)
// todo
// 所有amount要做bigint处理,还要做只保留四位的截断处理
// EthereumRelayerCmd command func
func EthereumRelayerCmd() *cobra.Command {
cmd := &cobra.Command{
......
......@@ -42,6 +42,12 @@ func LogLockToEthBridgeClaim(event *events.LockEvent, ethereumChainID int64, bri
witnessClaim.Symbol = event.Symbol
witnessClaim.EthereumSender = event.From.String()
witnessClaim.Chain33Receiver = string(recipient)
if decimal > 8 {
event.Value = event.Value.Quo(event.Value, big.NewInt(int64(types.MultiplySpecifyTimes(1, decimal-8))))
} else {
event.Value = event.Value.Mul(event.Value, big.NewInt(int64(types.MultiplySpecifyTimes(1, 8-decimal))))
}
witnessClaim.Amount = event.Value.String()
witnessClaim.ClaimType = types.LOCK_CLAIM_TYPE
......@@ -97,6 +103,11 @@ func ParseBurnLockTxReceipt(claimType events.Event, receipt *chain33Types.Receip
chain33ToEth.Amount = types.TrimZeroAndDot(chain33ToEth.Amount)
amount = big.NewInt(1)
amount, _ = amount.SetString(chain33ToEth.Amount, 10)
if chain33ToEth.Decimals > 8 {
amount = amount.Mul(amount, big.NewInt(int64(types.MultiplySpecifyTimes(1, chain33ToEth.Decimals-8))))
} else {
amount = amount.Quo(amount, big.NewInt(int64(types.MultiplySpecifyTimes(1, 8-chain33ToEth.Decimals))))
}
txslog.Info("ParseBurnLockTxReceipt", "chain33Sender", chain33Sender, "ethereumReceiver", ethereumReceiver.String(), "tokenContractAddress", tokenContractAddress.String(), "symbol", symbol, "amount", amount.String())
// Package the event data into a Chain33Msg
......
package common
import (
"fmt"
"reflect"
gethCommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
// EthereumAddress defines a standard ethereum address
type EthAddress gethCommon.Address
// NewEthereumAddress is a constructor function for EthereumAddress
func NewEthereumAddress(address string) EthAddress {
return EthAddress(gethCommon.HexToAddress(address))
}
// Route should return the name of the module
func (ethAddr EthAddress) String() string {
return gethCommon.Address(ethAddr).String()
}
// MarshalJSON marshals the etherum address to JSON
func (ethAddr EthAddress) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%v\"", ethAddr.String())), nil
}
// UnmarshalJSON unmarshals an ethereum address
func (ethAddr *EthAddress) UnmarshalJSON(input []byte) error {
return hexutil.UnmarshalFixedJSON(reflect.TypeOf(gethCommon.Address{}), input, ethAddr[:])
}
package common
import (
"fmt"
"math"
"math/big"
"testing"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
func TestAddToStringMap(t *testing.T) {
bn := big.NewInt(1)
ss := types.TrimZeroAndDot(fmt.Sprintf("%.0f", types.MultiplySpecifyTimes(math.Trunc(5*1e4), 14)))
bn, ok := bn.SetString(ss, 10)
fmt.Println(bn, ok)
}
package ethbridge
import (
"encoding/json"
"errors"
"fmt"
"strconv"
"github.com/golang/protobuf/proto"
log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
......@@ -15,22 +16,6 @@ var (
elog = log.New("module", "ethbridge")
)
func NewEthBridgeClaim(ethereumChainID int64, bridgeContract string, nonce int64, localCoinSymbol, localCoinExec string, tokenContact string, ethereumSender string, chain33Receiver string, validator string, amount string, claimType int64) types.Eth2Chain33 {
return types.Eth2Chain33{
EthereumChainID: ethereumChainID,
BridgeContractAddress: bridgeContract,
Nonce: nonce,
TokenContractAddress: tokenContact,
EthereumSender: ethereumSender,
Chain33Receiver: chain33Receiver,
ValidatorAddress: validator,
Amount: amount,
ClaimType: claimType,
LocalCoinSymbol: localCoinSymbol,
LocalCoinExec: localCoinExec,
}
}
func NewOracleClaimContent(chain33Receiver string, amount string, claimType, decimals int64) types.OracleClaimContent {
return types.OracleClaimContent{
Chain33Receiver: chain33Receiver,
......@@ -53,14 +38,14 @@ func CreateOracleClaimFromEthClaim(ethClaim types.Eth2Chain33) (types.OracleClai
if ethClaim.ClaimType != int64(types.LOCK_CLAIM_TYPE) && ethClaim.ClaimType != int64(types.BURN_CLAIM_TYPE) {
return types.OracleClaim{}, types.ErrInvalidClaimType
}
oracleID := strconv.Itoa(int(ethClaim.EthereumChainID)) + strconv.Itoa(int(ethClaim.Nonce)) + ethClaim.EthereumSender
oracleID := strconv.Itoa(int(ethClaim.EthereumChainID)) + strconv.Itoa(int(ethClaim.Nonce)) + ethClaim.EthereumSender + ethClaim.TokenContractAddress
if ethClaim.ClaimType == int64(types.LOCK_CLAIM_TYPE) {
oracleID = oracleID + "lock"
} else if ethClaim.ClaimType == int64(types.BURN_CLAIM_TYPE) {
oracleID = oracleID + "burn"
}
claimContent := NewOracleClaimContent(ethClaim.Chain33Receiver, ethClaim.Amount, ethClaim.ClaimType, ethClaim.Decimals)
claimBytes, err := json.Marshal(claimContent)
claimBytes, err := proto.Marshal(&claimContent)
if err != nil {
return types.OracleClaim{}, err
}
......@@ -69,34 +54,11 @@ func CreateOracleClaimFromEthClaim(ethClaim types.Eth2Chain33) (types.OracleClai
return claim, nil
}
// 通过oracleclaim反向构造ethchain33结构
func CreateEthClaimFromOracleString(ethereumChainID int64, bridgeContract string, nonce int64, localCoinSymbol, localCoinExec string, tokenContract string, ethereumAddress string, validator string, oracleClaimString string) (types.Eth2Chain33, error) {
oracleClaim, err := CreateOracleClaimFromOracleString(oracleClaimString)
if err != nil {
elog.Error("CreateEthClaimFromOracleString", "CreateOracleClaimFromOracleString error", err)
return types.Eth2Chain33{}, err
}
return NewEthBridgeClaim(
ethereumChainID,
bridgeContract,
nonce,
localCoinSymbol,
localCoinExec,
tokenContract,
ethereumAddress,
oracleClaim.Chain33Receiver,
validator,
oracleClaim.Amount,
oracleClaim.ClaimType,
), nil
}
func CreateOracleClaimFromOracleString(oracleClaimString string) (types.OracleClaimContent, error) {
var oracleClaimContent types.OracleClaimContent
bz := []byte(oracleClaimString)
if err := json.Unmarshal(bz, &oracleClaimContent); err != nil {
if err := proto.Unmarshal(bz, &oracleClaimContent); err != nil {
return types.OracleClaimContent{}, errors.New(fmt.Sprintf("failed to parse claim: %s", err.Error()))
}
......
package ethbridge
import (
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/executor/oracle"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
// OracleKeeper defines the expected oracle keeper
type OracleKeeper interface {
ProcessClaim(claim types.OracleClaim) (oracle.Status, error)
GetProphecy(id string) (oracle.Prophecy, error)
GetValidatorArray() ([]types.MsgValidator, error)
SetConsensusThreshold(ConsensusThreshold int64)
GetConsensusThreshold() int64
}
package ethbridge
import (
"encoding/json"
"strconv"
"github.com/golang/protobuf/proto"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common/address"
dbm "github.com/33cn/chain33/common/db"
......@@ -13,11 +14,11 @@ import (
)
type Keeper struct {
oracleKeeper OracleKeeper
oracleKeeper oracle.OracleKeeper
db dbm.KV
}
func NewKeeper(oracleKeeper OracleKeeper, db dbm.KV) Keeper {
func NewKeeper(oracleKeeper oracle.OracleKeeper, db dbm.KV) Keeper {
return Keeper{
oracleKeeper: oracleKeeper,
db: db,
......@@ -25,16 +26,16 @@ func NewKeeper(oracleKeeper OracleKeeper, db dbm.KV) Keeper {
}
// 处理接收到的ethchain33请求
func (k Keeper) ProcessClaim(claim types.Eth2Chain33) (oracle.Status, error) {
func (k Keeper) ProcessClaim(claim types.Eth2Chain33) (*types.ProphecyStatus, error) {
oracleClaim, err := CreateOracleClaimFromEthClaim(claim)
if err != nil {
elog.Error("CreateEthClaimFromOracleString", "CreateOracleClaimFromOracleString error", err)
return oracle.Status{}, err
return nil, err
}
status, err := k.oracleKeeper.ProcessClaim(oracleClaim)
if err != nil {
return oracle.Status{}, err
return nil, err
}
return status, nil
}
......@@ -52,14 +53,7 @@ func (k Keeper) ProcessSuccessfulClaimForLock(claim, execAddr, tokenSymbol, toke
if oracleClaim.ClaimType == int64(types.LOCK_CLAIM_TYPE) {
//铸币到相关的tokenSymbolBank账户下
d := oracleClaim.Decimals
var amount int64
if d > 8 {
amount = int64(types.Toeth(oracleClaim.Amount, d-8))
} else {
a, _ := strconv.ParseFloat(types.TrimZeroAndDot(oracleClaim.Amount), 64)
amount = int64(types.MultiplySpecifyTimes(a, 8-d))
}
amount, _ := strconv.ParseInt(types.TrimZeroAndDot(oracleClaim.Amount), 10, 64)
receipt, err = accDB.Mint(execAddr, amount)
if err != nil {
......@@ -103,12 +97,7 @@ func (k Keeper) ProcessSuccessfulClaimForBurn(claim, execAddr, tokenSymbol strin
// ProcessBurn processes the burn of bridged coins from the given sender
func (k Keeper) ProcessBurn(address, execAddr, amount, tokenAddress string, d int64, accDB *account.DB) (*types2.Receipt, error) {
var a int64
if d > 8 {
a = int64(types.Toeth(amount, d-8))
} else {
aa, _ := strconv.ParseFloat(types.TrimZeroAndDot(amount), 64)
a = int64(types.MultiplySpecifyTimes(aa, 8-d))
}
a, _ = strconv.ParseInt(types.TrimZeroAndDot(amount), 10, 64)
receipt, err := accDB.ExecWithdraw(execAddr, address, a)
if err != nil {
return nil, err
......@@ -135,7 +124,6 @@ func (k Keeper) ProcessLock(address, to, execAddr, amount string, accDB *account
return receipt, nil
}
//todo
// 对于相同的地址该如何处理?
// 现有方案是相同地址就报错
func (k Keeper) ProcessAddValidator(address string, power int64) (*types2.Receipt, error) {
......@@ -146,9 +134,13 @@ func (k Keeper) ProcessAddValidator(address string, power int64) (*types2.Receip
return nil, err
}
if validatorMaps == nil {
validatorMaps = new(types.ValidatorList)
}
elog.Info("ProcessLogInValidator", "pre validatorMaps", validatorMaps, "Add Address", address, "Add power", power)
var totalPower int64
for _, p := range validatorMaps {
for _, p := range validatorMaps.Validators {
if p.Address != address {
totalPower += p.Power
} else {
......@@ -156,18 +148,21 @@ func (k Keeper) ProcessAddValidator(address string, power int64) (*types2.Receip
}
}
validatorMaps = append(validatorMaps, types.MsgValidator{
vs := append(validatorMaps.Validators, &types.MsgValidator{
Address: address,
Power: power,
})
v, _ := json.Marshal(validatorMaps)
validatorMaps.Validators = vs
v, _ := proto.Marshal(validatorMaps)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalValidatorMapsPrefix(), Value: v})
totalPower += power
totalP := types.ReceiptQueryTotalPower{
TotalPower: totalPower,
}
totalPBytes, _ := json.Marshal(totalP)
totalPBytes, _ := proto.Marshal(&totalP)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalLastTotalPowerPrefix(), Value: totalPBytes})
return receipt, nil
}
......@@ -183,13 +178,13 @@ func (k Keeper) ProcessRemoveValidator(address string) (*types2.Receipt, error)
elog.Info("ProcessLogOutValidator", "pre validatorMaps", validatorMaps, "Delete Address", address)
var totalPower int64
var validatorRes []types.MsgValidator
for _, p := range validatorMaps {
validatorRes := new(types.ValidatorList)
for _, p := range validatorMaps.Validators {
if address != p.Address {
validatorRes = append(validatorRes, p)
v := append(validatorRes.Validators, p)
validatorRes.Validators = v
totalPower += p.Power
} else {
//oracle.RemoveAddrFromValidatorMap(validatorMaps, index)
exist = true
continue
}
......@@ -199,12 +194,12 @@ func (k Keeper) ProcessRemoveValidator(address string) (*types2.Receipt, error)
return nil, types.ErrAddressNotExist
}
v, _ := json.Marshal(validatorRes)
v, _ := proto.Marshal(validatorRes)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalValidatorMapsPrefix(), Value: v})
totalP := types.ReceiptQueryTotalPower{
TotalPower: totalPower,
}
totalPBytes, _ := json.Marshal(totalP)
totalPBytes, _ := proto.Marshal(&totalP)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalLastTotalPowerPrefix(), Value: totalPBytes})
return receipt, nil
}
......@@ -221,11 +216,11 @@ func (k Keeper) ProcessModifyValidator(address string, power int64) (*types2.Rec
elog.Info("ProcessModifyValidator", "pre validatorMaps", validatorMaps, "Modify Address", address, "Modify power", power)
var totalPower int64
for index, p := range validatorMaps {
for index, p := range validatorMaps.Validators {
if address != p.Address {
totalPower += p.Power
} else {
validatorMaps[index].Power = power
validatorMaps.Validators[index].Power = power
exist = true
totalPower += power
}
......@@ -235,18 +230,18 @@ func (k Keeper) ProcessModifyValidator(address string, power int64) (*types2.Rec
return nil, types.ErrAddressNotExist
}
v, _ := json.Marshal(validatorMaps)
v, _ := proto.Marshal(validatorMaps)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalValidatorMapsPrefix(), Value: v})
totalP := types.ReceiptQueryTotalPower{
TotalPower: totalPower,
}
totalPBytes, _ := json.Marshal(totalP)
totalPBytes, _ := proto.Marshal(&totalP)
receipt.KV = append(receipt.KV, &types2.KeyValue{Key: types.CalLastTotalPowerPrefix(), Value: totalPBytes})
return receipt, nil
}
func (k Keeper) ProcessSetConsensusNeeded(ConsensusThreshold int64) (int64, int64, error) {
func (k *Keeper) ProcessSetConsensusNeeded(ConsensusThreshold int64) (int64, int64, error) {
preCon := k.oracleKeeper.GetConsensusThreshold()
k.oracleKeeper.SetConsensusThreshold(ConsensusThreshold)
nowCon := k.oracleKeeper.GetConsensusThreshold()
......
package ethbridge
import (
"strconv"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/executor/common"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
gethCommon "github.com/ethereum/go-ethereum/common"
)
type Msg_Burn struct {
EthereumChainID int64 `json:"ethereum_chain_id" yaml:"ethereum_chain_id"`
TokenContract common.EthAddress `json:"token_contract_address" yaml:"token_contract_address"`
Chain33Sender string `json:"chain33_sender" yaml:"chain33_sender"`
EthereumReceiver common.EthAddress `json:"ethereum_receiver" yaml:"ethereum_receiver"`
Amount uint64 `json:"amount" yaml:"amount"`
}
func NewMsgBurn(ethereumChainID int64, tokenContract string, chain33Sender string, ethereumReceiver string, amount uint64) Msg_Burn {
return Msg_Burn{
EthereumChainID: ethereumChainID,
TokenContract: common.NewEthereumAddress(tokenContract),
Chain33Sender: chain33Sender,
EthereumReceiver: common.NewEthereumAddress(ethereumReceiver),
Amount: amount,
}
}
// Route should return the name of the module
func (msg Msg_Burn) Route() string { return types.ModuleName }
// Type should return the action
func (msg Msg_Burn) Type() string { return "burn" }
// ValidateBasic runs stateless checks on the message
func (msg Msg_Burn) ValidateBasic() error {
if strconv.Itoa(int(msg.EthereumChainID)) == "" {
return types.ErrInvalidChainID
}
if msg.TokenContract.String() == "" {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.TokenContract.String()) {
return types.ErrInvalidEthAddress
}
if types.AddressIsEmpty(msg.Chain33Sender) {
return types.ErrInvalidAddress
}
if msg.EthereumReceiver.String() == "" {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.EthereumReceiver.String()) {
return types.ErrInvalidEthAddress
}
return nil
}
package ethbridge
import (
"errors"
"fmt"
"strings"
"github.com/33cn/chain33/common/address"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
gethCommon "github.com/ethereum/go-ethereum/common"
)
// MsgCreateEthBridgeClaim defines a message for creating claims on the ethereum bridge
type MsgCreateEthBridgeClaim types.Eth2Chain33
// NewMsgCreateEthBridgeClaim is a constructor function for MsgCreateBridgeClaim
func NewMsgCreateEthBridgeClaim(ethBridgeClaim types.Eth2Chain33) MsgCreateEthBridgeClaim {
return MsgCreateEthBridgeClaim(ethBridgeClaim)
}
// Route should return the name of the module
func (msg MsgCreateEthBridgeClaim) Route() string { return types.ModuleName }
// Type should return the action
func (msg MsgCreateEthBridgeClaim) Type() string { return "create_bridge_claim" }
// ValidateBasic runs stateless checks on the message
func (msg MsgCreateEthBridgeClaim) ValidateBasic() error {
if types.AddressIsEmpty(msg.Chain33Receiver) {
return types.ErrInvalidAddress
}
if types.AddressIsEmpty(msg.ValidatorAddress) {
return types.ErrInvalidAddress
}
if msg.Nonce < 0 {
return types.ErrInvalidEthNonce
}
if !gethCommon.IsHexAddress(msg.EthereumSender) {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.BridgeContractAddress) {
return types.ErrInvalidEthAddress
}
if strings.ToLower(msg.LocalCoinSymbol) == "eth" && msg.TokenContractAddress != "0x0000000000000000000000000000000000000000" {
return types.ErrInvalidEthSymbol
}
return nil
}
// MapOracleClaimsToEthBridgeClaims maps a set of generic oracle claim data into EthBridgeClaim objects
func MapOracleClaimsToEthBridgeClaims(ethereumChainID int, bridgeContract string, nonce int, symbol string, tokenContract string, ethereumSender string, oracleValidatorClaims map[string]string, f func(int, string, int, string, string, string, string, string) (types.Eth2Chain33, error)) ([]types.Eth2Chain33, error) {
mappedClaims := make([]types.Eth2Chain33, len(oracleValidatorClaims))
i := 0
for validator, validatorClaim := range oracleValidatorClaims {
parseErr := address.CheckAddress(validator)
if parseErr != nil {
return nil, errors.New(fmt.Sprintf("failed to parse claim: %s", parseErr))
}
mappedClaim, err := f(ethereumChainID, bridgeContract, nonce, symbol, tokenContract, ethereumSender, validator, validatorClaim)
if err != nil {
return nil, err
}
mappedClaims[i] = mappedClaim
i++
}
return mappedClaims, nil
}
package ethbridge
import (
"strconv"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/executor/common"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
gethCommon "github.com/ethereum/go-ethereum/common"
)
// MsgLock defines a message for locking coins and triggering a related event
type MsgLock struct {
EthereumChainID int `json:"ethereum_chain_id" yaml:"ethereum_chain_id"`
TokenContract common.EthAddress `json:"token_contract_address" yaml:"token_contract_address"`
Chain33Sender string `json:"chain33_sender" yaml:"chain33_sender"`
EthereumReceiver common.EthAddress `json:"ethereum_receiver" yaml:"ethereum_receiver"`
Amount uint64 `json:"amount" yaml:"amount"`
}
// NewMsgLock is a constructor function for MsgLock
func NewMsgLock(ethereumChainID int, tokenContract string, cosmosSender string, ethereumReceiver string, amount uint64) MsgLock {
return MsgLock{
EthereumChainID: ethereumChainID,
TokenContract: common.NewEthereumAddress(tokenContract),
Chain33Sender: cosmosSender,
EthereumReceiver: common.NewEthereumAddress(ethereumReceiver),
Amount: amount,
}
}
// Route should return the name of the module
func (msg MsgLock) Route() string { return types.ModuleName }
// Type should return the action
func (msg MsgLock) Type() string { return "lock" }
// ValidateBasic runs stateless checks on the message
func (msg MsgLock) ValidateBasic() error {
if strconv.Itoa(msg.EthereumChainID) == "" {
return types.ErrInvalidChainID
}
if msg.TokenContract.String() == "" {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.TokenContract.String()) {
return types.ErrInvalidEthAddress
}
if types.AddressIsEmpty(msg.Chain33Sender) {
return types.ErrInvalidAddress
}
if msg.EthereumReceiver.String() == "" {
return types.ErrInvalidEthAddress
}
if !gethCommon.IsHexAddress(msg.EthereumReceiver.String()) {
return types.ErrInvalidEthAddress
}
return nil
}
......@@ -19,57 +19,56 @@ import (
// 然后relayer端订阅到该消息后向chain33发送该类型消息
// 本端在验证该类型的请求合理后铸币,并生成相同数额的token
func (x *x2ethereum) Exec_Eth2Chain33(payload *x2ethereumtypes.Eth2Chain33, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
if payload.ValidatorAddress == "" {
payload.ValidatorAddress = address.PubKeyToAddr(tx.Signature.Pubkey)
}
return action.procMsgEth2Chain33(payload, defaultCon)
return action.procMsgEth2Chain33(payload)
}
// 将因ethereum端锁定的eth或者erc20而在chain33端生成的token返还
func (x *x2ethereum) Exec_WithdrawEth(payload *x2ethereumtypes.Eth2Chain33, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
// WithdrawChain33类型的交易是将Eth端因Chain33端锁定所生成的token返还给Chain33端(Burn)
func (x *x2ethereum) Exec_WithdrawChain33(payload *x2ethereumtypes.Chain33ToEth, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
if payload.ValidatorAddress == "" {
payload.ValidatorAddress = address.PubKeyToAddr(tx.Signature.Pubkey)
}
return action.procWithdrawEth(payload, defaultCon)
return action.procMsgBurn(payload)
}
//---------------- Chain33(eth/erc20) --> Ethereum-------------------//
// WithdrawChain33类型的交易是Chain33侧将本端生成的token返还到Ethereum端
func (x *x2ethereum) Exec_WithdrawChain33(payload *x2ethereumtypes.Chain33ToEth, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
// 将因ethereum端锁定的eth或者erc20而在chain33端生成的token返还
func (x *x2ethereum) Exec_WithdrawEth(payload *x2ethereumtypes.Eth2Chain33, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procMsgBurn(payload, defaultCon)
payload.ValidatorAddress = address.PubKeyToAddr(tx.Signature.Pubkey)
return action.procWithdrawEth(payload)
}
// Chain33ToEth类型的交易是Chain33侧在本端发出申请
// 在本端锁定一定数额的token,然后在ethereum端生成相同数额的token
func (x *x2ethereum) Exec_Chain33ToEth(payload *x2ethereumtypes.Chain33ToEth, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procMsgLock(payload, defaultCon)
return action.procMsgLock(payload)
}
// 转账功能
func (x *x2ethereum) Exec_Transfer(payload *types.AssetsTransfer, tx *types.Transaction, index int) (*types.Receipt, error) {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procMsgTransfer(payload, defaultCon)
return action.procMsgTransfer(payload)
}
//--------------------------合约管理员账户操作-------------------------//
......@@ -78,11 +77,11 @@ func (x *x2ethereum) Exec_Transfer(payload *types.AssetsTransfer, tx *types.Tran
func (x *x2ethereum) Exec_AddValidator(payload *x2ethereumtypes.MsgValidator, tx *types.Transaction, index int) (*types.Receipt, error) {
err := checkTxSignBySpecificAddr(tx, x2ethereumtypes.X2ethereumAdmin)
if err == nil {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procAddValidator(payload, defaultCon)
return action.procAddValidator(payload)
}
return nil, err
}
......@@ -91,11 +90,11 @@ func (x *x2ethereum) Exec_AddValidator(payload *x2ethereumtypes.MsgValidator, tx
func (x *x2ethereum) Exec_RemoveValidator(payload *x2ethereumtypes.MsgValidator, tx *types.Transaction, index int) (*types.Receipt, error) {
err := checkTxSignBySpecificAddr(tx, x2ethereumtypes.X2ethereumAdmin)
if err == nil {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procRemoveValidator(payload, defaultCon)
return action.procRemoveValidator(payload)
}
return nil, err
}
......@@ -104,11 +103,11 @@ func (x *x2ethereum) Exec_RemoveValidator(payload *x2ethereumtypes.MsgValidator,
func (x *x2ethereum) Exec_ModifyPower(payload *x2ethereumtypes.MsgValidator, tx *types.Transaction, index int) (*types.Receipt, error) {
err := checkTxSignBySpecificAddr(tx, x2ethereumtypes.X2ethereumAdmin)
if err == nil {
action, defaultCon := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
return action.procModifyValidator(payload, defaultCon)
return action.procModifyValidator(payload)
}
return nil, err
}
......@@ -117,7 +116,7 @@ func (x *x2ethereum) Exec_ModifyPower(payload *x2ethereumtypes.MsgValidator, tx
func (x *x2ethereum) Exec_SetConsensusThreshold(payload *x2ethereumtypes.MsgConsensusThreshold, tx *types.Transaction, index int) (*types.Receipt, error) {
err := checkTxSignBySpecificAddr(tx, x2ethereumtypes.X2ethereumAdmin)
if err == nil {
action, _ := newAction(x, tx, int32(index))
action := newAction(x, tx, int32(index))
if action == nil {
return nil, errors.New("Create Action Error")
}
......
......@@ -13,7 +13,6 @@ import (
"github.com/33cn/chain33/types"
chain33types "github.com/33cn/chain33/types"
"github.com/33cn/chain33/util"
common2 "github.com/33cn/plugin/plugin/dapp/x2Ethereum/executor/common"
types2 "github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
......@@ -74,7 +73,7 @@ func (x *suiteX2Ethereum) SetupSuite() {
tx.Nonce = 1
tx.Sign(types.SECP256K1, privFrom)
x.action = newAction(x2eth, tx, 0)
x.action, _ = newAction(x2eth, tx, 0)
x.x2eth = x2eth
x.addrX2Eth = address.ExecAddress(driverName)
......@@ -178,9 +177,8 @@ func (x *suiteX2Ethereum) Test_4_Eth2Chain33() {
EthereumSender: ethereumAddr,
Chain33Receiver: chain33Receiver,
ValidatorAddress: addValidator1,
Amount: 10,
ClaimType: common2.LockText,
EthSymbol: symbol,
Amount: "10",
ClaimType: int64(types2.LOCK_CLAIM_TYPE),
}
receipt, err := x.action.procMsgEth2Chain33(payload)
......@@ -198,20 +196,20 @@ func (x *suiteX2Ethereum) Test_4_Eth2Chain33() {
x.query_GetEthProphecy("000x7B95B6EC7EbD73572298cEf32Bb54FA408207359", types2.EthBridgeStatus_SuccessStatusText)
x.query_GetSymbolTotalAmountByTxType(symbol, 1, "lock", 10)
payload.Amount = 3
payload.Amount = "3"
payload.Nonce = 1
payload.ClaimType = common2.BurnText
payload.ClaimType = int64(types2.BURN_CLAIM_TYPE)
payload.ValidatorAddress = addValidator1
receipt, err = x.action.procWithdrawEth(payload)
x.NoError(err)
x.setDb(receipt)
payload.ValidatorAddress = addValidator2
payload.Amount = 2
payload.Amount = "2"
receipt, err = x.action.procWithdrawEth(payload)
x.Equal(err, types2.ErrClaimInconsist)
payload.Amount = 3
payload.Amount = "3"
receipt, err = x.action.procWithdrawEth(payload)
x.NoError(err)
x.setDb(receipt)
......@@ -220,7 +218,7 @@ func (x *suiteX2Ethereum) Test_4_Eth2Chain33() {
x.query_GetSymbolTotalAmount(symbol, 1, 7)
x.query_GetSymbolTotalAmountByTxType(symbol, 1, "withdraw", 3)
payload.Amount = 10
payload.Amount = "10"
payload.Nonce = 2
payload.ValidatorAddress = addValidator1
receipt, err = x.action.procWithdrawEth(payload)
......@@ -228,9 +226,9 @@ func (x *suiteX2Ethereum) Test_4_Eth2Chain33() {
receipt, err = x.action.procWithdrawEth(payload)
x.Equal(types.ErrNoBalance, err)
payload.Amount = 1
payload.Amount = "1"
payload.Nonce = 3
payload.ClaimType = common2.LockText
payload.ClaimType = int64(types2.LOCK_CLAIM_TYPE)
payload.ValidatorAddress = addValidator1
receipt, err = x.action.procMsgEth2Chain33(payload)
x.setDb(receipt)
......@@ -248,8 +246,7 @@ func (x *suiteX2Ethereum) Test_5_Chain33ToEth() {
TokenContract: tokenContractAddress,
Chain33Sender: addValidator1,
EthereumReceiver: ethereumAddr,
Amount: 5,
EthSymbol: symbol,
Amount: "5",
LocalCoinSymbol: "bty",
LocalCoinExec: coinExec,
}
......@@ -261,7 +258,7 @@ func (x *suiteX2Ethereum) Test_5_Chain33ToEth() {
x.query_GetSymbolTotalAmount("bty", 2, 5)
x.query_GetSymbolTotalAmountByTxType("bty", 2, "lock", 5)
msgLock.Amount = 4
msgLock.Amount = "4"
receipt, err = x.action.procMsgBurn(msgLock)
x.NoError(err)
x.setDb(receipt)
......@@ -272,7 +269,7 @@ func (x *suiteX2Ethereum) Test_5_Chain33ToEth() {
receipt, err = x.action.procMsgBurn(msgLock)
x.Equal(err, types.ErrNoBalance)
msgLock.Amount = 1
msgLock.Amount = "1"
receipt, err = x.action.procMsgBurn(msgLock)
x.NoError(err)
x.setDb(receipt)
......
package oracle
import (
"encoding/json"
"strings"
"github.com/golang/protobuf/proto"
dbm "github.com/33cn/chain33/common/db"
log "github.com/33cn/chain33/common/log/log15"
types2 "github.com/33cn/chain33/types"
......@@ -15,154 +16,77 @@ var (
olog = log.New("module", "oracle")
)
type Keeper struct {
type OracleKeeper struct {
db dbm.KV
// 通过审核的最低阈值
ConsensusThreshold int64
}
func NewKeeper(db dbm.KV, ConsensusThreshold int64) *Keeper {
func NewOracleKeeper(db dbm.KV, ConsensusThreshold int64) *OracleKeeper {
if ConsensusThreshold <= 0 || ConsensusThreshold > 100 {
return nil
}
return &Keeper{
return &OracleKeeper{
db: db,
ConsensusThreshold: ConsensusThreshold,
}
}
func (k *Keeper) GetProphecy(id string) (Prophecy, error) {
func (k *OracleKeeper) GetProphecy(id string) (*types.ReceiptEthProphecy, error) {
if id == "" {
return NewEmptyProphecy(), types.ErrInvalidIdentifier
}
bz, err := k.db.Get(types.CalProphecyPrefix())
bz, err := k.db.Get(types.CalProphecyPrefix(id))
if err != nil && err != types2.ErrNotFound {
return NewEmptyProphecy(), types.ErrProphecyGet
} else if err == types2.ErrNotFound {
return NewEmptyProphecy(), types.ErrProphecyNotFound
}
var dbProphecys []DBProphecy
var dbProphecy DBProphecy
err = json.Unmarshal(bz, &dbProphecys)
if err != nil {
return NewEmptyProphecy(), types2.ErrUnmarshal
}
var exist bool
for _, p := range dbProphecys {
if p.ID == id {
dbProphecy = p
exist = true
break
}
}
if exist {
deSerializedProphecy, err := dbProphecy.DeserializeFromDB()
var dbProphecy types.ReceiptEthProphecy
err = proto.Unmarshal(bz, &dbProphecy)
if err != nil {
return NewEmptyProphecy(), types.ErrinternalDB
}
return deSerializedProphecy, nil
} else {
return NewEmptyProphecy(), types.ErrProphecyNotFound
return NewEmptyProphecy(), types2.ErrUnmarshal
}
return &dbProphecy, nil
}
// setProphecy saves a prophecy with an initial claim
func (k *Keeper) setProphecy(prophecy Prophecy) error {
err := k.checkProphecy(prophecy)
if err != nil {
return err
}
serializedProphecy, err := prophecy.SerializeForDB()
if err != nil {
return types.ErrinternalDB
}
bz, err := k.db.Get(types.CalProphecyPrefix())
if err != nil && err != types2.ErrNotFound {
return types.ErrProphecyGet
}
var dbProphecys []DBProphecy
if err != types2.ErrNotFound {
err = json.Unmarshal(bz, &dbProphecys)
if err != nil {
return types2.ErrUnmarshal
}
}
var exist bool
for index, dbP := range dbProphecys {
if dbP.ID == serializedProphecy.ID {
exist = true
dbProphecys[index] = serializedProphecy
break
}
}
if !exist {
dbProphecys = append(dbProphecys, serializedProphecy)
}
serializedProphecyBytes, err := json.Marshal(dbProphecys)
if err != nil {
return types2.ErrMarshal
}
err = k.db.Set(types.CalProphecyPrefix(), serializedProphecyBytes)
if err != nil {
return types.ErrSetKV
}
return nil
}
// modifyProphecy saves a modified prophecy
func (k *Keeper) modifyProphecy(prophecy Prophecy) error {
func (k *OracleKeeper) setProphecy(prophecy *types.ReceiptEthProphecy) error {
err := k.checkProphecy(prophecy)
if err != nil {
return err
}
serializedProphecy, err := prophecy.SerializeForDB()
if err != nil {
return types.ErrinternalDB
}
bz, err := k.db.Get(types.CalProphecyPrefix())
bz, err := k.db.Get(types.CalProphecyPrefix(prophecy.ID))
if err != nil && err != types2.ErrNotFound {
return types.ErrProphecyGet
}
var dbProphecys []DBProphecy
var dbProphecy types.ReceiptEthProphecy
if err != types2.ErrNotFound {
err = json.Unmarshal(bz, &dbProphecys)
err = proto.Unmarshal(bz, &dbProphecy)
if err != nil {
return types2.ErrUnmarshal
}
}
for index, dbP := range dbProphecys {
if dbP.ID == serializedProphecy.ID {
dbProphecys[index] = serializedProphecy
break
}
}
dbProphecy = *prophecy
serializedProphecyBytes, err := json.Marshal(dbProphecys)
serializedProphecyBytes, err := proto.Marshal(&dbProphecy)
if err != nil {
return types2.ErrMarshal
}
err = k.db.Set(types.CalProphecyPrefix(), serializedProphecyBytes)
err = k.db.Set(types.CalProphecyPrefix(prophecy.ID), serializedProphecyBytes)
if err != nil {
return types.ErrSetKV
}
return nil
}
func (k *Keeper) checkProphecy(prophecy Prophecy) error {
func (k *OracleKeeper) checkProphecy(prophecy *types.ReceiptEthProphecy) error {
if prophecy.ID == "" {
return types.ErrInvalidIdentifier
}
......@@ -172,23 +96,23 @@ func (k *Keeper) checkProphecy(prophecy Prophecy) error {
return nil
}
func (k *Keeper) ProcessClaim(claim types.OracleClaim) (Status, error) {
func (k *OracleKeeper) ProcessClaim(claim types.OracleClaim) (*types.ProphecyStatus, error) {
activeValidator := k.checkActiveValidator(claim.ValidatorAddress)
if !activeValidator {
return Status{}, types.ErrInvalidValidator
return nil, types.ErrInvalidValidator
}
if strings.TrimSpace(claim.Content) == "" {
return Status{}, types.ErrInvalidClaim
return nil, types.ErrInvalidClaim
}
var claimContent types.OracleClaimContent
err := json.Unmarshal([]byte(claim.Content), &claimContent)
err := proto.Unmarshal([]byte(claim.Content), &claimContent)
if err != nil {
return Status{}, types2.ErrUnmarshal
return nil, types2.ErrUnmarshal
}
prophecy, err := k.GetProphecy(claim.ID)
if err != nil {
if err != types.ErrProphecyNotFound {
return Status{}, err
return nil, err
}
prophecy = NewProphecy(claim.ID)
} else {
......@@ -199,40 +123,37 @@ func (k *Keeper) ProcessClaim(claim types.OracleClaim) (Status, error) {
}
}
if !exist {
prophecy.Status.Text = StatusText(types.EthBridgeStatus_FailedStatusText)
return Status{}, types.ErrClaimInconsist
prophecy.Status.Text = types.EthBridgeStatus_FailedStatusText
return nil, types.ErrClaimInconsist
}
if claimContent.ClaimType == int64(types.LOCK_CLAIM_TYPE) {
if prophecy.Status.Text == StatusText(types.EthBridgeStatus_SuccessStatusText) || prophecy.Status.Text == StatusText(types.EthBridgeStatus_FailedStatusText) {
return Status{}, types.ErrProphecyFinalized
if prophecy.Status.Text == types.EthBridgeStatus_FailedStatusText {
return nil, types.ErrProphecyFinalized
}
for _, vc := range prophecy.ValidatorClaims {
if vc.Validator == claim.ValidatorAddress && vc.Claim != "" {
return Status{}, types.ErrDuplicateMessage
return nil, types.ErrDuplicateMessage
}
}
} else if claimContent.ClaimType == int64(types.BURN_CLAIM_TYPE) {
if prophecy.Status.Text == StatusText(types.EthBridgeStatus_WithdrawedStatusText) || prophecy.Status.Text == StatusText(types.EthBridgeStatus_FailedStatusText) {
return Status{}, types.ErrProphecyFinalized
}
}
AddClaim(prophecy, claim.ValidatorAddress, claim.Content)
prophecy, err = k.processCompletion(prophecy, claimContent.ClaimType)
if err != nil {
return nil, err
}
prophecy.AddClaim(claim.ValidatorAddress, claim.Content)
prophecy, err = k.processCompletion(&prophecy, claimContent.ClaimType)
err = k.setProphecy(prophecy)
if err != nil {
return Status{}, err
return nil, err
}
return prophecy.Status, nil
}
func (k *Keeper) checkActiveValidator(validatorAddress string) bool {
func (k *OracleKeeper) checkActiveValidator(validatorAddress string) bool {
validatorMap, err := k.GetValidatorArray()
if err != nil {
return false
}
for _, v := range validatorMap {
for _, v := range validatorMap.Validators {
if v.Address == validatorAddress {
return true
}
......@@ -241,41 +162,37 @@ func (k *Keeper) checkActiveValidator(validatorAddress string) bool {
}
// 计算该prophecy是否达标
func (k *Keeper) processCompletion(prophecy *Prophecy, claimType int64) (Prophecy, error) {
func (k *OracleKeeper) processCompletion(prophecy *types.ReceiptEthProphecy, claimType int64) (*types.ReceiptEthProphecy, error) {
address2power := make(map[string]int64)
validatorArrays, err := k.GetValidatorArray()
if err != nil {
return *prophecy, err
return nil, err
}
for _, validator := range validatorArrays {
for _, validator := range validatorArrays.Validators {
address2power[validator.Address] = validator.Power
}
highestClaim, highestClaimPower, totalClaimsPower := prophecy.FindHighestClaim(address2power)
highestClaim, highestClaimPower, totalClaimsPower := FindHighestClaim(prophecy, address2power)
totalPower, err := k.GetLastTotalPower()
if err != nil {
return *prophecy, err
return nil, err
}
highestConsensusRatio := highestClaimPower * 100 / totalPower
highestConsensusRatio := highestClaimPower * 100
remainingPossibleClaimPower := totalPower - totalClaimsPower
highestPossibleClaimPower := highestClaimPower + remainingPossibleClaimPower
highestPossibleConsensusRatio := highestPossibleClaimPower * 100 / totalPower
olog.Info("processCompletion", "highestConsensusRatio", highestConsensusRatio, "ConsensusThreshold", k.ConsensusThreshold, "highestPossibleConsensusRatio", highestPossibleConsensusRatio)
if highestConsensusRatio >= k.ConsensusThreshold {
if claimType == int64(types.LOCK_CLAIM_TYPE) {
prophecy.Status.Text = StatusText(types.EthBridgeStatus_SuccessStatusText)
} else if claimType == int64(types.BURN_CLAIM_TYPE) {
prophecy.Status.Text = StatusText(types.EthBridgeStatus_WithdrawedStatusText)
}
highestPossibleConsensusRatio := highestPossibleClaimPower * 100
olog.Info("processCompletion", "highestConsensusRatio", highestConsensusRatio/totalPower, "ConsensusThreshold", k.ConsensusThreshold, "highestPossibleConsensusRatio", highestPossibleConsensusRatio/totalPower)
if highestConsensusRatio >= k.ConsensusThreshold*totalPower {
prophecy.Status.Text = types.EthBridgeStatus_SuccessStatusText
prophecy.Status.FinalClaim = highestClaim
} else if highestPossibleConsensusRatio < k.ConsensusThreshold {
prophecy.Status.Text = StatusText(types.EthBridgeStatus_FailedStatusText)
} else if highestPossibleConsensusRatio < k.ConsensusThreshold*totalPower {
prophecy.Status.Text = types.EthBridgeStatus_FailedStatusText
}
return *prophecy, nil
return prophecy, nil
}
// Load the last total validator power.
func (k *Keeper) GetLastTotalPower() (int64, error) {
func (k *OracleKeeper) GetLastTotalPower() (int64, error) {
b, err := k.db.Get(types.CalLastTotalPowerPrefix())
if err != nil && err != types2.ErrNotFound {
return 0, err
......@@ -283,7 +200,7 @@ func (k *Keeper) GetLastTotalPower() (int64, error) {
return 0, nil
}
var powers types.ReceiptQueryTotalPower
err = json.Unmarshal(b, &powers)
err = proto.Unmarshal(b, &powers)
if err != nil {
return 0, types2.ErrUnmarshal
}
......@@ -291,19 +208,19 @@ func (k *Keeper) GetLastTotalPower() (int64, error) {
}
// Set the last total validator power.
func (k *Keeper) SetLastTotalPower() error {
func (k *OracleKeeper) SetLastTotalPower() error {
var totalPower int64
validatorArrays, err := k.GetValidatorArray()
if err != nil {
return err
}
for _, validator := range validatorArrays {
for _, validator := range validatorArrays.Validators {
totalPower += validator.Power
}
totalP := types.ReceiptQueryTotalPower{
TotalPower: totalPower,
}
totalPBytes, _ := json.Marshal(totalP)
totalPBytes, _ := proto.Marshal(&totalP)
err = k.db.Set(types.CalLastTotalPowerPrefix(), totalPBytes)
if err != nil {
return types.ErrSetKV
......@@ -311,25 +228,25 @@ func (k *Keeper) SetLastTotalPower() error {
return nil
}
func (k *Keeper) GetValidatorArray() ([]types.MsgValidator, error) {
func (k *OracleKeeper) GetValidatorArray() (*types.ValidatorList, error) {
validatorsBytes, err := k.db.Get(types.CalValidatorMapsPrefix())
if err != nil {
return nil, err
}
var validatorArrays []types.MsgValidator
err = json.Unmarshal(validatorsBytes, &validatorArrays)
var validatorArrays types.ValidatorList
err = proto.Unmarshal(validatorsBytes, &validatorArrays)
if err != nil {
return nil, types2.ErrUnmarshal
}
return validatorArrays, nil
return &validatorArrays, nil
}
func (k *Keeper) SetConsensusThreshold(ConsensusThreshold int64) {
func (k *OracleKeeper) SetConsensusThreshold(ConsensusThreshold int64) {
k.ConsensusThreshold = ConsensusThreshold
olog.Info("SetConsensusNeeded", "nowConsensusNeeded", k.ConsensusThreshold)
return
}
func (k *Keeper) GetConsensusThreshold() int64 {
func (k *OracleKeeper) GetConsensusThreshold() int64 {
return k.ConsensusThreshold
}
package oracle
import (
"encoding/json"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
type Prophecy struct {
ID string `json:"id"`
Status Status `json:"status"`
ClaimValidators []*types.ClaimValidators `json:"claim_validators"`
ValidatorClaims []*types.ValidatorClaims `json:"validator_claims"`
}
func NewProphecy(id string) *types.ReceiptEthProphecy {
func NewProphecy(id string) Prophecy {
return Prophecy{
status := new(types.ProphecyStatus)
status.Text = types.EthBridgeStatus_PendingStatusText
return &types.ReceiptEthProphecy{
ID: id,
Status: NewStatus(StatusText(types.EthBridgeStatus_PendingStatusText), ""),
Status: status,
ClaimValidators: *new([]*types.ClaimValidators),
ValidatorClaims: *new([]*types.ValidatorClaims),
}
}
func NewEmptyProphecy() Prophecy {
func NewEmptyProphecy() *types.ReceiptEthProphecy {
return NewProphecy("")
}
type DBProphecy struct {
ID string `json:"id"`
Status Status `json:"status"`
ClaimValidators []byte `json:"claim_validators"`
ValidatorClaims []byte `json:"validator_claims"`
}
// SerializeForDB serializes a prophecy into a DBProphecy
func (prophecy Prophecy) SerializeForDB() (DBProphecy, error) {
claimValidators, err := json.Marshal(prophecy.ClaimValidators)
if err != nil {
return DBProphecy{}, err
}
validatorClaims, err := json.Marshal(prophecy.ValidatorClaims)
if err != nil {
return DBProphecy{}, err
}
return DBProphecy{
ID: prophecy.ID,
Status: prophecy.Status,
ClaimValidators: claimValidators,
ValidatorClaims: validatorClaims,
}, nil
}
// DeserializeFromDB deserializes a DBProphecy into a prophecy
func (dbProphecy DBProphecy) DeserializeFromDB() (Prophecy, error) {
claimValidators := new([]*types.ClaimValidators)
err := json.Unmarshal(dbProphecy.ClaimValidators, &claimValidators)
if err != nil {
return Prophecy{}, err
}
validatorClaims := new([]*types.ValidatorClaims)
err = json.Unmarshal(dbProphecy.ValidatorClaims, &validatorClaims)
if err != nil {
return Prophecy{}, err
}
return Prophecy{
ID: dbProphecy.ID,
Status: dbProphecy.Status,
ClaimValidators: *claimValidators,
ValidatorClaims: *validatorClaims,
}, nil
}
//
//type DBProphecy struct {
// ID string `json:"id"`
// Status Status `json:"status"`
// ClaimValidators []byte `json:"claim_validators"`
// ValidatorClaims []byte `json:"validator_claims"`
//}
//
//// SerializeForDB serializes a prophecy into a DBProphecy
//func (prophecy Prophecy) SerializeForDB() (DBProphecy, error) {
// claimValidators, err := json.Marshal(prophecy.ClaimValidators)
// if err != nil {
// return DBProphecy{}, err
// }
//
// validatorClaims, err := json.Marshal(prophecy.ValidatorClaims)
// if err != nil {
// return DBProphecy{}, err
// }
//
// return DBProphecy{
// ID: prophecy.ID,
// Status: prophecy.Status,
// ClaimValidators: claimValidators,
// ValidatorClaims: validatorClaims,
// }, nil
//}
//
//// DeserializeFromDB deserializes a DBProphecy into a prophecy
//func (dbProphecy DBProphecy) DeserializeFromDB() (Prophecy, error) {
// claimValidators := new([]*types.ClaimValidators)
// err := json.Unmarshal(dbProphecy.ClaimValidators, &claimValidators)
// if err != nil {
// return Prophecy{}, err
// }
//
// validatorClaims := new([]*types.ValidatorClaims)
// err = json.Unmarshal(dbProphecy.ValidatorClaims, &validatorClaims)
// if err != nil {
// return Prophecy{}, err
// }
//
// return Prophecy{
// ID: dbProphecy.ID,
// Status: dbProphecy.Status,
// ClaimValidators: *claimValidators,
// ValidatorClaims: *validatorClaims,
// }, nil
//}
// AddClaim adds a given claim to this prophecy
func (prophecy *Prophecy) AddClaim(validator string, claim string) {
func AddClaim(prophecy *types.ReceiptEthProphecy, validator string, claim string) {
claimValidators := new(types.StringMap)
if len(prophecy.ClaimValidators) == 0 {
prophecy.ClaimValidators = append(prophecy.ClaimValidators, &types.ClaimValidators{
......@@ -95,29 +91,36 @@ func (prophecy *Prophecy) AddClaim(validator string, claim string) {
}
}
if len(prophecy.ValidatorClaims) == 0 {
prophecy.ValidatorClaims = append(prophecy.ValidatorClaims, &types.ValidatorClaims{
Validator: validator,
Claim: claim,
})
} else {
for index, vc := range prophecy.ValidatorClaims {
if vc.Validator == validator {
prophecy.ValidatorClaims[index].Claim = claim
break
} else {
//todo
// validator不可能相同?
//if len(prophecy.ValidatorClaims) == 0 {
// prophecy.ValidatorClaims = append(prophecy.ValidatorClaims, &types.ValidatorClaims{
// Validator: validator,
// Claim: claim,
// })
//} else {
// for index, vc := range prophecy.ValidatorClaims {
// if vc.Validator == validator {
// prophecy.ValidatorClaims[index].Claim = claim
// break
// } else {
// prophecy.ValidatorClaims = append(prophecy.ValidatorClaims, &types.ValidatorClaims{
// Validator: validator,
// Claim: claim,
// })
// }
// }
//}
prophecy.ValidatorClaims = append(prophecy.ValidatorClaims, &types.ValidatorClaims{
Validator: validator,
Claim: claim,
})
}
}
}
}
// 遍历该prophecy所有claim,找出获得最多票数的claim
func (prophecy *Prophecy) FindHighestClaim(validators map[string]int64) (string, int64, int64) {
func FindHighestClaim(prophecy *types.ReceiptEthProphecy, validators map[string]int64) (string, int64, int64) {
totalClaimsPower := int64(0)
highestClaimPower := int64(-1)
highestClaim := ""
......@@ -135,17 +138,3 @@ func (prophecy *Prophecy) FindHighestClaim(validators map[string]int64) (string,
}
return highestClaim, highestClaimPower, totalClaimsPower
}
// Status is a struct that contains the status of a given prophecy
type Status struct {
Text StatusText `json:"text"`
FinalClaim string `json:"final_claim"`
}
// NewStatus returns a new Status with the given data contained
func NewStatus(text StatusText, finalClaim string) Status {
return Status{
Text: text,
FinalClaim: finalClaim,
}
}
package oracle
import (
"encoding/json"
"fmt"
"strconv"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
// StatusText is an enum used to represent the status of the prophecy
type StatusText int
var StatusTextToString = [...]string{"pending", "success", "failed", "withdrawed"}
var StringToStatusText = map[string]types.EthBridgeStatus{
"pending": types.EthBridgeStatus_PendingStatusText,
"success": types.EthBridgeStatus_SuccessStatusText,
"failed": types.EthBridgeStatus_FailedStatusText,
"withdrawed": types.EthBridgeStatus_WithdrawedStatusText,
}
func (text StatusText) String() string {
return StatusTextToString[text]
}
func (text StatusText) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("\"%v\"", text.String())), nil
}
func (text *StatusText) UnmarshalJSON(b []byte) error {
var j string
err := json.Unmarshal(b, &j)
if err != nil {
return err
}
stringKey, err := strconv.Unquote(string(b))
if err != nil {
return err
}
// Note that if the string cannot be found then it will be set to the zero value, 'pending' in this case.
*text = StatusText(StringToStatusText[stringKey])
return nil
}
package executor
import (
"encoding/json"
"strconv"
"strings"
"github.com/golang/protobuf/proto"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/x2Ethereum/executor/oracle"
types2 "github.com/33cn/plugin/plugin/dapp/x2Ethereum/types"
)
func (x *x2ethereum) Query_GetEthProphecy(in *types2.QueryEthProphecyParams) (types.Message, error) {
prophecy := &types2.ReceiptEthProphecy{}
prophecyKey := types2.CalProphecyPrefix()
prophecyKey := types2.CalProphecyPrefix(in.ID)
var dbProphecy types2.ReceiptEthProphecy
var dbProphecy []oracle.DBProphecy
val, err := x.GetStateDB().Get(prophecyKey)
if err != nil {
return nil, err
}
err = json.Unmarshal(val, &dbProphecy)
err = proto.Unmarshal(val, &dbProphecy)
if err != nil {
return nil, types.ErrUnmarshal
}
for _, dbP := range dbProphecy {
if dbP.ID == in.ID {
dbPD, err := dbP.DeserializeFromDB()
if err != nil {
return nil, err
}
prophecy = &types2.ReceiptEthProphecy{
ID: in.ID,
Status: &types2.ProphecyStatus{
Text: types2.EthBridgeStatus(dbP.Status.Text),
FinalClaim: dbP.Status.FinalClaim,
},
ClaimValidators: dbPD.ClaimValidators,
ValidatorClaims: dbPD.ValidatorClaims,
}
return prophecy, nil
}
}
return nil, types2.ErrInvalidProphecyID
return &dbProphecy, nil
}
func (x *x2ethereum) Query_GetValidators(in *types2.QueryValidatorsParams) (types.Message, error) {
validatorsKey := types2.CalValidatorMapsPrefix()
var v []*types2.MsgValidator
var v types2.ValidatorList
vBytes, err := x.GetStateDB().Get(validatorsKey)
if err != nil {
elog.Error("Query_GetValidators", "GetValidators Err", err)
return nil, err
}
err = json.Unmarshal(vBytes, &v)
err = proto.Unmarshal(vBytes, &v)
if err != nil {
return nil, types.ErrUnmarshal
}
if in.Validator != "" {
validatorsRes := new(types2.ReceiptQueryValidator)
for _, vv := range v {
for _, vv := range v.Validators {
if vv.Address == in.Validator {
val := make([]*types2.MsgValidator, 1)
val[0] = vv
......@@ -81,10 +63,10 @@ func (x *x2ethereum) Query_GetValidators(in *types2.QueryValidatorsParams) (type
} else {
validatorsRes := new(types2.ReceiptQueryValidator)
var totalPower int64
for _, vv := range v {
for _, vv := range v.Validators {
totalPower += vv.Power
}
validatorsRes.Validators = v
validatorsRes.Validators = v.Validators
validatorsRes.TotalPower = totalPower
return validatorsRes, nil
}
......@@ -99,7 +81,7 @@ func (x *x2ethereum) Query_GetTotalPower(in *types2.QueryTotalPowerParams) (type
elog.Error("Query_GetTotalPower", "GetTotalPower Err", err)
return nil, err
}
err = json.Unmarshal(totalPowerBytes, &totalPower)
err = proto.Unmarshal(totalPowerBytes, totalPower)
if err != nil {
return nil, types.ErrUnmarshal
}
......@@ -107,7 +89,7 @@ func (x *x2ethereum) Query_GetTotalPower(in *types2.QueryTotalPowerParams) (type
}
func (x *x2ethereum) Query_GetConsensusThreshold(in *types2.QueryConsensusThresholdParams) (types.Message, error) {
consensus := &types2.ReceiptSetConsensusThreshold{}
consensus := &types2.ReceiptQueryConsensusThreshold{}
consensusKey := types2.CalConsensusThresholdPrefix()
consensusBytes, err := x.GetStateDB().Get(consensusKey)
......@@ -115,7 +97,7 @@ func (x *x2ethereum) Query_GetConsensusThreshold(in *types2.QueryConsensusThresh
elog.Error("Query_GetConsensusNeeded", "GetConsensusNeeded Err", err)
return nil, err
}
err = json.Unmarshal(consensusBytes, &consensus)
err = proto.Unmarshal(consensusBytes, consensus)
if err != nil {
return nil, types.ErrUnmarshal
}
......
......@@ -53,7 +53,11 @@ func (x *x2ethereum) GetDriverName() string {
}
// CheckTx 实现自定义检验交易接口,供框架调用
// todo
// 实现
func (x *x2ethereum) CheckTx(tx *types.Transaction, index int) error {
// implement code
//var action x2ethereumtypes.X2EthereumAction
//err := types.Decode(tx.Payload, &action)
//if action.Ty
return nil
}
package executor
import (
"encoding/json"
"strconv"
"strings"
"github.com/golang/protobuf/proto"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common/address"
......@@ -59,120 +60,88 @@ type action struct {
keeper ethbridge.Keeper
}
//todo
//补充不同token的decimal数据库存储
func newAction(a *x2ethereum, tx *chain33types.Transaction, index int32) (*action, bool) {
var defaultCon = false
func newAction(a *x2ethereum, tx *chain33types.Transaction, index int32) *action {
hash := tx.Hash()
fromaddr := tx.From()
var ConsensusThreshold int64
consensusNeededBytes, err := a.GetStateDB().Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
ConsensusThreshold = types2.DefaultConsensusNeeded
cb, _ := json.Marshal(types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: 0,
NowConsensusThreshold: ConsensusThreshold,
})
_ = a.GetStateDB().Set(types2.CalConsensusThresholdPrefix(), cb)
defaultCon = true
} else {
return nil, false
}
} else {
var mc types2.ReceiptSetConsensusThreshold
_ = json.Unmarshal(consensusNeededBytes, &mc)
ConsensusThreshold = mc.NowConsensusThreshold
}
oracleKeeper := oracle.NewKeeper(a.GetStateDB(), ConsensusThreshold)
oracleKeeper := oracle.NewOracleKeeper(a.GetStateDB(), types2.DefaultConsensusNeeded)
if oracleKeeper == nil {
return nil, true
return nil
}
elog.Info("newAction", "newAction", "done")
return &action{a.GetAPI(), a.GetCoinsAccount(), a.GetStateDB(), hash, fromaddr,
a.GetBlockTime(), a.GetHeight(), index, address.ExecAddress(string(tx.Execer)), ethbridge.NewKeeper(oracleKeeper, a.GetStateDB())}, defaultCon
a.GetBlockTime(), a.GetHeight(), index, address.ExecAddress(string(tx.Execer)), ethbridge.NewKeeper(*oracleKeeper, a.GetStateDB())}
}
// ethereum ---> chain33
// lock
func (a *action) procMsgEth2Chain33(ethBridgeClaim *types2.Eth2Chain33, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procMsgEth2Chain33(ethBridgeClaim *types2.Eth2Chain33) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
ethBridgeClaim.LocalCoinSymbol = strings.ToLower(ethBridgeClaim.LocalCoinSymbol)
msgEthBridgeClaim := ethbridge.NewMsgCreateEthBridgeClaim(*ethBridgeClaim)
if err := msgEthBridgeClaim.ValidateBasic(); err != nil {
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
status, err := a.keeper.ProcessClaim(*ethBridgeClaim)
if err != nil {
return nil, err
}
ID := strconv.Itoa(int(msgEthBridgeClaim.EthereumChainID)) + strconv.Itoa(int(msgEthBridgeClaim.Nonce)) + msgEthBridgeClaim.EthereumSender + "lock"
ID := strconv.Itoa(int(ethBridgeClaim.EthereumChainID)) + strconv.Itoa(int(ethBridgeClaim.Nonce)) + ethBridgeClaim.EthereumSender + ethBridgeClaim.TokenContractAddress + "lock"
//记录ethProphecy
bz, err := a.db.Get(types2.CalProphecyPrefix())
bz, err := a.db.Get(types2.CalProphecyPrefix(ID))
if err != nil {
return nil, types2.ErrProphecyGet
}
var dbProphecys []oracle.DBProphecy
var dbProphecy oracle.DBProphecy
err = json.Unmarshal(bz, &dbProphecys)
var dbProphecy types2.ReceiptEthProphecy
err = proto.Unmarshal(bz, &dbProphecy)
if err != nil {
return nil, chain33types.ErrUnmarshal
}
for _, p := range dbProphecys {
if p.ID == ID {
dbProphecy = p
break
}
}
dRes, err := dbProphecy.DeserializeFromDB()
if err != nil {
return nil, err
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalProphecyPrefix(),
Key: types2.CalProphecyPrefix(ID),
Value: bz,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TyProphecyLog, Log: chain33types.Encode(&types2.ReceiptEthProphecy{
ID: dRes.ID,
Status: &types2.ProphecyStatus{
Text: types2.EthBridgeStatus(dRes.Status.Text),
FinalClaim: dRes.Status.FinalClaim,
},
ClaimValidators: dRes.ClaimValidators,
ValidatorClaims: dRes.ValidatorClaims,
})})
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TyProphecyLog, Log: chain33types.Encode(&dbProphecy)})
if status.Text == oracle.StatusText(types2.EthBridgeStatus_SuccessStatusText) {
if status.Text == types2.EthBridgeStatus_SuccessStatusText {
// mavl-x2ethereum-eth
accDB, err := account.NewAccountDB(a.api.GetConfig(), msgEthBridgeClaim.LocalCoinExec, strings.ToLower(msgEthBridgeClaim.LocalCoinSymbol+msgEthBridgeClaim.TokenContractAddress), a.db)
// 这里为了区分相同tokensymbol不同tokenAddress做了级联处理
accDB, err := account.NewAccountDB(a.api.GetConfig(), ethBridgeClaim.LocalCoinExec, strings.ToLower(ethBridgeClaim.LocalCoinSymbol+ethBridgeClaim.TokenContractAddress), a.db)
if err != nil {
return nil, errors.Wrapf(err, "relay procMsgEth2Chain33,exec=%s,sym=%s", msgEthBridgeClaim.LocalCoinExec, msgEthBridgeClaim.LocalCoinSymbol)
return nil, errors.Wrapf(err, "relay procMsgEth2Chain33,exec=%s,sym=%s", ethBridgeClaim.LocalCoinExec, ethBridgeClaim.LocalCoinSymbol)
}
r, err := a.keeper.ProcessSuccessfulClaimForLock(status.FinalClaim, a.execaddr, ethBridgeClaim.LocalCoinSymbol, ethBridgeClaim.TokenContractAddress, accDB)
......@@ -183,28 +152,28 @@ func (a *action) procMsgEth2Chain33(ethBridgeClaim *types2.Eth2Chain33, defaultC
receipt.Logs = append(receipt.Logs, r.Logs...)
//记录成功lock的日志
msgEthBridgeClaimBytes, err := json.Marshal(msgEthBridgeClaim)
msgEthBridgeClaimBytes, err := proto.Marshal(ethBridgeClaim)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{Key: types2.CalEth2Chain33Prefix(), Value: msgEthBridgeClaimBytes})
execlog := &chain33types.ReceiptLog{Ty: types2.TyEth2Chain33Log, Log: chain33types.Encode(&types2.ReceiptEth2Chain33{
EthereumChainID: msgEthBridgeClaim.EthereumChainID,
BridgeContractAddress: msgEthBridgeClaim.BridgeContractAddress,
Nonce: msgEthBridgeClaim.Nonce,
LocalCoinSymbol: msgEthBridgeClaim.LocalCoinSymbol,
LocalCoinExec: msgEthBridgeClaim.LocalCoinExec,
TokenContractAddress: msgEthBridgeClaim.TokenContractAddress,
EthereumSender: msgEthBridgeClaim.EthereumSender,
Chain33Receiver: msgEthBridgeClaim.Chain33Receiver,
ValidatorAddress: msgEthBridgeClaim.ValidatorAddress,
Amount: msgEthBridgeClaim.Amount,
ClaimType: msgEthBridgeClaim.ClaimType,
EthereumChainID: ethBridgeClaim.EthereumChainID,
BridgeContractAddress: ethBridgeClaim.BridgeContractAddress,
Nonce: ethBridgeClaim.Nonce,
LocalCoinSymbol: ethBridgeClaim.LocalCoinSymbol,
LocalCoinExec: ethBridgeClaim.LocalCoinExec,
TokenContractAddress: ethBridgeClaim.TokenContractAddress,
EthereumSender: ethBridgeClaim.EthereumSender,
Chain33Receiver: ethBridgeClaim.Chain33Receiver,
ValidatorAddress: ethBridgeClaim.ValidatorAddress,
Amount: ethBridgeClaim.Amount,
ClaimType: ethBridgeClaim.ClaimType,
XTxHash: a.txhash,
XHeight: uint64(a.height),
ProphecyID: ID,
Decimals: msgEthBridgeClaim.Decimals,
Decimals: ethBridgeClaim.Decimals,
})}
receipt.Logs = append(receipt.Logs, execlog)
......@@ -216,13 +185,46 @@ func (a *action) procMsgEth2Chain33(ethBridgeClaim *types2.Eth2Chain33, defaultC
// chain33 -> ethereum
// 返还在chain33上生成的erc20代币
func (a *action) procMsgBurn(msgBurn *types2.Chain33ToEth, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procMsgBurn(msgBurn *types2.Chain33ToEth) (*chain33types.Receipt, error) {
msgBurn.LocalCoinExec = types2.X2ethereumX
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
accDB, err := account.NewAccountDB(a.api.GetConfig(), msgBurn.LocalCoinExec, strings.ToLower(msgBurn.LocalCoinSymbol+msgBurn.TokenContract), a.db)
if err != nil {
return nil, errors.Wrapf(err, "relay procMsgBurn,exec=%s,sym=%s", msgBurn.LocalCoinExec, msgBurn.LocalCoinSymbol)
}
receipt, err := a.keeper.ProcessBurn(a.fromaddr, a.execaddr, msgBurn.Amount, msgBurn.TokenContract, msgBurn.Decimals, accDB)
receipt, err = a.keeper.ProcessBurn(a.fromaddr, a.execaddr, msgBurn.Amount, msgBurn.TokenContract, msgBurn.Decimals, accDB)
if err != nil {
return nil, err
}
......@@ -237,20 +239,25 @@ func (a *action) procMsgBurn(msgBurn *types2.Chain33ToEth, defaultCon bool) (*ch
})}
receipt.Logs = append(receipt.Logs, execlog)
msgBurnBytes, err := json.Marshal(msgBurn)
msgBurnBytes, err := proto.Marshal(msgBurn)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{Key: types2.CalWithdrawChain33Prefix(), Value: msgBurnBytes})
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procMsgLock(msgLock *types2.Chain33ToEth) (*chain33types.Receipt, error) {
msgLock.LocalCoinExec = types2.X2ethereumX
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
......@@ -258,18 +265,28 @@ func (a *action) procMsgBurn(msgBurn *types2.Chain33ToEth, defaultCon bool) (*ch
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procMsgLock(msgLock *types2.Chain33ToEth, defaultCon bool) (*chain33types.Receipt, error) {
msgLock.LocalCoinExec = types2.X2ethereumX
accDB := account.NewCoinsAccount(a.api.GetConfig())
accDB.SetDB(a.db)
receipt, err := a.keeper.ProcessLock(a.fromaddr, address.ExecAddress(msgLock.LocalCoinSymbol), a.execaddr, msgLock.Amount, accDB)
receipt, err = a.keeper.ProcessLock(a.fromaddr, address.ExecAddress(msgLock.LocalCoinSymbol), a.execaddr, msgLock.Amount, accDB)
if err != nil {
return nil, err
}
......@@ -284,108 +301,79 @@ func (a *action) procMsgLock(msgLock *types2.Chain33ToEth, defaultCon bool) (*ch
})}
receipt.Logs = append(receipt.Logs, execlog)
msgLockBytes, err := json.Marshal(msgLock)
msgLockBytes, err := proto.Marshal(msgLock)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{Key: types2.CalChain33ToEthPrefix(), Value: msgLockBytes})
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
// ethereum -> chain33
// burn
func (a *action) procWithdrawEth(withdrawEth *types2.Eth2Chain33, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procWithdrawEth(withdrawEth *types2.Eth2Chain33) (*chain33types.Receipt, error) {
elog.Info("procWithdrawEth", "receive a procWithdrawEth tx", "start")
receipt := new(chain33types.Receipt)
msgWithdrawEth := ethbridge.NewMsgCreateEthBridgeClaim(*withdrawEth)
if err := msgWithdrawEth.ValidateBasic(); err != nil {
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
status, err := a.keeper.ProcessClaim(*withdrawEth)
if err != nil {
return nil, err
}
ID := strconv.Itoa(int(msgWithdrawEth.EthereumChainID)) + strconv.Itoa(int(msgWithdrawEth.Nonce)) + msgWithdrawEth.EthereumSender + "burn"
ID := strconv.Itoa(int(withdrawEth.EthereumChainID)) + strconv.Itoa(int(withdrawEth.Nonce)) + withdrawEth.EthereumSender + withdrawEth.TokenContractAddress + "burn"
//记录ethProphecy
bz, err := a.db.Get(types2.CalProphecyPrefix())
bz, err := a.db.Get(types2.CalProphecyPrefix(ID))
if err != nil {
return nil, types2.ErrProphecyGet
}
var dbProphecys []oracle.DBProphecy
var dbProphecy oracle.DBProphecy
err = json.Unmarshal(bz, &dbProphecys)
var dbProphecy types2.ReceiptEthProphecy
err = proto.Unmarshal(bz, &dbProphecy)
if err != nil {
return nil, chain33types.ErrUnmarshal
}
for _, p := range dbProphecys {
if p.ID == ID {
dbProphecy = p
break
}
}
dRes, err := dbProphecy.DeserializeFromDB()
if err != nil {
return nil, err
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalProphecyPrefix(),
Key: types2.CalProphecyPrefix(ID),
Value: bz,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TyProphecyLog, Log: chain33types.Encode(&types2.ReceiptEthProphecy{
ID: dRes.ID,
Status: &types2.ProphecyStatus{
Text: types2.EthBridgeStatus(dRes.Status.Text),
FinalClaim: dRes.Status.FinalClaim,
},
ClaimValidators: dRes.ClaimValidators,
ValidatorClaims: dRes.ValidatorClaims,
})})
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TyProphecyLog, Log: chain33types.Encode(&dbProphecy)})
if status.Text == oracle.StatusText(types2.EthBridgeStatus_WithdrawedStatusText) {
if status.Text == types2.EthBridgeStatus_SuccessStatusText {
accDB := account.NewCoinsAccount(a.api.GetConfig())
accDB.SetDB(a.db)
r, err := a.keeper.ProcessSuccessfulClaimForBurn(status.FinalClaim, a.execaddr, withdrawEth.LocalCoinSymbol, accDB)
......@@ -395,28 +383,28 @@ func (a *action) procWithdrawEth(withdrawEth *types2.Eth2Chain33, defaultCon boo
receipt.KV = append(receipt.KV, r.KV...)
receipt.Logs = append(receipt.Logs, r.Logs...)
msgWithdrawEthBytes, err := json.Marshal(msgWithdrawEth)
msgWithdrawEthBytes, err := proto.Marshal(withdrawEth)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{Key: types2.CalWithdrawEthPrefix(), Value: msgWithdrawEthBytes})
execlog := &chain33types.ReceiptLog{Ty: types2.TyWithdrawEthLog, Log: chain33types.Encode(&types2.ReceiptEth2Chain33{
EthereumChainID: msgWithdrawEth.EthereumChainID,
BridgeContractAddress: msgWithdrawEth.BridgeContractAddress,
Nonce: msgWithdrawEth.Nonce,
LocalCoinSymbol: msgWithdrawEth.LocalCoinSymbol,
LocalCoinExec: msgWithdrawEth.LocalCoinExec,
TokenContractAddress: msgWithdrawEth.TokenContractAddress,
EthereumSender: msgWithdrawEth.EthereumSender,
Chain33Receiver: msgWithdrawEth.Chain33Receiver,
ValidatorAddress: msgWithdrawEth.ValidatorAddress,
Amount: msgWithdrawEth.Amount,
ClaimType: msgWithdrawEth.ClaimType,
EthereumChainID: withdrawEth.EthereumChainID,
BridgeContractAddress: withdrawEth.BridgeContractAddress,
Nonce: withdrawEth.Nonce,
LocalCoinSymbol: withdrawEth.LocalCoinSymbol,
LocalCoinExec: withdrawEth.LocalCoinExec,
TokenContractAddress: withdrawEth.TokenContractAddress,
EthereumSender: withdrawEth.EthereumSender,
Chain33Receiver: withdrawEth.Chain33Receiver,
ValidatorAddress: withdrawEth.ValidatorAddress,
Amount: withdrawEth.Amount,
ClaimType: withdrawEth.ClaimType,
XTxHash: a.txhash,
XHeight: uint64(a.height),
ProphecyID: ID,
Decimals: msgWithdrawEth.Decimals,
Decimals: withdrawEth.Decimals,
})}
receipt.Logs = append(receipt.Logs, execlog)
......@@ -426,33 +414,48 @@ func (a *action) procWithdrawEth(withdrawEth *types2.Eth2Chain33, defaultCon boo
return receipt, nil
}
func (a *action) procMsgTransfer(msgTransfer *chain33types.AssetsTransfer, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procMsgTransfer(msgTransfer *chain33types.AssetsTransfer) (*chain33types.Receipt, error) {
token := msgTransfer.GetCointoken()
accDB, err := account.NewAccountDB(a.api.GetConfig(), types2.X2ethereumX, token, a.db)
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
return nil, err
}
receipt, err := accDB.ExecTransfer(a.fromaddr, msgTransfer.To, address.ExecAddress(types2.X2ethereumX), msgTransfer.Amount)
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, err
return nil, chain33types.ErrMarshal
}
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
return nil, err
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
accDB, err := account.NewAccountDB(a.api.GetConfig(), types2.X2ethereumX, token, a.db)
if err != nil {
return nil, err
}
receipt, err = accDB.ExecTransfer(a.fromaddr, msgTransfer.To, address.ExecAddress(types2.X2ethereumX), msgTransfer.Amount)
if err != nil {
return nil, err
}
receipt.Ty = chain33types.ExecOk
......@@ -462,10 +465,46 @@ func (a *action) procMsgTransfer(msgTransfer *chain33types.AssetsTransfer, defau
//需要一笔交易来注册validator
//这里注册的validator的power之和可能不为1,需要在内部进行加权
//返回的回执中,KV包含所有validator的power值,Log中包含本次注册的validator的power值
func (a *action) procAddValidator(msgAddValidator *types2.MsgValidator, defaultCon bool) (*chain33types.Receipt, error) {
func (a *action) procAddValidator(msgAddValidator *types2.MsgValidator) (*chain33types.Receipt, error) {
elog.Info("procAddValidator", "start", msgAddValidator)
receipt := new(chain33types.Receipt)
receipt, err := a.keeper.ProcessAddValidator(msgAddValidator.Address, msgAddValidator.Power)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
if !types2.CheckPower(msgAddValidator.Power) {
return nil, types2.ErrInvalidPower
}
receipt, err = a.keeper.ProcessAddValidator(msgAddValidator.Address, msgAddValidator.Power)
if err != nil {
return nil, err
}
......@@ -478,14 +517,18 @@ func (a *action) procAddValidator(msgAddValidator *types2.MsgValidator, defaultC
})}
receipt.Logs = append(receipt.Logs, execlog)
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procRemoveValidator(msgRemoveValidator *types2.MsgValidator) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
......@@ -493,17 +536,26 @@ func (a *action) procAddValidator(msgAddValidator *types2.MsgValidator, defaultC
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procRemoveValidator(msgRemoveValidator *types2.MsgValidator, defaultCon bool) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
receipt, err := a.keeper.ProcessRemoveValidator(msgRemoveValidator.Address)
receipt, err = a.keeper.ProcessRemoveValidator(msgRemoveValidator.Address)
if err != nil {
return nil, err
}
......@@ -516,14 +568,18 @@ func (a *action) procRemoveValidator(msgRemoveValidator *types2.MsgValidator, de
})}
receipt.Logs = append(receipt.Logs, execlog)
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procModifyValidator(msgModifyValidator *types2.MsgValidator) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
consensusNeededBytes, err := a.db.Get(types2.CalConsensusThresholdPrefix())
if err != nil {
if err == chain33types.ErrNotFound {
setConsensusThreshold := &types2.ReceiptQueryConsensusThreshold{ConsensusThreshold: types2.DefaultConsensusNeeded}
msgSetConsensusThresholdBytes, err := proto.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
......@@ -531,17 +587,30 @@ func (a *action) procRemoveValidator(msgRemoveValidator *types2.MsgValidator, de
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
consensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(consensusThreshold)})
} else {
return nil, err
}
} else {
var mc types2.ReceiptQueryConsensusThreshold
_ = proto.Unmarshal(consensusNeededBytes, &mc)
_, _, err = a.keeper.ProcessSetConsensusNeeded(mc.ConsensusThreshold)
if err != nil {
return nil, err
}
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procModifyValidator(msgModifyValidator *types2.MsgValidator, defaultCon bool) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
if !types2.CheckPower(msgModifyValidator.Power) {
return nil, types2.ErrInvalidPower
}
receipt, err := a.keeper.ProcessModifyValidator(msgModifyValidator.Address, msgModifyValidator.Power)
receipt, err = a.keeper.ProcessModifyValidator(msgModifyValidator.Address, msgModifyValidator.Power)
if err != nil {
return nil, err
}
......@@ -554,30 +623,15 @@ func (a *action) procModifyValidator(msgModifyValidator *types2.MsgValidator, de
})}
receipt.Logs = append(receipt.Logs, execlog)
if defaultCon {
setConsensusThreshold := &types2.ReceiptSetConsensusThreshold{
PreConsensusThreshold: int64(0),
NowConsensusThreshold: types2.DefaultConsensusNeeded,
XTxHash: a.txhash,
XHeight: uint64(a.height),
}
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
if err != nil {
return nil, chain33types.ErrMarshal
}
receipt.KV = append(receipt.KV, &chain33types.KeyValue{
Key: types2.CalConsensusThresholdPrefix(),
Value: msgSetConsensusThresholdBytes,
})
receipt.Logs = append(receipt.Logs, &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)})
}
receipt.Ty = chain33types.ExecOk
return receipt, nil
}
func (a *action) procMsgSetConsensusThreshold(msgSetConsensusThreshold *types2.MsgConsensusThreshold) (*chain33types.Receipt, error) {
receipt := new(chain33types.Receipt)
if !types2.CheckPower(msgSetConsensusThreshold.ConsensusThreshold) {
return nil, types2.ErrInvalidPower
}
preConsensusNeeded, nowConsensusNeeded, err := a.keeper.ProcessSetConsensusNeeded(msgSetConsensusThreshold.ConsensusThreshold)
if err != nil {
......@@ -593,7 +647,9 @@ func (a *action) procMsgSetConsensusThreshold(msgSetConsensusThreshold *types2.M
execlog := &chain33types.ReceiptLog{Ty: types2.TySetConsensusThresholdLog, Log: chain33types.Encode(setConsensusThreshold)}
receipt.Logs = append(receipt.Logs, execlog)
msgSetConsensusThresholdBytes, err := json.Marshal(setConsensusThreshold)
msgSetConsensusThresholdBytes, err := proto.Marshal(&types2.ReceiptQueryConsensusThreshold{
ConsensusThreshold: nowConsensusNeeded,
})
if err != nil {
return nil, chain33types.ErrMarshal
}
......
......@@ -8,7 +8,6 @@ enum EthBridgeStatus {
PendingStatusText = 0;
SuccessStatusText = 1;
FailedStatusText = 2;
WithdrawedStatusText = 3;
}
message X2ethereumAction {
......@@ -138,6 +137,10 @@ message StringMap {
repeated string validators = 1;
}
message ValidatorList {
repeated MsgValidator validators = 1;
}
message ProphecyStatus {
EthBridgeStatus Text = 1;
string FinalClaim = 2;
......
# 测试流程
1. 起eth节点
```
cd /opt/src/github.com/cosmos/peggy/testnet-contracts
truffle develop
```
2. 起chain33节点
```
make docker-compose
```
3. 修改配置项,起relayer
修改 chain33Host,BridgeRegistry,pushHost,operatorAddr,deployerPrivateKey,validatorsAddr
注意:
BridgeRegistry 需要先起relayer然后部署完成后才有,然后停掉relayer,重新跑
4. 修改脚本中的私钥,跑部署脚本
```
./bridgeBankTest.sh
```
5. 在ethereum上发行bty
```
./ebcli_A relayer ethereum token4chain33 -s bty
```
6. 跑测试用例
```
./test.sh
```
7. 查询ispending的prophecy
```
./ebcli_A relayer ethereum ispending -i 1
```
8. 处理这个prophecy
```
./ebcli_A relayer ethereum process -i 1
```
9. 查询余额
```
./ebcli_A relayer ethereum balance -o 0x7B95B6EC7EbD73572298cEf32Bb54FA408207359 -a 0xbAf2646b8DaD8776fc74Bf4C8d59E6fB3720eddf
```
......@@ -287,6 +287,33 @@ function updata_relayer_toml() {
#sed -i 's/192.168.3.156/'${pushHost}'/g' "../build/relayer.toml"
}
# 更新配置文件 $1 为 BridgeRegistry 合约地址; $2 等待区块 默认10; $3 relayer.toml 地址
function updata_relayer_toml_ropston() {
local BridgeRegistry=${1}
local maturityDegree=${2}
local file=${3}
local chain33Host=127.0.0.1
local pushHost=127.0.0.1
local line=$(delete_line_show ${file} "chain33Host")
# 在第 line 行后面 新增合约地址
sed -i ''${line}' a chain33Host="http://'${chain33Host}':8801"' "${file}"
line=$(delete_line_show ${file} "pushHost")
sed -i ''${line}' a pushHost="http://'${pushHost}':20000"' "${file}"
line=$(delete_line_show ${file} "BridgeRegistry")
sed -i ''${line}' a BridgeRegistry="'${BridgeRegistry}'"' "${file}"
sed -i 's/EthMaturityDegree=10/'EthMaturityDegree=${maturityDegree}'/g' "${file}"
sed -i 's/maturityDegree=10/'maturityDegree=${maturityDegree}'/g' "${file}"
#sed -i 's/#BridgeRegistry=\"0x40BFE5eD039A9a2Eb42ece2E2CA431bFa7Cf4c42\"/BridgeRegistry=\"'${BridgeRegistry}'\"/g' "../build/relayer.toml"
#sed -i 's/192.168.64.2/'${chain33Host}'/g' "../build/relayer.toml"
#sed -i 's/192.168.3.156/'${pushHost}'/g' "../build/relayer.toml"
}
# 更新 B C D 的配置文件
function updata_all_relayer_toml() {
local port=9901
......@@ -409,7 +436,7 @@ function wait_prophecy_finish() {
set -x
}
# eth 区块等待 $1:等待高度
# eth 区块等待 $1:等待高度 $2:url地址,默认为 http://localhost:7545,测试网络用 https://ropsten-rpc.linkpool.io/
function eth_block_wait() {
set +x
if [[ $# -lt 0 ]]; then
......@@ -417,11 +444,24 @@ function eth_block_wait() {
exit 1
fi
local cur_height=$(curl -ksd '{"id":1,"jsonrpc":"2.0","method":"eth_blockNumber","params":[]}' http://localhost:7545 | jq -r ".result")
local cur_height=""
local new_height=""
local url=${2}
if [ "${url}" == "" ]; then
cur_height=$(curl -ksd '{"id":1,"jsonrpc":"2.0","method":"eth_blockNumber","params":[]}' http://localhost:7545 | jq -r ".result")
else
cur_height=$(curl -H "Content-Type: application/json" -X POST --data '{"id":1,"jsonrpc":"2.0","method":"eth_blockNumber","params":[]}' ${url} | jq -r ".result")
fi
local expect=$((cur_height + ${1} + 1))
local count=0
while true; do
if [ "${url}" == "" ]; then
new_height=$(curl -ksd '{"id":1,"jsonrpc":"2.0","method":"eth_blockNumber","params":[]}' http://localhost:7545 | jq -r ".result")
else
new_height=$(curl -H "Content-Type: application/json" -X POST --data '{"id":1,"jsonrpc":"2.0","method":"eth_blockNumber","params":[]}' ${url} | jq -r ".result")
fi
if [[ ${new_height} -ge ${expect} ]]; then
break
fi
......
......@@ -27,6 +27,7 @@ var (
ErrAddressExists = errors.New("This address already exists")
ErrInvalidAdminAddress = errors.New("This address is not admin address")
ErrClaimInconsist = errors.New("This claim does not consist with others")
ErrInvalidPower = errors.New("This power is invalid")
)
//common
......
......@@ -15,8 +15,8 @@ var (
KeyPrefixLocalDB = "LODB-x2ethereum-"
)
func CalProphecyPrefix() []byte {
return []byte(KeyPrefixStateDB + string(ProphecyKey))
func CalProphecyPrefix(id string) []byte {
return []byte(KeyPrefixStateDB + string(ProphecyKey) + id)
}
func CalEth2Chain33Prefix() []byte {
......
......@@ -95,3 +95,10 @@ func TrimZeroAndDot(s string) string {
return s
}
func CheckPower(power int64) bool {
if power <= 0 || power > 100 {
return false
}
return true
}
......@@ -30,21 +30,18 @@ const (
EthBridgeStatus_PendingStatusText EthBridgeStatus = 0
EthBridgeStatus_SuccessStatusText EthBridgeStatus = 1
EthBridgeStatus_FailedStatusText EthBridgeStatus = 2
EthBridgeStatus_WithdrawedStatusText EthBridgeStatus = 3
)
var EthBridgeStatus_name = map[int32]string{
0: "PendingStatusText",
1: "SuccessStatusText",
2: "FailedStatusText",
3: "WithdrawedStatusText",
}
var EthBridgeStatus_value = map[string]int32{
"PendingStatusText": 0,
"SuccessStatusText": 1,
"FailedStatusText": 2,
"WithdrawedStatusText": 3,
}
func (x EthBridgeStatus) String() string {
......@@ -1207,6 +1204,45 @@ func (m *StringMap) GetValidators() []string {
return nil
}
type ValidatorList struct {
Validators []*MsgValidator `protobuf:"bytes,1,rep,name=validators,proto3" json:"validators,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ValidatorList) Reset() { *m = ValidatorList{} }
func (m *ValidatorList) String() string { return proto.CompactTextString(m) }
func (*ValidatorList) ProtoMessage() {}
func (*ValidatorList) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{15}
}
func (m *ValidatorList) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ValidatorList.Unmarshal(m, b)
}
func (m *ValidatorList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ValidatorList.Marshal(b, m, deterministic)
}
func (m *ValidatorList) XXX_Merge(src proto.Message) {
xxx_messageInfo_ValidatorList.Merge(m, src)
}
func (m *ValidatorList) XXX_Size() int {
return xxx_messageInfo_ValidatorList.Size(m)
}
func (m *ValidatorList) XXX_DiscardUnknown() {
xxx_messageInfo_ValidatorList.DiscardUnknown(m)
}
var xxx_messageInfo_ValidatorList proto.InternalMessageInfo
func (m *ValidatorList) GetValidators() []*MsgValidator {
if m != nil {
return m.Validators
}
return nil
}
type ProphecyStatus struct {
Text EthBridgeStatus `protobuf:"varint,1,opt,name=Text,proto3,enum=types.EthBridgeStatus" json:"Text,omitempty"`
FinalClaim string `protobuf:"bytes,2,opt,name=FinalClaim,proto3" json:"FinalClaim,omitempty"`
......@@ -1219,7 +1255,7 @@ func (m *ProphecyStatus) Reset() { *m = ProphecyStatus{} }
func (m *ProphecyStatus) String() string { return proto.CompactTextString(m) }
func (*ProphecyStatus) ProtoMessage() {}
func (*ProphecyStatus) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{15}
return fileDescriptor_1dd1834a817ceb21, []int{16}
}
func (m *ProphecyStatus) XXX_Unmarshal(b []byte) error {
......@@ -1265,7 +1301,7 @@ func (m *QueryValidatorsParams) Reset() { *m = QueryValidatorsParams{} }
func (m *QueryValidatorsParams) String() string { return proto.CompactTextString(m) }
func (*QueryValidatorsParams) ProtoMessage() {}
func (*QueryValidatorsParams) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{16}
return fileDescriptor_1dd1834a817ceb21, []int{17}
}
func (m *QueryValidatorsParams) XXX_Unmarshal(b []byte) error {
......@@ -1305,7 +1341,7 @@ func (m *ReceiptQueryValidator) Reset() { *m = ReceiptQueryValidator{} }
func (m *ReceiptQueryValidator) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryValidator) ProtoMessage() {}
func (*ReceiptQueryValidator) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{17}
return fileDescriptor_1dd1834a817ceb21, []int{18}
}
func (m *ReceiptQueryValidator) XXX_Unmarshal(b []byte) error {
......@@ -1350,7 +1386,7 @@ func (m *QueryTotalPowerParams) Reset() { *m = QueryTotalPowerParams{} }
func (m *QueryTotalPowerParams) String() string { return proto.CompactTextString(m) }
func (*QueryTotalPowerParams) ProtoMessage() {}
func (*QueryTotalPowerParams) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{18}
return fileDescriptor_1dd1834a817ceb21, []int{19}
}
func (m *QueryTotalPowerParams) XXX_Unmarshal(b []byte) error {
......@@ -1382,7 +1418,7 @@ func (m *ReceiptQueryTotalPower) Reset() { *m = ReceiptQueryTotalPower{}
func (m *ReceiptQueryTotalPower) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryTotalPower) ProtoMessage() {}
func (*ReceiptQueryTotalPower) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{19}
return fileDescriptor_1dd1834a817ceb21, []int{20}
}
func (m *ReceiptQueryTotalPower) XXX_Unmarshal(b []byte) error {
......@@ -1420,7 +1456,7 @@ func (m *QueryConsensusThresholdParams) Reset() { *m = QueryConsensusThr
func (m *QueryConsensusThresholdParams) String() string { return proto.CompactTextString(m) }
func (*QueryConsensusThresholdParams) ProtoMessage() {}
func (*QueryConsensusThresholdParams) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{20}
return fileDescriptor_1dd1834a817ceb21, []int{21}
}
func (m *QueryConsensusThresholdParams) XXX_Unmarshal(b []byte) error {
......@@ -1452,7 +1488,7 @@ func (m *ReceiptQueryConsensusThreshold) Reset() { *m = ReceiptQueryCons
func (m *ReceiptQueryConsensusThreshold) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryConsensusThreshold) ProtoMessage() {}
func (*ReceiptQueryConsensusThreshold) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{21}
return fileDescriptor_1dd1834a817ceb21, []int{22}
}
func (m *ReceiptQueryConsensusThreshold) XXX_Unmarshal(b []byte) error {
......@@ -1495,7 +1531,7 @@ func (m *QuerySymbolAssetsByTxTypeParams) Reset() { *m = QuerySymbolAsse
func (m *QuerySymbolAssetsByTxTypeParams) String() string { return proto.CompactTextString(m) }
func (*QuerySymbolAssetsByTxTypeParams) ProtoMessage() {}
func (*QuerySymbolAssetsByTxTypeParams) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{22}
return fileDescriptor_1dd1834a817ceb21, []int{23}
}
func (m *QuerySymbolAssetsByTxTypeParams) XXX_Unmarshal(b []byte) error {
......@@ -1562,7 +1598,7 @@ func (m *ReceiptQuerySymbolAssets) Reset() { *m = ReceiptQuerySymbolAsse
func (m *ReceiptQuerySymbolAssets) String() string { return proto.CompactTextString(m) }
func (*ReceiptQuerySymbolAssets) ProtoMessage() {}
func (*ReceiptQuerySymbolAssets) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{23}
return fileDescriptor_1dd1834a817ceb21, []int{24}
}
func (m *ReceiptQuerySymbolAssets) XXX_Unmarshal(b []byte) error {
......@@ -1605,7 +1641,7 @@ func (m *ReceiptQuerySymbolAssetsByTxType) Reset() { *m = ReceiptQuerySy
func (m *ReceiptQuerySymbolAssetsByTxType) String() string { return proto.CompactTextString(m) }
func (*ReceiptQuerySymbolAssetsByTxType) ProtoMessage() {}
func (*ReceiptQuerySymbolAssetsByTxType) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{24}
return fileDescriptor_1dd1834a817ceb21, []int{25}
}
func (m *ReceiptQuerySymbolAssetsByTxType) XXX_Unmarshal(b []byte) error {
......@@ -1674,7 +1710,7 @@ func (m *QueryRelayerBalance) Reset() { *m = QueryRelayerBalance{} }
func (m *QueryRelayerBalance) String() string { return proto.CompactTextString(m) }
func (*QueryRelayerBalance) ProtoMessage() {}
func (*QueryRelayerBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{25}
return fileDescriptor_1dd1834a817ceb21, []int{26}
}
func (m *QueryRelayerBalance) XXX_Unmarshal(b []byte) error {
......@@ -1727,7 +1763,7 @@ func (m *ReceiptQueryRelayerBalance) Reset() { *m = ReceiptQueryRelayerB
func (m *ReceiptQueryRelayerBalance) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryRelayerBalance) ProtoMessage() {}
func (*ReceiptQueryRelayerBalance) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{26}
return fileDescriptor_1dd1834a817ceb21, []int{27}
}
func (m *ReceiptQueryRelayerBalance) XXX_Unmarshal(b []byte) error {
......@@ -1768,7 +1804,7 @@ func (m *ReceiptQueryRelayerBalanceForOneToken) Reset() { *m = ReceiptQu
func (m *ReceiptQueryRelayerBalanceForOneToken) String() string { return proto.CompactTextString(m) }
func (*ReceiptQueryRelayerBalanceForOneToken) ProtoMessage() {}
func (*ReceiptQueryRelayerBalanceForOneToken) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{27}
return fileDescriptor_1dd1834a817ceb21, []int{28}
}
func (m *ReceiptQueryRelayerBalanceForOneToken) XXX_Unmarshal(b []byte) error {
......@@ -1821,7 +1857,7 @@ func (m *ReceiptTokenToTokenAddress) Reset() { *m = ReceiptTokenToTokenA
func (m *ReceiptTokenToTokenAddress) String() string { return proto.CompactTextString(m) }
func (*ReceiptTokenToTokenAddress) ProtoMessage() {}
func (*ReceiptTokenToTokenAddress) Descriptor() ([]byte, []int) {
return fileDescriptor_1dd1834a817ceb21, []int{28}
return fileDescriptor_1dd1834a817ceb21, []int{29}
}
func (m *ReceiptTokenToTokenAddress) XXX_Unmarshal(b []byte) error {
......@@ -1866,6 +1902,7 @@ func init() {
proto.RegisterType((*ClaimValidators)(nil), "types.ClaimValidators")
proto.RegisterType((*ValidatorClaims)(nil), "types.ValidatorClaims")
proto.RegisterType((*StringMap)(nil), "types.StringMap")
proto.RegisterType((*ValidatorList)(nil), "types.ValidatorList")
proto.RegisterType((*ProphecyStatus)(nil), "types.ProphecyStatus")
proto.RegisterType((*QueryValidatorsParams)(nil), "types.QueryValidatorsParams")
proto.RegisterType((*ReceiptQueryValidator)(nil), "types.ReceiptQueryValidator")
......@@ -1887,91 +1924,92 @@ func init() {
}
var fileDescriptor_1dd1834a817ceb21 = []byte{
// 1344 bytes of a gzipped FileDescriptorProto
// 1346 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x58, 0xcb, 0x6e, 0xdb, 0x46,
0x17, 0x36, 0x45, 0x49, 0x0e, 0x8f, 0x14, 0x5b, 0x99, 0x58, 0xfe, 0x09, 0xc3, 0x7f, 0x22, 0x10,
0xbd, 0x18, 0x69, 0x6b, 0x14, 0x76, 0x7a, 0xc9, 0x26, 0x8d, 0x2d, 0x2b, 0x75, 0x16, 0x69, 0xdc,
0x11, 0x7b, 0x03, 0xb2, 0x19, 0x93, 0x13, 0x93, 0x28, 0x45, 0x0a, 0xe4, 0xc8, 0x96, 0x96, 0xdd,
0x76, 0xd5, 0x57, 0x69, 0x97, 0x5d, 0xf4, 0x35, 0xb2, 0xec, 0xab, 0x14, 0x33, 0x1c, 0x92, 0x43,
0x8a, 0x56, 0x8c, 0xa0, 0x8b, 0x16, 0xe8, 0x72, 0xbe, 0x73, 0xfb, 0xce, 0x65, 0x0e, 0x47, 0x82,
0xde, 0xfc, 0x80, 0x32, 0x8f, 0xc6, 0x74, 0x36, 0xd9, 0x9f, 0xc6, 0x11, 0x8b, 0x50, 0x8b, 0x2d,
0xa6, 0x34, 0xd9, 0xb9, 0xc3, 0x62, 0x12, 0x26, 0xc4, 0x61, 0x7e, 0x14, 0xa6, 0x92, 0x9d, 0xdb,
0xc4, 0x71, 0xa2, 0x59, 0xc8, 0xd2, 0xa3, 0xf5, 0xba, 0x09, 0xbd, 0xef, 0x73, 0xeb, 0x23, 0xa1,
0x89, 0x3e, 0x85, 0x0e, 0x65, 0xde, 0xc1, 0xd0, 0x23, 0x7e, 0x78, 0x78, 0x68, 0x6a, 0x03, 0x6d,
0xaf, 0x73, 0x80, 0xf6, 0x85, 0xcf, 0xfd, 0x51, 0x21, 0x39, 0x5d, 0xc3, 0xaa, 0x22, 0xb7, 0xbb,
0xf2, 0x99, 0xe7, 0xc6, 0xe4, 0x6a, 0xc4, 0x3c, 0xb3, 0xb1, 0xca, 0x4e, 0x51, 0x44, 0x5f, 0xc0,
0x66, 0x76, 0xcc, 0x62, 0xea, 0xc2, 0xf6, 0xae, 0xb4, 0x95, 0xa8, 0x1d, 0x8d, 0x98, 0x77, 0xba,
0x86, 0xab, 0xda, 0xe8, 0x11, 0x74, 0x1d, 0x45, 0xc5, 0x6c, 0xae, 0xb2, 0x2e, 0xa9, 0x72, 0x53,
0xe2, 0xba, 0xdf, 0x92, 0xc0, 0x77, 0x09, 0x8b, 0x62, 0xb3, 0x55, 0x32, 0x7d, 0x9e, 0x5c, 0xe4,
0x22, 0x6e, 0xaa, 0xaa, 0x72, 0xda, 0x31, 0x9d, 0x44, 0x97, 0xb4, 0xb0, 0x6e, 0xaf, 0xb2, 0xae,
0x6a, 0xa3, 0xcf, 0xa0, 0x33, 0x89, 0x5c, 0xff, 0xd5, 0xe2, 0x2c, 0xba, 0xa2, 0xb1, 0xb9, 0xbe,
0xca, 0x58, 0xd5, 0x44, 0x36, 0xf4, 0x13, 0xca, 0x86, 0x51, 0x98, 0xd0, 0x30, 0x99, 0x25, 0xb6,
0x17, 0xd3, 0xc4, 0x8b, 0x02, 0xd7, 0xbc, 0x25, 0x5c, 0xec, 0x16, 0x2e, 0x96, 0x75, 0x4e, 0xd7,
0x70, 0xbd, 0x31, 0x3a, 0x84, 0x5b, 0x62, 0x5e, 0x5e, 0xd1, 0xd8, 0x34, 0x84, 0xa3, 0xbe, 0x74,
0x74, 0x94, 0x24, 0x94, 0x25, 0xb6, 0x14, 0x9e, 0xae, 0xe1, 0x5c, 0x11, 0x6d, 0x40, 0x83, 0x2d,
0x4c, 0x18, 0x68, 0x7b, 0x2d, 0xdc, 0x60, 0x8b, 0xe3, 0x75, 0x68, 0x5d, 0x92, 0x60, 0x46, 0xad,
0x2f, 0xa1, 0x5f, 0x1b, 0x1f, 0xed, 0x03, 0x72, 0x96, 0x99, 0xf3, 0x21, 0xd3, 0x71, 0x8d, 0xc4,
0x7a, 0x0c, 0x5d, 0xb5, 0x16, 0xc8, 0x84, 0x75, 0xe2, 0xba, 0x31, 0x4d, 0x12, 0x61, 0x64, 0xe0,
0xec, 0x88, 0xb6, 0xa0, 0x35, 0x15, 0x95, 0x6c, 0x08, 0x67, 0xe9, 0xc1, 0x7a, 0xad, 0x43, 0x47,
0x19, 0x3e, 0xb4, 0x07, 0x9b, 0x23, 0x39, 0xef, 0x02, 0x7a, 0x76, 0x22, 0x83, 0x57, 0x61, 0xf4,
0x10, 0xfa, 0xc7, 0xb1, 0xef, 0x5e, 0xd0, 0x61, 0x14, 0xb2, 0x98, 0x38, 0xec, 0x48, 0xc6, 0x6d,
0x88, 0xb8, 0xf5, 0x42, 0xce, 0xe2, 0xab, 0x28, 0x74, 0xa8, 0x98, 0x61, 0x1d, 0xa7, 0x07, 0x1e,
0x35, 0x88, 0x1c, 0x12, 0x0c, 0x23, 0x3f, 0x1c, 0x2f, 0x26, 0xe7, 0x51, 0x20, 0xa6, 0xd4, 0xc0,
0x55, 0x18, 0xbd, 0x03, 0xb7, 0x73, 0x68, 0x34, 0xa7, 0x8e, 0x18, 0x49, 0x03, 0x97, 0x41, 0x74,
0x00, 0x5b, 0x76, 0xf4, 0x23, 0x0d, 0xab, 0xd4, 0xda, 0x42, 0xb9, 0x56, 0x86, 0xde, 0x83, 0x8d,
0x2c, 0xc5, 0x31, 0x0d, 0x5d, 0x39, 0x72, 0x06, 0xae, 0xa0, 0x9c, 0xab, 0x2c, 0x16, 0xa6, 0x0e,
0xf5, 0x2f, 0x69, 0x2c, 0x06, 0xcb, 0xc0, 0x55, 0x18, 0x3d, 0x80, 0x5e, 0xde, 0x98, 0x8c, 0x81,
0x21, 0x54, 0x97, 0x70, 0xb4, 0x0d, 0xed, 0xa3, 0x09, 0x5f, 0x3d, 0x62, 0x5a, 0x0c, 0x2c, 0x4f,
0x68, 0x17, 0x8c, 0x61, 0x40, 0xfc, 0x89, 0xbd, 0x98, 0x52, 0xb3, 0x23, 0x6a, 0x56, 0x00, 0x68,
0x07, 0x6e, 0x9d, 0x50, 0xc7, 0x9f, 0x90, 0x20, 0x31, 0xbb, 0x42, 0x98, 0x9f, 0xad, 0x5f, 0x34,
0x40, 0x2f, 0x62, 0xe2, 0x04, 0x54, 0xe8, 0xf3, 0x74, 0x69, 0xc8, 0xea, 0xe8, 0x6b, 0xf5, 0xf4,
0x0b, 0x4a, 0x8d, 0xeb, 0x29, 0xe9, 0xab, 0x28, 0x35, 0x2b, 0x94, 0x7e, 0x6e, 0x40, 0x57, 0xdd,
0x37, 0xbc, 0x9b, 0xa5, 0x5e, 0x48, 0x2a, 0x65, 0x90, 0x6b, 0x49, 0x2b, 0xd9, 0x98, 0x94, 0x4f,
0x19, 0xe4, 0xd5, 0xce, 0x3a, 0x95, 0x67, 0xa6, 0xa7, 0xd5, 0xae, 0xe2, 0x4a, 0x6a, 0xcd, 0x52,
0x6a, 0x35, 0x73, 0xd8, 0xba, 0xe1, 0x1c, 0xb6, 0xeb, 0xe6, 0x50, 0x2d, 0xc6, 0x7a, 0xa5, 0x18,
0xbf, 0x35, 0x01, 0x09, 0x42, 0x53, 0xf6, 0xdf, 0x05, 0xfc, 0xb7, 0x5e, 0x40, 0x13, 0xd6, 0xe7,
0xf6, 0xfc, 0x94, 0x24, 0x9e, 0xb8, 0x7f, 0x5d, 0x9c, 0x1d, 0x85, 0xe4, 0x94, 0xfa, 0x17, 0x1e,
0x33, 0x6f, 0x0f, 0xb4, 0xbd, 0x26, 0xce, 0x8e, 0xe8, 0x1e, 0xc0, 0x59, 0x1c, 0x4d, 0x3d, 0xea,
0x2c, 0x9e, 0x9d, 0x98, 0x1b, 0x22, 0x9a, 0x82, 0x94, 0x86, 0x66, 0xb3, 0x32, 0x34, 0x7f, 0x6a,
0x70, 0x57, 0x0e, 0xcd, 0x3f, 0xfa, 0x22, 0xed, 0x82, 0x31, 0x62, 0x5e, 0xe9, 0x0a, 0x15, 0x40,
0x29, 0xc3, 0x76, 0x25, 0xc3, 0x4b, 0xe8, 0xc9, 0x04, 0xdf, 0xfa, 0xa3, 0xa6, 0x76, 0x45, 0xbf,
0xb6, 0x2b, 0xcd, 0x52, 0x57, 0xac, 0x3f, 0x34, 0xd8, 0x95, 0x81, 0xc7, 0xb5, 0x0f, 0x80, 0x87,
0xd0, 0x9f, 0xc6, 0x74, 0x78, 0xdd, 0xc7, 0xb9, 0x5e, 0xc8, 0xad, 0xc2, 0xe8, 0xaa, 0xc6, 0x2a,
0x25, 0x5c, 0x2f, 0x7c, 0xab, 0x04, 0xf6, 0x60, 0xfb, 0xeb, 0x19, 0x8d, 0x17, 0x23, 0xe6, 0x65,
0xc3, 0x74, 0x46, 0x62, 0x32, 0x49, 0xf8, 0x2b, 0x44, 0x6e, 0x11, 0x03, 0x37, 0x9e, 0x9d, 0x58,
0xaf, 0x35, 0x75, 0xf3, 0x64, 0xca, 0x55, 0x35, 0xf4, 0x11, 0xb4, 0xc7, 0x8c, 0xb0, 0x59, 0x22,
0xdf, 0xaa, 0xd9, 0x7b, 0x27, 0x33, 0x48, 0x85, 0x58, 0x2a, 0xa1, 0x27, 0xb0, 0x29, 0xee, 0x45,
0xde, 0xb6, 0xc4, 0xd4, 0x07, 0xfa, 0x5e, 0xe7, 0x60, 0x3b, 0x7b, 0x69, 0x96, 0xa5, 0xb8, 0xaa,
0xce, 0x3d, 0xe4, 0x27, 0x21, 0xe3, 0x5f, 0x10, 0xd5, 0x43, 0x45, 0x8a, 0xab, 0xea, 0xd6, 0x0f,
0x4b, 0x1c, 0xf8, 0x84, 0x38, 0x1c, 0x92, 0x89, 0xa5, 0x07, 0xf4, 0x31, 0xc0, 0x65, 0xc1, 0x33,
0xcd, 0xaf, 0x27, 0xa3, 0x8c, 0x59, 0xec, 0x87, 0x17, 0xcf, 0xc9, 0x14, 0x2b, 0x3a, 0xd6, 0x68,
0x89, 0x1c, 0x1f, 0xf2, 0x5c, 0x41, 0xba, 0x2f, 0x80, 0x22, 0x70, 0x43, 0x09, 0x6c, 0x7d, 0x00,
0x46, 0xee, 0x9f, 0x6f, 0x02, 0x85, 0x85, 0x36, 0xd0, 0xf9, 0x26, 0x50, 0x62, 0xbe, 0x84, 0x8d,
0x72, 0xb1, 0xd1, 0x03, 0x68, 0xda, 0x74, 0x9e, 0x5e, 0xef, 0x8d, 0xbc, 0x2e, 0x23, 0xe6, 0xa5,
0xcb, 0x5e, 0xb6, 0x44, 0xe8, 0x70, 0xef, 0x4f, 0xfd, 0x90, 0x04, 0x43, 0x85, 0x85, 0x82, 0x58,
0x9f, 0x40, 0x5f, 0x0c, 0x4c, 0x51, 0x2c, 0x39, 0x2f, 0x2b, 0xf3, 0xb2, 0x02, 0xe8, 0xcb, 0xe1,
0x29, 0x5b, 0xa3, 0xc3, 0xa5, 0x6c, 0xea, 0xdf, 0xeb, 0x6a, 0x8a, 0x9c, 0x24, 0x8b, 0x18, 0x09,
0xce, 0x94, 0x5b, 0xac, 0x20, 0xd6, 0xff, 0x24, 0x49, 0x3b, 0x87, 0x52, 0x92, 0xd6, 0xe7, 0xb0,
0xad, 0xd2, 0x28, 0xe4, 0x15, 0x97, 0xda, 0x92, 0xcb, 0xfb, 0xf0, 0x7f, 0x61, 0xb2, 0x7c, 0xef,
0xa4, 0xeb, 0x33, 0xb8, 0xa7, 0xba, 0xfe, 0x1b, 0x5e, 0xe9, 0xbf, 0x6a, 0x70, 0x5f, 0xf8, 0x4a,
0x17, 0x60, 0xfa, 0x8b, 0xe1, 0x78, 0x61, 0xcf, 0xf9, 0x47, 0x44, 0x56, 0x7d, 0x00, 0x1d, 0xc6,
0xb7, 0xb5, 0x5c, 0x9a, 0x69, 0xdd, 0x55, 0x88, 0xf7, 0xc5, 0xf5, 0x63, 0x2a, 0x7e, 0x86, 0xca,
0x52, 0x15, 0x00, 0x5f, 0xc5, 0x6c, 0x9e, 0xbf, 0xc9, 0x0c, 0x2c, 0x4f, 0xdc, 0x4a, 0x38, 0xe1,
0x1f, 0x3a, 0xb9, 0xa5, 0x0b, 0x80, 0xef, 0x13, 0x37, 0x5d, 0xbd, 0x62, 0x4d, 0xeb, 0x38, 0x3b,
0x5a, 0xdf, 0x80, 0xa9, 0x56, 0x41, 0x65, 0x8e, 0x1e, 0x81, 0x1e, 0xd3, 0xac, 0xc7, 0xef, 0xcb,
0x1e, 0x5f, 0xa7, 0x9d, 0xe5, 0x89, 0xb9, 0x8d, 0xf5, 0xbb, 0x06, 0x83, 0x37, 0x69, 0xde, 0xa0,
0x16, 0x42, 0x83, 0x91, 0xa0, 0xf4, 0x42, 0x55, 0xa1, 0x55, 0xf5, 0x28, 0xaa, 0xd8, 0xac, 0x56,
0xb1, 0x54, 0xad, 0x56, 0xa5, 0x5a, 0x56, 0x04, 0x77, 0x05, 0x69, 0x4c, 0x03, 0xb2, 0xa0, 0xf1,
0x31, 0x09, 0x08, 0x7f, 0x3d, 0xbd, 0x99, 0xae, 0xf2, 0x05, 0x6b, 0x94, 0xbf, 0x60, 0xa5, 0x80,
0x7a, 0x35, 0xe0, 0x4b, 0xd8, 0x51, 0x8b, 0x55, 0x89, 0xfb, 0x58, 0x6d, 0xc3, 0x87, 0x35, 0x6d,
0x28, 0xeb, 0x3f, 0x8d, 0xe2, 0x17, 0x21, 0x15, 0x4f, 0x82, 0xb4, 0x17, 0x3f, 0x69, 0xf0, 0xee,
0x8d, 0xd4, 0x39, 0xff, 0xf3, 0x14, 0xcd, 0xbe, 0xc0, 0xe7, 0xf5, 0xb9, 0x37, 0x6a, 0xc7, 0x76,
0x45, 0x86, 0x4f, 0xf2, 0x0c, 0x45, 0x24, 0x3b, 0xb2, 0x33, 0x11, 0xaf, 0x8e, 0x05, 0x5d, 0xa6,
0x9c, 0xe5, 0x8e, 0x2c, 0x61, 0x0f, 0x22, 0xf1, 0x62, 0x56, 0x17, 0x20, 0xea, 0xc3, 0x9d, 0x33,
0x1a, 0xba, 0x7e, 0x78, 0x91, 0x02, 0x7c, 0x1f, 0xf6, 0xd6, 0x38, 0x3c, 0x9e, 0x39, 0x0e, 0x4d,
0x12, 0x05, 0xd6, 0xd0, 0x16, 0xf4, 0x9e, 0x12, 0x3f, 0xa0, 0xae, 0x82, 0x36, 0x90, 0x09, 0x5b,
0xdf, 0xc9, 0x7f, 0x52, 0x4a, 0x12, 0xfd, 0xa0, 0x0b, 0x50, 0xfc, 0xa7, 0x74, 0xde, 0x16, 0xff,
0x15, 0x1d, 0xfe, 0x15, 0x00, 0x00, 0xff, 0xff, 0xb7, 0x6a, 0xa5, 0xfa, 0x68, 0x12, 0x00, 0x00,
0x14, 0x35, 0x45, 0x49, 0x0e, 0xaf, 0x64, 0x5b, 0x99, 0x44, 0x2e, 0x61, 0xb8, 0x89, 0x40, 0xf4,
0x61, 0xa4, 0xad, 0x51, 0xd8, 0xe9, 0x23, 0x9b, 0x34, 0xb6, 0xac, 0xd4, 0x01, 0x9a, 0xc6, 0x1d,
0x31, 0x45, 0x0b, 0x64, 0x33, 0x26, 0x27, 0x26, 0x51, 0x8a, 0x14, 0xc8, 0x91, 0x2d, 0x2d, 0xbb,
0xed, 0xaa, 0xbf, 0xd2, 0x2e, 0xbb, 0xe8, 0x6f, 0x64, 0xd9, 0x5f, 0x29, 0x66, 0x38, 0x24, 0x87,
0x14, 0xad, 0x04, 0x41, 0x17, 0x2d, 0xd0, 0xe5, 0x9c, 0xfb, 0x3a, 0xf7, 0xc1, 0x3b, 0x23, 0x41,
0x6f, 0x7e, 0x40, 0x99, 0x47, 0x63, 0x3a, 0x9b, 0xec, 0x4f, 0xe3, 0x88, 0x45, 0xa8, 0xc5, 0x16,
0x53, 0x9a, 0xec, 0xdc, 0x64, 0x31, 0x09, 0x13, 0xe2, 0x30, 0x3f, 0x0a, 0x53, 0xc9, 0xce, 0x06,
0x71, 0x9c, 0x68, 0x16, 0xb2, 0xf4, 0x68, 0xbd, 0x6a, 0x42, 0xef, 0x87, 0xdc, 0xfa, 0x48, 0x68,
0xa2, 0xcf, 0xa1, 0x43, 0x99, 0x77, 0x30, 0xf4, 0x88, 0x1f, 0x1e, 0x1e, 0x9a, 0xda, 0x40, 0xdb,
0xeb, 0x1c, 0xa0, 0x7d, 0xe1, 0x73, 0x7f, 0x54, 0x48, 0x4e, 0xd7, 0xb0, 0xaa, 0xc8, 0xed, 0xae,
0x7c, 0xe6, 0xb9, 0x31, 0xb9, 0x1a, 0x31, 0xcf, 0x6c, 0xac, 0xb2, 0x53, 0x14, 0xd1, 0x57, 0xb0,
0x95, 0x1d, 0xb3, 0x98, 0xba, 0xb0, 0xbd, 0x25, 0x6d, 0x25, 0x6a, 0x47, 0x23, 0xe6, 0x9d, 0xae,
0xe1, 0xaa, 0x36, 0x7a, 0x00, 0x5d, 0x47, 0x51, 0x31, 0x9b, 0xab, 0xac, 0x4b, 0xaa, 0xdc, 0x94,
0xb8, 0xee, 0xf7, 0x24, 0xf0, 0x5d, 0xc2, 0xa2, 0xd8, 0x6c, 0x95, 0x4c, 0x9f, 0x26, 0x17, 0xb9,
0x88, 0x9b, 0xaa, 0xaa, 0x9c, 0x76, 0x4c, 0x27, 0xd1, 0x25, 0x2d, 0xac, 0xdb, 0xab, 0xac, 0xab,
0xda, 0xe8, 0x0b, 0xe8, 0x4c, 0x22, 0xd7, 0x7f, 0xb9, 0x38, 0x8b, 0xae, 0x68, 0x6c, 0xae, 0xaf,
0x32, 0x56, 0x35, 0x91, 0x0d, 0xfd, 0x84, 0xb2, 0x61, 0x14, 0x26, 0x34, 0x4c, 0x66, 0x89, 0xed,
0xc5, 0x34, 0xf1, 0xa2, 0xc0, 0x35, 0x6f, 0x08, 0x17, 0xbb, 0x85, 0x8b, 0x65, 0x9d, 0xd3, 0x35,
0x5c, 0x6f, 0x8c, 0x0e, 0xe1, 0x86, 0x98, 0x97, 0x97, 0x34, 0x36, 0x0d, 0xe1, 0xa8, 0x2f, 0x1d,
0x1d, 0x25, 0x09, 0x65, 0x89, 0x2d, 0x85, 0xa7, 0x6b, 0x38, 0x57, 0x44, 0x9b, 0xd0, 0x60, 0x0b,
0x13, 0x06, 0xda, 0x5e, 0x0b, 0x37, 0xd8, 0xe2, 0x78, 0x1d, 0x5a, 0x97, 0x24, 0x98, 0x51, 0xeb,
0x6b, 0xe8, 0xd7, 0xc6, 0x47, 0xfb, 0x80, 0x9c, 0x65, 0xe6, 0x7c, 0xc8, 0x74, 0x5c, 0x23, 0xb1,
0x1e, 0x42, 0x57, 0xad, 0x05, 0x32, 0x61, 0x9d, 0xb8, 0x6e, 0x4c, 0x93, 0x44, 0x18, 0x19, 0x38,
0x3b, 0xa2, 0xdb, 0xd0, 0x9a, 0x8a, 0x4a, 0x36, 0x84, 0xb3, 0xf4, 0x60, 0xbd, 0xd2, 0xa1, 0xa3,
0x0c, 0x1f, 0xda, 0x83, 0xad, 0x91, 0x9c, 0x77, 0x01, 0x3d, 0x39, 0x91, 0xc1, 0xab, 0x30, 0xba,
0x0f, 0xfd, 0xe3, 0xd8, 0x77, 0x2f, 0xe8, 0x30, 0x0a, 0x59, 0x4c, 0x1c, 0x76, 0x24, 0xe3, 0x36,
0x44, 0xdc, 0x7a, 0x21, 0x67, 0xf1, 0x6d, 0x14, 0x3a, 0x54, 0xcc, 0xb0, 0x8e, 0xd3, 0x03, 0x8f,
0x1a, 0x44, 0x0e, 0x09, 0x86, 0x91, 0x1f, 0x8e, 0x17, 0x93, 0xf3, 0x28, 0x10, 0x53, 0x6a, 0xe0,
0x2a, 0x8c, 0xde, 0x83, 0x8d, 0x1c, 0x1a, 0xcd, 0xa9, 0x23, 0x46, 0xd2, 0xc0, 0x65, 0x10, 0x1d,
0xc0, 0x6d, 0x3b, 0xfa, 0x89, 0x86, 0x55, 0x6a, 0x6d, 0xa1, 0x5c, 0x2b, 0x43, 0x1f, 0xc0, 0x66,
0x96, 0xe2, 0x98, 0x86, 0xae, 0x1c, 0x39, 0x03, 0x57, 0x50, 0xce, 0x55, 0x16, 0x0b, 0x53, 0x87,
0xfa, 0x97, 0x34, 0x16, 0x83, 0x65, 0xe0, 0x2a, 0x8c, 0xee, 0x41, 0x2f, 0x6f, 0x4c, 0xc6, 0xc0,
0x10, 0xaa, 0x4b, 0x38, 0xda, 0x86, 0xf6, 0xd1, 0x84, 0xaf, 0x1e, 0x31, 0x2d, 0x06, 0x96, 0x27,
0xb4, 0x0b, 0xc6, 0x30, 0x20, 0xfe, 0xc4, 0x5e, 0x4c, 0xa9, 0xd9, 0x11, 0x35, 0x2b, 0x00, 0xb4,
0x03, 0x37, 0x4e, 0xa8, 0xe3, 0x4f, 0x48, 0x90, 0x98, 0x5d, 0x21, 0xcc, 0xcf, 0xd6, 0xaf, 0x1a,
0xa0, 0x67, 0x31, 0x71, 0x02, 0x2a, 0xf4, 0x79, 0xba, 0x34, 0x64, 0x75, 0xf4, 0xb5, 0x7a, 0xfa,
0x05, 0xa5, 0xc6, 0xf5, 0x94, 0xf4, 0x55, 0x94, 0x9a, 0x15, 0x4a, 0xbf, 0x34, 0xa0, 0xab, 0xee,
0x1b, 0xde, 0xcd, 0x52, 0x2f, 0x24, 0x95, 0x32, 0xc8, 0xb5, 0xa4, 0x95, 0x6c, 0x4c, 0xca, 0xa7,
0x0c, 0xf2, 0x6a, 0x67, 0x9d, 0xca, 0x33, 0xd3, 0xd3, 0x6a, 0x57, 0x71, 0x25, 0xb5, 0x66, 0x29,
0xb5, 0x9a, 0x39, 0x6c, 0xbd, 0xe1, 0x1c, 0xb6, 0xeb, 0xe6, 0x50, 0x2d, 0xc6, 0x7a, 0xa5, 0x18,
0xbf, 0x37, 0x01, 0x09, 0x42, 0x53, 0xf6, 0xff, 0x07, 0xf8, 0x5f, 0xfd, 0x00, 0x4d, 0x58, 0x9f,
0xdb, 0xf3, 0x53, 0x92, 0x78, 0xe2, 0xfb, 0xeb, 0xe2, 0xec, 0x28, 0x24, 0xa7, 0xd4, 0xbf, 0xf0,
0x98, 0xb9, 0x31, 0xd0, 0xf6, 0x9a, 0x38, 0x3b, 0xa2, 0x3b, 0x00, 0x67, 0x71, 0x34, 0xf5, 0xa8,
0xb3, 0x78, 0x72, 0x62, 0x6e, 0x8a, 0x68, 0x0a, 0x52, 0x1a, 0x9a, 0xad, 0xca, 0xd0, 0xfc, 0xa5,
0xc1, 0x2d, 0x39, 0x34, 0xff, 0xea, 0x0f, 0x69, 0x17, 0x8c, 0x11, 0xf3, 0x4a, 0x9f, 0x50, 0x01,
0x94, 0x32, 0x6c, 0x57, 0x32, 0xbc, 0x84, 0x9e, 0x4c, 0xf0, 0xad, 0x2f, 0x35, 0xb5, 0x2b, 0xfa,
0xb5, 0x5d, 0x69, 0x96, 0xba, 0x62, 0xfd, 0xa9, 0xc1, 0xae, 0x0c, 0x3c, 0xae, 0x7d, 0x00, 0xdc,
0x87, 0xfe, 0x34, 0xa6, 0xc3, 0xeb, 0x2e, 0xe7, 0x7a, 0x21, 0xb7, 0x0a, 0xa3, 0xab, 0x1a, 0xab,
0x94, 0x70, 0xbd, 0xf0, 0xad, 0x12, 0xd8, 0x83, 0xed, 0xef, 0x66, 0x34, 0x5e, 0x8c, 0x98, 0x97,
0x0d, 0xd3, 0x19, 0x89, 0xc9, 0x24, 0xe1, 0xaf, 0x10, 0xb9, 0x45, 0x0c, 0xdc, 0x78, 0x72, 0x62,
0xbd, 0xd2, 0xd4, 0xcd, 0x93, 0x29, 0x57, 0xd5, 0xd0, 0x27, 0xd0, 0x1e, 0x33, 0xc2, 0x66, 0x89,
0x7c, 0xab, 0x66, 0xef, 0x9d, 0xcc, 0x20, 0x15, 0x62, 0xa9, 0x84, 0x1e, 0xc1, 0x96, 0xf8, 0x2e,
0xf2, 0xb6, 0x25, 0xa6, 0x3e, 0xd0, 0xf7, 0x3a, 0x07, 0xdb, 0xd9, 0x4b, 0xb3, 0x2c, 0xc5, 0x55,
0x75, 0xee, 0x21, 0x3f, 0x09, 0x19, 0xbf, 0x41, 0x54, 0x0f, 0x15, 0x29, 0xae, 0xaa, 0x5b, 0x3f,
0x2e, 0x71, 0xe0, 0x13, 0xe2, 0x70, 0x48, 0x26, 0x96, 0x1e, 0xd0, 0xa7, 0x00, 0x97, 0x05, 0xcf,
0x34, 0xbf, 0x9e, 0x8c, 0x32, 0x66, 0xb1, 0x1f, 0x5e, 0x3c, 0x25, 0x53, 0xac, 0xe8, 0x58, 0xa3,
0x25, 0x72, 0x7c, 0xc8, 0x73, 0x05, 0xe9, 0xbe, 0x00, 0x8a, 0xc0, 0x0d, 0x25, 0xb0, 0xf5, 0x11,
0x18, 0xb9, 0x7f, 0xbe, 0x09, 0x14, 0x16, 0xda, 0x40, 0xe7, 0x9b, 0x40, 0x89, 0x79, 0x02, 0x1b,
0x79, 0xcc, 0x6f, 0xfc, 0x84, 0xa1, 0xc3, 0x25, 0x83, 0xfa, 0x27, 0x71, 0xc9, 0xcb, 0x0b, 0xd8,
0x2c, 0xb7, 0x0c, 0xdd, 0x83, 0xa6, 0x4d, 0xe7, 0xe9, 0x92, 0xd8, 0xcc, 0xab, 0x3b, 0x62, 0x5e,
0x7a, 0x65, 0xc8, 0xc6, 0x0a, 0x1d, 0xce, 0xf1, 0xb1, 0x1f, 0x92, 0x60, 0xa8, 0xe4, 0xa2, 0x20,
0xd6, 0x67, 0xd0, 0x17, 0x63, 0x57, 0x94, 0x5c, 0x4e, 0xdd, 0xca, 0xea, 0x58, 0x01, 0xf4, 0xe5,
0x08, 0x96, 0xad, 0xdf, 0x2a, 0x45, 0x4e, 0x92, 0x45, 0x8c, 0x04, 0x67, 0xca, 0x2e, 0x50, 0x10,
0xeb, 0x1d, 0x49, 0xd2, 0xce, 0xa1, 0x94, 0xa4, 0xf5, 0x25, 0x6c, 0xab, 0x34, 0x0a, 0x79, 0xc5,
0xa5, 0xb6, 0xe4, 0xf2, 0x2e, 0xbc, 0x2b, 0x4c, 0x96, 0xbf, 0x5e, 0xe9, 0xfa, 0x0c, 0xee, 0xa8,
0xae, 0xff, 0x81, 0xb7, 0xfe, 0x6f, 0x1a, 0xdc, 0x15, 0xbe, 0xd2, 0x35, 0x9a, 0xfe, 0xee, 0x38,
0x5e, 0xd8, 0x73, 0x7e, 0x15, 0xc9, 0xaa, 0x0f, 0xa0, 0xc3, 0xf8, 0xce, 0x97, 0xab, 0x37, 0xad,
0xbb, 0x0a, 0xf1, 0xbe, 0xb8, 0x7e, 0x4c, 0xc5, 0x8f, 0x59, 0x59, 0xaa, 0x02, 0xe0, 0x0b, 0x9d,
0xcd, 0xf3, 0x97, 0x9d, 0x81, 0xe5, 0x89, 0x5b, 0x09, 0x27, 0xfc, 0xba, 0x94, 0xbb, 0xbe, 0x00,
0xf8, 0x56, 0x72, 0xd3, 0x05, 0x2e, 0x96, 0xbd, 0x8e, 0xb3, 0xa3, 0xf5, 0x1c, 0x4c, 0xb5, 0x0a,
0x2a, 0x73, 0xf4, 0x00, 0xf4, 0x98, 0x66, 0x3d, 0xfe, 0x50, 0xf6, 0xf8, 0x3a, 0xed, 0x2c, 0x4f,
0xcc, 0x6d, 0xac, 0x3f, 0x34, 0x18, 0xbc, 0x4e, 0xf3, 0x0d, 0x6a, 0x21, 0x34, 0x18, 0x09, 0x4a,
0xef, 0x5c, 0x15, 0x5a, 0x55, 0x8f, 0xa2, 0x8a, 0xcd, 0x6a, 0x15, 0x4b, 0xd5, 0x6a, 0x55, 0xaa,
0x65, 0x45, 0x70, 0x4b, 0x90, 0xc6, 0x34, 0x20, 0x0b, 0x1a, 0x1f, 0x93, 0x80, 0xf0, 0x37, 0xd8,
0xeb, 0xe9, 0x2a, 0xf7, 0x60, 0xa3, 0x7c, 0x0f, 0x96, 0x02, 0xea, 0xd5, 0x80, 0x2f, 0x60, 0x47,
0x2d, 0x56, 0x25, 0xee, 0x43, 0xb5, 0x0d, 0x1f, 0xd7, 0xb4, 0xa1, 0xac, 0xff, 0x38, 0x8a, 0x9f,
0x85, 0x54, 0x3c, 0x2c, 0xd2, 0x5e, 0xfc, 0xac, 0xc1, 0xfb, 0x6f, 0xa4, 0xce, 0xf9, 0x9f, 0xa7,
0x68, 0x76, 0x8f, 0x9f, 0xd7, 0xe7, 0xde, 0xa8, 0x1d, 0xdb, 0x15, 0x19, 0x3e, 0xca, 0x33, 0x14,
0x91, 0xec, 0xc8, 0xce, 0x44, 0xbc, 0x3a, 0x16, 0x74, 0x99, 0x72, 0x96, 0x9b, 0xb6, 0x84, 0xdd,
0x7b, 0x2e, 0xde, 0xdd, 0xea, 0x02, 0x44, 0x7d, 0xb8, 0x79, 0x46, 0x43, 0xd7, 0x0f, 0x2f, 0x52,
0x80, 0xef, 0xc3, 0xde, 0x1a, 0x87, 0xc7, 0x33, 0xc7, 0xa1, 0x49, 0xa2, 0xc0, 0x1a, 0xba, 0x0d,
0xbd, 0xc7, 0xc4, 0x0f, 0xa8, 0xab, 0xa0, 0x8d, 0x83, 0x2e, 0x40, 0xf1, 0xff, 0xd3, 0x79, 0x5b,
0xfc, 0xaf, 0x74, 0xf8, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1f, 0xcd, 0x0e, 0x4f, 0x94, 0x12,
0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment