Commit 2e954ca3 authored by QM's avatar QM

修改x2eth测试方式

parent 29bd6344
...@@ -41,13 +41,6 @@ function down() { ...@@ -41,13 +41,6 @@ function down() {
echo "=========== # docker-compose down =============" echo "=========== # docker-compose down ============="
docker-compose down --rmi local docker-compose down --rmi local
fi fi
# shellcheck disable=SC2155
local isGanacheExit=$(docker ps | grep ganachetest)
if [[ ${isGanacheExit} != "" ]]; then
docker stop ganachetest
docker rm ganachetest
fi
} }
# run script # run script
......
...@@ -15,6 +15,9 @@ set -o pipefail ...@@ -15,6 +15,9 @@ set -o pipefail
PWD=$(cd "$(dirname "$0")" && pwd) PWD=$(cd "$(dirname "$0")" && pwd)
export PATH="$PWD:$PATH" export PATH="$PWD:$PATH"
dockerNamePrefix="${1}"
echo "dockerNamePrefix : ${dockerNamePrefix}"
NODE3="${1}_chain33_1" NODE3="${1}_chain33_1"
CLI="docker exec ${NODE3} /root/chain33-cli" CLI="docker exec ${NODE3} /root/chain33-cli"
...@@ -58,9 +61,7 @@ if [ -n "${DAPP}" ]; then ...@@ -58,9 +61,7 @@ if [ -n "${DAPP}" ]; then
DAPP_COMPOSE_FILE="docker-compose-${DAPP}.yml" DAPP_COMPOSE_FILE="docker-compose-${DAPP}.yml"
if [ -e "$DAPP_COMPOSE_FILE" ]; then if [ -e "$DAPP_COMPOSE_FILE" ]; then
export COMPOSE_FILE="docker-compose.yml:${DAPP_COMPOSE_FILE}" export COMPOSE_FILE="docker-compose.yml:${DAPP_COMPOSE_FILE}"
fi fi
fi fi
if [ -z "$DAPP" ] || [ "$DAPP" == "paracross" ]; then if [ -z "$DAPP" ] || [ "$DAPP" == "paracross" ]; then
......
FROM ubuntu:16.04
WORKDIR /root
COPY relayer.toml relayer.toml
COPY ebrelayer ebrelayer
COPY ebcli_A ebcli_A
EXPOSE 20000
CMD ["/root/ebrelayer"]
...@@ -6,13 +6,6 @@ set +e ...@@ -6,13 +6,6 @@ set +e
source "./publicTest.sh" source "./publicTest.sh"
CLIA="./ebcli_A"
CLIB="./ebcli_B"
CLIC="./ebcli_C"
CLID="./ebcli_D"
Chain33Cli="docker exec ${NODE3} /root/chain33-cli"
chain33SenderAddr="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt" chain33SenderAddr="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
# validatorsAddr=["0x92c8b16afd6d423652559c6e266cbe1c29bfd84f", "0x0df9a824699bc5878232c9e612fe1a5346a5a368", "0xcb074cb21cdddf3ce9c3c0a7ac4497d633c9d9f1", "0xd9dab021e74ecf475788ed7b61356056b2095830"] # validatorsAddr=["0x92c8b16afd6d423652559c6e266cbe1c29bfd84f", "0x0df9a824699bc5878232c9e612fe1a5346a5a368", "0xcb074cb21cdddf3ce9c3c0a7ac4497d633c9d9f1", "0xd9dab021e74ecf475788ed7b61356056b2095830"]
ethValidatorAddrKeyA="3fa21584ae2e4fd74db9b58e2386f5481607dfa4d7ba0617aaa7858e5025dc1e" ethValidatorAddrKeyA="3fa21584ae2e4fd74db9b58e2386f5481607dfa4d7ba0617aaa7858e5025dc1e"
...@@ -43,6 +36,7 @@ function kill_ebrelayerC() { ...@@ -43,6 +36,7 @@ function kill_ebrelayerC() {
function kill_ebrelayerD() { function kill_ebrelayerD() {
kill_ebrelayer "./D/ebrelayer" kill_ebrelayer "./D/ebrelayer"
} }
function start_ebrelayerC() { function start_ebrelayerC() {
start_ebrelayer "./C/ebrelayer" "./C/ebrelayer.log" start_ebrelayer "./C/ebrelayer" "./C/ebrelayer.log"
${CLIC} relayer unlock -p 123456hzj ${CLIC} relayer unlock -p 123456hzj
...@@ -72,14 +66,57 @@ function InitAndDeploy() { ...@@ -72,14 +66,57 @@ function InitAndDeploy() {
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}" echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
} }
function StartRelayerAndDeploy() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
# stop all docker
docker-compose -f docker-compose-ebrelayer.yml down
for name in b c d; do
docker-compose -f "docker-compose-ebrelayer${name}.yml" down
done
# change EthProvider url
{
inetAddr=$(get_inet_addr)
# shellcheck disable=SC2155
local line=$(delete_line_show "./relayer.toml" "EthProvider=\"ws:")
sed -i ''"${line}"' a EthProvider="ws://'"${inetAddr}"':7545/"' "./relayer.toml"
line=$(delete_line_show "./relayer.toml" "EthProviderCli=\"http:")
sed -i ''"${line}"' a EthProviderCli="http://'"${inetAddr}"':7545"' "./relayer.toml"
}
docker-compose -f docker-compose-ebrelayer.yml up --build -d
sleep 1
# 部署合约
InitAndDeploy
# 获取 BridgeRegistry 地址
result=$(${CLIA} relayer ethereum bridgeRegistry)
BridgeRegistry=$(cli_ret "${result}" "bridgeRegistry" ".addr")
# kill_ebrelayer "./A/ebrelayer"
docker-compose -f docker-compose-ebrelayer.yml down
# 修改 relayer.toml 配置文件
updata_relayer_toml "${BridgeRegistry}" ${maturityDegree} "./relayer.toml"
docker-compose -f docker-compose-ebrelayer.yml up --build -d
updata_docker_relayer_toml
for name in b c d; do
docker-compose -f "docker-compose-ebrelayer$name.yml" up --build -d
done
sleep 1
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function EthImportKey() { function EthImportKey() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}" echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
# 重启 ebrelayer 并解锁 # 重启 ebrelayer 并解锁
for name in A B C D; do for name in a b c d; do
start_ebrelayer "./$name/ebrelayer" "./$name/ebrelayer.log"
# 导入测试地址私钥 # 导入测试地址私钥
CLI="./ebcli_$name" # shellcheck disable=SC2154
CLI="docker exec ${dockerNamePrefix}_ebrelayer${name}_1 /root/ebcli_A"
result=$(${CLI} relayer set_pwd -p 123456hzj) result=$(${CLI} relayer set_pwd -p 123456hzj)
...@@ -108,38 +145,6 @@ function EthImportKey() { ...@@ -108,38 +145,6 @@ function EthImportKey() {
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}" 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")
kill_ebrelayer "./A/ebrelayer"
# 修改 relayer.toml 配置文件
updata_relayer_toml "${BridgeRegistry}" ${maturityDegree} "./A/relayer.toml"
updata_all_relayer_toml
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
# chian33 添加验证着及权重 # chian33 添加验证着及权重
function InitChain33Vilators() { function InitChain33Vilators() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}" echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
...@@ -530,8 +535,14 @@ function TestETH2Chain33Erc20Kill() { ...@@ -530,8 +535,14 @@ function TestETH2Chain33Erc20Kill() {
function AllRelayerMainTest() { function AllRelayerMainTest() {
set +e set +e
docker_chain33_ip=$(docker inspect "${NODE3}" | jq ".[].NetworkSettings.Networks" | grep "IPAddress" | awk '{ print $2}' | sed 's/\"//g' | sed 's/,//g') docker_chain33_ip=$(docker inspect "${NODE3}" | jq ".[].NetworkSettings.Networks" | grep "IPAddress" | awk '{ print $2}' | sed 's/\"//g' | sed 's/,//g')
Chain33Cli="./chain33-cli --rpc_laddr http://${docker_chain33_ip}:8801" Chain33Cli="./chain33-cli --rpc_laddr http://${docker_chain33_ip}:8801"
CLIA="docker exec ${dockerNamePrefix}_ebrelayera_1 /root/ebcli_A"
CLIB="docker exec ${dockerNamePrefix}_ebrelayerb_1 /root/ebcli_A"
CLIC="docker exec ${dockerNamePrefix}_ebrelayerc_1 /root/ebcli_A"
CLID="docker exec ${dockerNamePrefix}_ebrelayerd_1 /root/ebcli_A"
echo "${CLIA}"
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}" echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
if [[ ${1} != "" ]]; then if [[ ${1} != "" ]]; then
...@@ -548,11 +559,13 @@ function AllRelayerMainTest() { ...@@ -548,11 +559,13 @@ function AllRelayerMainTest() {
TestChain33ToEthAssets TestChain33ToEthAssets
TestETH2Chain33Assets TestETH2Chain33Assets
TestETH2Chain33Erc20 TestETH2Chain33Erc20
#
# kill relayer and start relayer # # kill relayer and start relayer
TestChain33ToEthAssetsKill # TestChain33ToEthAssetsKill
TestETH2Chain33AssetsKill # TestETH2Chain33AssetsKill
TestETH2Chain33Erc20Kill # TestETH2Chain33Erc20Kill
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}" echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
} }
version: '3'
services:
ebrelayera:
build:
context: .
dockerfile: Dockerfile-x2ethrelay
ports:
- "20000:20000"
version: '3'
#services:
# ganachetest:
# build:
# context: .
version: '3'
services:
ganachetest:
entrypoint: ["node", "/app/ganache-core.docker.cli.js", "-a", "10", "-b", "2", "--debug", "-m", "coast bar giraffe art venue decide symbol law visual crater vital fold"]
image: trufflesuite/ganache-cli:latest
ports:
- "7545:8545"
ebrelayera:
build:
context: .
dockerfile: Dockerfile-x2ethrelay
ebrelayerb:
build:
context: .
dockerfile: Dockerfile-x2ethrelay
ebrelayerc:
build:
context: .
dockerfile: Dockerfile-x2ethrelay
ebrelayerd:
build:
context: .
dockerfile: Dockerfile-x2ethrelay
\ No newline at end of file
...@@ -23,8 +23,9 @@ function exit_cp_file() { ...@@ -23,8 +23,9 @@ function exit_cp_file() {
mkdir -p ${dirName} mkdir -p ${dirName}
fi fi
for name in A B C D; do for name in a b c d; do
cp "./$name/ebrelayer.log" "$dirName/ebrelayer$name.log" # shellcheck disable=SC2154
docker cp "${dockerNamePrefix}_ebrelayer${name}_1":/root/logs/x2Ethereum_relayer.log "$dirName/ebrelayer$name.log"
done done
docker cp "${NODE3}":/root/logs/chain33.log "$dirName/chain33.log" docker cp "${NODE3}":/root/logs/chain33.log "$dirName/chain33.log"
...@@ -328,6 +329,25 @@ function check_addr() { ...@@ -328,6 +329,25 @@ function check_addr() {
fi fi
} }
function get_inet_addr() {
local inetAddr=$(ifconfig wlp2s0 | grep "inet " | awk '{ print $2}' | awk -F: '{print $2}')
if [[ ${inetAddr} == "" ]]; then
inetAddr=$(ifconfig wlp2s0 | grep "inet " | awk '{ print $2}')
if [[ ${inetAddr} == "" ]]; then
inetAddr=$(ifconfig eth0 | grep "inet " | awk '{ print $2}' | awk -F: '{print $2}')
if [[ ${inetAddr} == "" ]]; then
inetAddr=$(ifconfig eth0 | grep "inet " | awk '{ print $2}')
if [[ ${inetAddr} == "" ]]; then
ip addr show eth0
inetAddr=$(ip addr show eth0 | grep "inet " | awk '{ print $2}' | head -c-4)
fi
fi
fi
fi
echo "${inetAddr}"
}
# 更新配置文件 $1 为 BridgeRegistry 合约地址; $2 等待区块 默认10; $3 relayer.toml 地址 # 更新配置文件 $1 为 BridgeRegistry 合约地址; $2 等待区块 默认10; $3 relayer.toml 地址
function updata_relayer_toml() { function updata_relayer_toml() {
local BridgeRegistry=${1} local BridgeRegistry=${1}
...@@ -341,21 +361,7 @@ function updata_relayer_toml() { ...@@ -341,21 +361,7 @@ function updata_relayer_toml() {
exit_cp_file exit_cp_file
fi fi
local pushHost=$(ifconfig wlp2s0 | grep "inet " | awk '{ print $2}' | awk -F: '{print $2}') local pushHost=$(get_inet_addr)
if [[ ${pushHost} == "" ]]; then
pushHost=$(ifconfig wlp2s0 | grep "inet " | awk '{ print $2}')
if [[ ${pushHost} == "" ]]; then
pushHost=$(ifconfig eth0 | grep "inet " | awk '{ print $2}' | awk -F: '{print $2}')
if [[ ${pushHost} == "" ]]; then
pushHost=$(ifconfig eth0 | grep "inet " | awk '{ print $2}')
if [[ ${pushHost} == "" ]]; then
ip addr show eth0
pushHost=$(ip addr show eth0 | grep "inet " | awk '{ print $2}' | head -c-4)
fi
fi
fi
fi
if [[ ${pushHost} == "" ]]; then if [[ ${pushHost} == "" ]]; then
echo -e "${RED}pushHost is empty${NOC}" echo -e "${RED}pushHost is empty${NOC}"
exit_cp_file exit_cp_file
...@@ -368,6 +374,9 @@ function updata_relayer_toml() { ...@@ -368,6 +374,9 @@ function updata_relayer_toml() {
line=$(delete_line_show "${file}" "pushHost") line=$(delete_line_show "${file}" "pushHost")
sed -i ''"${line}"' a pushHost="http://'"${pushHost}"':20000"' "${file}" sed -i ''"${line}"' a pushHost="http://'"${pushHost}"':20000"' "${file}"
# line=$(delete_line_show "${file}" "pushBind")
# sed -i ''"${line}"' a pushBind="'"${pushHost}"':20000"' "${file}"
line=$(delete_line_show "${file}" "BridgeRegistry") line=$(delete_line_show "${file}" "BridgeRegistry")
sed -i ''"${line}"' a BridgeRegistry="'"${BridgeRegistry}"'"' "${file}" sed -i ''"${line}"' a BridgeRegistry="'"${BridgeRegistry}"'"' "${file}"
...@@ -401,6 +410,47 @@ function updata_relayer_toml_ropston() { ...@@ -401,6 +410,47 @@ function updata_relayer_toml_ropston() {
sed -i 's/maturityDegree=10/'maturityDegree="${maturityDegree}"'/g' "${file}" sed -i 's/maturityDegree=10/'maturityDegree="${maturityDegree}"'/g' "${file}"
} }
function updata_docker_relayer_toml() {
local port=20000
for name in b c d; do
local file="./relayer$name.toml"
cp './relayer.toml' "${file}"
# 删除配置文件中不需要的字段
for deleteName in "deployerPrivateKey" "operatorAddr" "validatorsAddr" "initPowers" "deployerPrivateKey" "deploy"; do
delete_line "${file}" "${deleteName}"
done
port=$((port + 1))
sed -i 's/20000/'${port}'/g' "${file}"
sed -i 's/x2ethereum/x2ethereum'${name}'/g' "${file}"
local dockerfile="./Dockerfile-x2ethrelay$name"
cp "./Dockerfile-x2ethrelay" "${dockerfile}"
# shellcheck disable=SC2155
local line=$(delete_line_show "${dockerfile}" "COPY relayer.toml relayer.toml")
sed -i ''"${line}"' a COPY relayer'$name'.toml relayer.toml' "${dockerfile}"
line=$(delete_line_show "${dockerfile}" "EXPOSE 20000")
sed -i ''"${line}"' a EXPOSE '$port'' "${dockerfile}"
local dockeryml="./docker-compose-ebrelayer$name.yml"
cp "./docker-compose-ebrelayer.yml" "${dockeryml}"
line=$(delete_line_show "${dockeryml}" "ebrelayera")
sed -i ''"${line}"' a \ \ ebrelayer'$name':' "${dockeryml}"
line=$(delete_line_show "${dockeryml}" "dockerfile: Dockerfile-x2ethrelay")
sed -i ''"${line}"' a \ \ \ \ \ \ dockerfile: Dockerfile-x2ethrelay'$name'' "${dockeryml}"
line=$(delete_line_show "${dockeryml}" "20000:20000")
sed -i ''"${line}"' a \ \ \ \ \ \ -\ "'${port}':'${port}'"' "${dockeryml}"
done
}
# 更新 B C D 的配置文件 # 更新 B C D 的配置文件
function updata_all_relayer_toml() { function updata_all_relayer_toml() {
local port=9901 local port=9901
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# shellcheck source=/dev/null # shellcheck source=/dev/null
source "./allRelayerTest.sh" source "./allRelayerTest.sh"
#source "./relayerTest.sh"
source "./perf_test.sh" source "./perf_test.sh"
function x2ethereum() { function x2ethereum() {
...@@ -15,7 +16,7 @@ function x2ethereum() { ...@@ -15,7 +16,7 @@ function x2ethereum() {
set +e set +e
set -x set -x
AllRelayerMainTest 5 AllRelayerMainTest 5
perf_test_main 10 # perf_test_main 10
echo "========================== x2ethereum test end ==========================" echo "========================== x2ethereum test end =========================="
fi fi
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
...@@ -13,6 +14,8 @@ import ( ...@@ -13,6 +14,8 @@ import (
"github.com/33cn/chain33/common/log" "github.com/33cn/chain33/common/log"
"github.com/33cn/chain33/pluginmgr" "github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/x2ethereum/ebcli/buildflags" "github.com/33cn/plugin/plugin/dapp/x2ethereum/ebcli/buildflags"
relayerTypes "github.com/33cn/plugin/plugin/dapp/x2ethereum/ebrelayer/types"
tml "github.com/BurntSushi/toml"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -21,6 +24,10 @@ var rootCmd = &cobra.Command{ ...@@ -21,6 +24,10 @@ var rootCmd = &cobra.Command{
Short: "chain33xEth-relayer" + "client tools", Short: "chain33xEth-relayer" + "client tools",
} }
var (
configPath = flag.String("f", "", "configfile")
)
func init() { func init() {
rootCmd.AddCommand( rootCmd.AddCommand(
RelayerCmd(), RelayerCmd(),
...@@ -66,12 +73,29 @@ func run(RPCAddr, NodeAddr string) { ...@@ -66,12 +73,29 @@ func run(RPCAddr, NodeAddr string) {
} }
} }
func initCfg(path string) *relayerTypes.RelayerConfig {
var cfg relayerTypes.RelayerConfig
if _, err := tml.DecodeFile(path, &cfg); err != nil {
fmt.Println(err)
os.Exit(-1)
}
//fmt.Println(cfg)
return &cfg
}
func main() { func main() {
if *configPath == "" {
*configPath = "relayer.toml"
}
cfg := initCfg(*configPath)
if buildflags.RPCAddr == "" { if buildflags.RPCAddr == "" {
buildflags.RPCAddr = "http://localhost:9901" buildflags.RPCAddr = "http://localhost:9901"
} }
if buildflags.NodeAddr == "" { if buildflags.NodeAddr == "" {
buildflags.NodeAddr = "http://127.0.0.1:7545" //buildflags.NodeAddr = "http://127.0.0.1:7545"
buildflags.NodeAddr = cfg.EthProviderCli
} }
run(buildflags.RPCAddr, buildflags.NodeAddr) run(buildflags.RPCAddr, buildflags.NodeAddr)
} }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
title="x2Ethereum_relayer" title="x2Ethereum_relayer"
#用于cli向该relayer进行配置 #用于cli向该relayer进行配置
JrpcBindAddr="localhost:9901" JrpcBindAddr="localhost:9901"
EthProviderCli="http://127.0.0.1:7545"
EthProvider="ws://127.0.0.1:7545/" EthProvider="ws://127.0.0.1:7545/"
#EthProvider="wss://rinkeby.infura.io/ws/v3/404eb4acc421426ebeb6e92c7ce9a270" #EthProvider="wss://rinkeby.infura.io/ws/v3/404eb4acc421426ebeb6e92c7ce9a270"
#EthProvider="wss://ropsten.infura.io/ws/v3/404eb4acc421426ebeb6e92c7ce9a270" #EthProvider="wss://ropsten.infura.io/ws/v3/404eb4acc421426ebeb6e92c7ce9a270"
......
...@@ -69,6 +69,7 @@ type RelayerConfig struct { ...@@ -69,6 +69,7 @@ type RelayerConfig struct {
Deploy *Deploy `protobuf:"bytes,7,opt,name=deploy" json:"deploy,omitempty"` Deploy *Deploy `protobuf:"bytes,7,opt,name=deploy" json:"deploy,omitempty"`
EthMaturityDegree int32 `protobuf:"varint,8,opt,name=ethMaturityDegree" json:"ethMaturityDegree,omitempty"` EthMaturityDegree int32 `protobuf:"varint,8,opt,name=ethMaturityDegree" json:"ethMaturityDegree,omitempty"`
EthBlockFetchPeriod int32 `protobuf:"varint,9,opt,name=ethBlockFetchPeriod" json:"ethBlockFetchPeriod,omitempty"` EthBlockFetchPeriod int32 `protobuf:"varint,9,opt,name=ethBlockFetchPeriod" json:"ethBlockFetchPeriod,omitempty"`
EthProviderCli string `protobuf:"bytes,10,opt,name=ethProviderCli" json:"ethProviderCli,omitempty"`
} }
func (m *RelayerConfig) Reset() { *m = RelayerConfig{} } func (m *RelayerConfig) Reset() { *m = RelayerConfig{} }
......
...@@ -40,6 +40,7 @@ message RelayerConfig { ...@@ -40,6 +40,7 @@ message RelayerConfig {
Deploy deploy = 7; Deploy deploy = 7;
int32 ethMaturityDegree = 8; int32 ethMaturityDegree = 8;
int32 ethBlockFetchPeriod = 9; int32 ethBlockFetchPeriod = 9;
string ethProviderCli = 10;
} }
message SyncTxReceiptConfig { message SyncTxReceiptConfig {
......
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