Repository: xuperchain/xuperchain (language: python)

Issue:
优化代码实现
- 优化代码实现效率
- 提升可维护性
  - 去除重复代码，抽取类、函数
  - Error 处理规范化
  - 去除无用代码
- 优化可读性
  - 变量名优化
  - 函数原型优化
  - 长函数拆解
- 代码规范
  - Import
优化代码实现
- 优化代码实现效率
- 提升可维护性
  - 去除重复代码，抽取类、函数
  - Error 处理规范化
  - 去除无用代码
- 优化可读性
  - 变量名优化
  - 函数原型优化
  - 长函数拆解
- 代码规范
  - Import


Discussion / hints:

Fix patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 0ee24b421..012977b9b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -5,3 +5,8 @@ repos:
       - id: check-yaml
       - id: end-of-file-fixer
       - id: trailing-whitespace
+
+  - repo: https://github.com/golangci/golangci-lint
+    rev: v1.16.0
+    hooks:
+      - id: golangci-lint
diff --git a/auto/ci_pipeline.sh b/auto/ci_pipeline.sh
index f079d3a17..99123f923 100644
--- a/auto/ci_pipeline.sh
+++ b/auto/ci_pipeline.sh
@@ -16,12 +16,17 @@ WorkRoot=$AbsPath/..
 TestNet=$WorkRoot/testnet
 # 工作路径：所有命令在node1路径下运行
 WorkPath=$TestNet/node1
+# log
+LogPath="${WorkPath}/logs"
+ErrorLogFile="${LogPath}/xchain.log.wf"
 # mine period (in second)
 mine_period=3
 
+# Make `alias` work in GitHub actions
+shopt -s expand_aliases
 alias xchain-cli='$WorkPath/bin/xchain-cli'
-alias info='echo INFO $(date +"%Y-%m-%d %H:%M:%S") ${BASH_SOURCE##*/}:$LINENO'
-alias error='echo ERROR $(date +"%Y-%m-%d %H:%M:%S") ${BASH_SOURCE##*/}:$LINENO'
+alias log_info='echo INFO $(date +"%Y-%m-%d %H:%M:%S") ${BASH_SOURCE##*/}:$LINENO'
+alias log_error='echo ERROR $(date +"%Y-%m-%d %H:%M:%S") ${BASH_SOURCE##*/}:$LINENO'
 
 # testnet
 function testnet() {
@@ -36,13 +41,20 @@ function testnet() {
 
   cd "$WorkPath" || exit
 
-  echo "start testnet path=$(pwd)"
-  sleep 3s && ./bin/xchain-cli status || \
-  sleep 3s && ./bin/xchain-cli status || \
-  sleep 3s && ./bin/xchain-cli status || \
-  sleep 3s && ./bin/xchain-cli status || \
-  sleep 3s && ./bin/xchain-cli status || \
-  sleep 3s && ./bin/xchain-cli status || exit
+  log_info "start testnet path=$(pwd)"
+
+  # check status
+  for i in $(seq 10);
+  do
+    sleep 3
+    if ./bin/xchain-cli status ; then
+      log_info "testnet started"
+      return 0
+    fi
+  done
+
+  log_error "start testnet failed"
+  exit
 }
 
 # account
@@ -51,44 +63,47 @@ function account() {
   ./bin/xchain-cli account newkeys --output data/alice || exit
   ./bin/xchain-cli transfer --to "$(cat data/alice/address)" --amount 10000000 || exit
   balance=$(./bin/xchain-cli account balance --keys data/alice)
-  echo "account $(cat data/alice/address) balance $balance"
+  log_info "account $(cat data/alice/address) balance $balance"
 
   ## 合约账户
   ./bin/xchain-cli account new --account 1111111111111111 --fee 1000 || exit
   ./bin/xchain-cli transfer --to XC1111111111111111@xuper --amount 100000001 || exit
   balance=$(./bin/xchain-cli account balance XC1111111111111111@xuper)
-  echo "account XC1111111111111111@xuper balance $balance"
+  log_info "account XC1111111111111111@xuper balance $balance"
 
   ## 合约账户：desc 文件
   ./bin/xchain-cli account new --desc $WorkRoot/data/desc/NewAccount.json --fee 1000 || exit
   ./bin/xchain-cli transfer --to XC2222222222222222@xuper --amount 100000002 || exit
   balance=$(./bin/xchain-cli account balance XC2222222222222222@xuper)
-  echo "account XC2222222222222222@xuper balance $balance"
+  log_info "account XC2222222222222222@xuper balance $balance"
 }
 
 # contract
 function contract() {
   cp $WorkRoot/auto/counter.wasm $WorkPath
   # wasm
-  echo "contract wasm"
+  log_info "contract wasm"
   ./bin/xchain-cli wasm deploy $WorkPath/counter.wasm --cname counter.wasm \
             --account XC1111111111111111@xuper \
-            --runtime c -a '{"creator": "xuper"}' --fee 155537 || exit
-  echo "contract wasm invoke"
+            --runtime c -a '{"creator": "xuper"}' --fee 155537 || {
+              tail "${ErrorLogFile}"
+              exit
+            }
+  log_info "contract wasm invoke"
   ./bin/xchain-cli wasm invoke --method increase -a '{"key":"test"}' counter.wasm --fee 100
   ./bin/xchain-cli wasm query --method get -a '{"key":"test"}' counter.wasm
 
   # 查询用户部署的合约
-  echo "contract XC1111111111111111@xuper"
+  log_info "contract XC1111111111111111@xuper"
   ./bin/xchain-cli account contracts --account XC1111111111111111@xuper
-  echo "contract $(cat data/keys/address)"
+  log_info "contract $(cat data/keys/address)"
   ./bin/xchain-cli account contracts --address $(cat data/keys/address)
 }
 
 # 内置合约
 function builtin() {
       # reserved_contracts
-  echo "contract reserved unified_check"
+  log_info "contract reserved unified_check"
   ./bin/xchain-cli wasm deploy $WorkPath/build/unified_check --cname unified_check \
             --account XC1111111111111111@xuper \
             --runtime c -a '{"creator": "TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY"}' --fee 164735 || exit
@@ -96,7 +111,7 @@ function builtin() {
             -a '{"aks":"SmJG3rH2ZzYQ9ojxhbRCPwFiE9y6pD1Co,iYjtLcW6SVCiousAb5DFKWtWroahhEj4u"}' --fee 155 || exit
 
   # forbidden_contract
-  echo "contract forbidden"
+  log_info "contract forbidden"
   ./bin/xchain-cli wasm deploy $WorkPath/build/forbidden --cname forbidden \
             --account XC1111111111111111@xuper \
             --runtime c -a '{"creator": "TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY"}' --fee 155679 || exit
@@ -108,7 +123,7 @@ function acl() {
   mkdir -p data/acl
 
   # 设置合约账户acl
-  echo "acl account"
+  log_info "acl account"
   echo "XC1111111111111111@xuper/$(cat $TestNet/node1/data/keys/address)" > data/acl/addrs
   ./bin/xchain-cli acl query --account XC1111111111111111@xuper
   ./bin/xchain-cli multisig gen --desc $WorkRoot/data/desc/SetAccountACL.json --fee 100
@@ -118,7 +133,7 @@ function acl() {
   ./bin/xchain-cli acl query --account XC1111111111111111@xuper
 
   # 设置合约方法acl
-  echo "acl contract method"
+  log_info "acl contract method"
   echo "XC1111111111111111@xuper/$(cat $TestNet/node2/data/keys/address)" >> data/acl/addrs
   ./bin/xchain-cli multisig gen --desc $WorkRoot/data/desc/SetMethodACL.json --fee 100
   ./bin/xchain-cli multisig sign --keys $TestNet/node1/data/keys --output sign1.out
@@ -129,13 +144,13 @@ function acl() {
   ./bin/xchain-cli acl query --contract counter.wasm --method increase
 
   # 调用合约方法
-  echo "acl invoke contract method"
+  log_info "acl invoke contract method"
   ./bin/xchain-cli transfer --to "$(cat $TestNet/node2/data/keys/address)" --amount 10000000 || exit
   ./bin/xchain-cli transfer --to "$(cat $TestNet/node3/data/keys/address)" --amount 10000000 || exit
   ./bin/xchain-cli wasm invoke --method increase -a '{"key":"test"}' counter.wasm --fee 100 --keys $TestNet/node1/data/keys || exit
   ./bin/xchain-cli wasm invoke --method increase -a '{"key":"test"}' counter.wasm --fee 100 --keys $TestNet/node2/data/keys || exit
   # node3节点无权限，应该调用失败
-  echo "acl node3 invoke contract method: should 'ACL not enough'"
+  log_info "acl node3 invoke contract method: should 'ACL not enough'"
   ./bin/xchain-cli wasm invoke --method increase -a '{"key":"test"}' counter.wasm --fee 100 --keys $TestNet/node3/data/keys && exit
 }
 
@@ -144,10 +159,10 @@ function height() {
   height2=$(./bin/xchain-cli status -H:37102 | grep trunkHeight | awk '{print $2}')
   height3=$(./bin/xchain-cli status -H:37103 | grep trunkHeight | awk '{print $2}')
 
-  echo "height1=$height1 height2=$height2 height3=$height3"
+  log_info "height1=$height1 height2=$height2 height3=$height3"
   diff=$((2*height1-height2-height3))
   if [ $diff -gt 3 ]; then
-		error "height inconsistency: height1=$height1 height2=$height2 height3=$height3" && exit
+		log_error "height inconsistency: height1=$height1 height2=$height2 height3=$height3" && exit
 	fi
 }
 
@@ -161,26 +176,26 @@ function clean() {
 }
 
 function main() {
-  echo "test start"
+  log_info "test start"
   clean
 
-  echo "test install"
+  log_info "test install"
   testnet
 
-  echo "test account"
+  log_info "test account"
   account
 
-  echo "test contract"
+  log_info "test contract"
   contract
   #builtin
 
-  echo "test acl"
+  log_info "test acl"
   acl
 
-  echo "test height"
+  log_info "test height"
   height
 
-  echo "test done"
+  log_info "test done"
 }
 
 case X$1 in
diff --git a/cmd/client/cmd/account.go b/cmd/client/cmd/account.go
index d711a0cda..06cfa3f8d 100644
--- a/cmd/client/cmd/account.go
+++ b/cmd/client/cmd/account.go
@@ -8,28 +8,20 @@ import (
 	"github.com/spf13/cobra"
 )
 
-// AccountCommand account cmd entrance
-type AccountCommand struct {
-	cli *Cli
-	cmd *cobra.Command
-}
-
 // NewAccountCommand new account cmd
 func NewAccountCommand(cli *Cli) *cobra.Command {
-	c := new(AccountCommand)
-	c.cli = cli
-	c.cmd = &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "account",
 		Short: "Operate an account or address: balance|new|newkeys|contracts|restore|decrypt.",
 	}
-	c.cmd.AddCommand(NewAccountBalanceCommand(cli))
-	c.cmd.AddCommand(NewAccountNewkeysCommand(cli))
-	c.cmd.AddCommand(NewAccountNewCommand(cli))
-	c.cmd.AddCommand(NewAccountContractsCommand(cli))
-	c.cmd.AddCommand(NewAccountQueryCommand(cli))
-	c.cmd.AddCommand(NewAccountRestoreCommand(cli))
-	c.cmd.AddCommand(NewAccountDecryptCommand(cli))
-	return c.cmd
+	cmd.AddCommand(NewAccountBalanceCommand(cli))
+	cmd.AddCommand(NewAccountNewkeysCommand(cli))
+	cmd.AddCommand(NewAccountNewCommand(cli))
+	cmd.AddCommand(NewAccountContractsCommand(cli))
+	cmd.AddCommand(NewAccountQueryCommand(cli))
+	cmd.AddCommand(NewAccountRestoreCommand(cli))
+	cmd.AddCommand(NewAccountDecryptCommand(cli))
+	return cmd
 }
 
 func init() {
diff --git a/cmd/client/cmd/acl.go b/cmd/client/cmd/acl.go
index e01dda7ad..3278c765a 100644
--- a/cmd/client/cmd/acl.go
+++ b/cmd/client/cmd/acl.go
@@ -6,22 +6,14 @@ package cmd
 
 import "github.com/spf13/cobra"
 
-// ACLCommand acl cmd struct
-type ACLCommand struct {
-	cli *Cli
-	cmd *cobra.Command
-}
-
 // NewACLCommand new acl cmd
 func NewACLCommand(cli *Cli) *cobra.Command {
-	c := new(ACLCommand)
-	c.cli = cli
-	c.cmd = &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "acl",
 		Short: "Operate an access control list(ACL): query.",
 	}
-	c.cmd.AddCommand(NewACLQueryCommand(cli))
-	return c.cmd
+	cmd.AddCommand(NewACLQueryCommand(cli))
+	return cmd
 }
 
 func init() {
diff --git a/cmd/client/cmd/ak.go b/cmd/client/cmd/ak.go
index 605d08a9e..ced73f065 100644
--- a/cmd/client/cmd/ak.go
+++ b/cmd/client/cmd/ak.go
@@ -9,11 +9,10 @@ import (
 	"math/big"
 	"os"
 	"path/filepath"
-	"strconv"
 
 	"github.com/xuperchain/xupercore/lib/crypto/client/base"
-	"github.com/xuperchain/xupercore/lib/crypto/hash"
 
+	"github.com/xuperchain/xuperchain/models"
 	"github.com/xuperchain/xuperchain/service/common"
 	"github.com/xuperchain/xuperchain/service/pb"
 )
@@ -157,7 +156,8 @@ type AKInfo struct {
 // 	amount: UTXO amount
 // 	crypto: crypto client
 func (i *AKInfo) SignUtxo(bcName string, amount *big.Int, crypto base.CryptoClient) (pb.SignatureInfo, error) {
-	return i.KeyPair.SignUtxo(bcName, i.address, amount, crypto)
+	lockedUtxo := models.NewLockedUtxo(bcName, i.address, amount)
+	return i.KeyPair.SignUtxo(lockedUtxo, crypto)
 }
 
 // KeyPair is key-pair for crypto
@@ -179,15 +179,9 @@ func (p *KeyPair) SignTx(tx *pb.Transaction, crypto base.CryptoClient) (*pb.Sign
 
 // SignUtxo signs for an UTXO with given crypto client by AK key pair
 // Params:
-// 	bcName: UTXO blockchain name
-// 	account: UTXO account
-// 	amount: UTXO amount
+// 	utxo: locked UTXO
 // 	crypto: crypto client
-func (p *KeyPair) SignUtxo(bcName, account string, amount *big.Int, crypto base.CryptoClient) (pb.SignatureInfo, error) {
-
-	// prepare raw content
-	hashKey := bcName + account + amount.String() + strconv.FormatBool(true)
-	hashValue := hash.DoubleSha256([]byte(hashKey))
+func (p *KeyPair) SignUtxo(utxo *models.LockedUtxo, crypto base.CryptoClient) (pb.SignatureInfo, error) {
 
 	// prepare private key
 	ecdsaPrivateKey, err := crypto.GetEcdsaPrivateKeyFromJsonStr(p.secretKey)
@@ -196,7 +190,7 @@ func (p *KeyPair) SignUtxo(bcName, account string, amount *big.Int, crypto base.
 	}
 
 	// sign
-	sign, err := crypto.SignECDSA(ecdsaPrivateKey, hashValue)
+	sign, err := crypto.SignECDSA(ecdsaPrivateKey, utxo.Hash())
 	if err != nil {
 		return pb.SignatureInfo{}, err
 	}
diff --git a/cmd/client/cmd/cli.go b/cmd/client/cmd/cli.go
index 9484bcc72..942b8ced9 100644
--- a/cmd/client/cmd/cli.go
+++ b/cmd/client/cmd/cli.go
@@ -77,7 +77,7 @@ func (c *Cli) SetVer(ver string) {
 }
 
 func (c *Cli) initXchainClient() error {
-	conn, err := grpc.Dial(c.RootOptions.Host, grpc.WithInsecure(), grpc.WithMaxMsgSize(64<<20-1))
+	conn, err := grpc.Dial(c.RootOptions.Host, grpc.WithInsecure(), grpc.WithMaxMsgSize(64<<20-1)) //nolint:SA1019
 	if err != nil {
 		return err
 	}
@@ -99,7 +99,9 @@ func (c *Cli) initFlags() error {
 	rootFlag.String("name", c.RootOptions.Name, "block chain name")
 	rootFlag.String("keys", c.RootOptions.Keys, "directory of keys")
 	rootFlag.String("crypto", c.RootOptions.Crypto, "crypto type")
-	viper.BindPFlags(rootFlag)
+	if err := viper.BindPFlags(rootFlag); err != nil {
+		return err
+	}
 	err := c.RootOptions.LoadConfig(cfgFile)
 	if err != nil {
 		fmt.Printf("load client config failed.config:%s err:%v\n", cfgFile, err)
@@ -107,11 +109,14 @@ func (c *Cli) initFlags() error {
 	}
 
 	cobra.OnInitialize(func() {
-		viper.Unmarshal(&c.RootOptions)
+		if err := viper.Unmarshal(&c.RootOptions); err != nil {
+			fmt.Printf("viper unmarshal failed. err: %s\n", err)
+			os.Exit(1)
+		}
 		err = c.initXchainClient()
 		if err != nil {
 			fmt.Printf("init xchain client failed.err:%v\n", err)
-			os.Exit(-1)
+			os.Exit(2)
 		}
 	})
 
@@ -204,7 +209,7 @@ func (c *Cli) RangeNodes(ctx context.Context, f func(addr string, client pb.Xcha
 	if err != nil {
 		return err
 	}
-	options := []grpc.DialOption{grpc.WithMaxMsgSize(64<<20 - 1)}
+	options := []grpc.DialOption{grpc.WithMaxMsgSize(64<<20 - 1)} //nolint:SA1019
 	if c.RootOptions.TLS.Enable {
 		cred, err := genCreds(c.RootOptions.TLS.Cert, c.RootOptions.TLS.Server)
 		if err != nil {
@@ -230,7 +235,7 @@ func (c *Cli) RangeNodes(ctx context.Context, f func(addr string, client pb.Xcha
 		}
 	}
 
-	optionsRPC := []grpc.DialOption{grpc.WithMaxMsgSize(64<<20 - 1), grpc.WithInsecure()}
+	optionsRPC := []grpc.DialOption{grpc.WithMaxMsgSize(64<<20 - 1), grpc.WithInsecure()} //nolint:SA1019
 	conn, err := grpc.Dial(c.RootOptions.Host, optionsRPC...)
 	if err != nil {
 		return err
diff --git a/cmd/client/cmd/comm_trans.go b/cmd/client/cmd/comm_trans.go
index 7ffe04072..e5bd28796 100644
--- a/cmd/client/cmd/comm_trans.go
+++ b/cmd/client/cmd/comm_trans.go
@@ -24,6 +24,7 @@ import (
 	"github.com/xuperchain/xupercore/lib/utils"
 	"google.golang.org/grpc"
 
+	"github.com/xuperchain/xuperchain/models"
 	"github.com/xuperchain/xuperchain/service/common"
 	"github.com/xuperchain/xuperchain/service/pb"
 )
@@ -384,16 +385,14 @@ func (t *CommTrans) GenTxInputs(ctx context.Context, totalNeed *big.Int) (
 
 // Transfer quick access to transfer
 func (t *CommTrans) Transfer(ctx context.Context) error {
-	var err error
-	tx := &pb.Transaction{}
-	if t.RootOptions.ComplianceCheck.IsNeedComplianceCheck == true {
+	if t.RootOptions.ComplianceCheck.IsNeedComplianceCheck {
 		preSelectUTXORes, err := t.GenPreExeWithSelectUtxoRes(ctx)
 		if err != nil {
 			return err
 		}
 		return t.GenCompleteTxAndPost(ctx, preSelectUTXORes)
 	} else {
-		tx, err = t.GenerateTx(ctx)
+		tx, err := t.GenerateTx(ctx)
 		if err != nil {
 			return err
 		}
@@ -615,8 +614,7 @@ func (t *CommTrans) GenTxInputsWithMergeUTXO(ctx context.Context) ([]*pb.TxInput
 		Address:  fromAddr,
 		NeedLock: true,
 	}
-
-	signature, err := t.signLockUtxo(t.ChainName, fromAddr, big.NewInt(0))
+	signature, err := t.signLockUtxo(utxoInput)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -917,7 +915,7 @@ func (t *CommTrans) GenerateMultiTxOutputs(selfAmount string, gasUsed string) ([
 	txOutputSelf := new(pb.TxOutput)
 	txOutputSelf.ToAddr = []byte(selfAddr)
 	realSelfAmount, isSuccess := new(big.Int).SetString(selfAmount, 10)
-	if isSuccess != true {
+	if !isSuccess {
 		fmt.Printf("selfAmount convert to bigint failed")
 		return nil, ErrInvalidAmount
 	}
@@ -925,7 +923,7 @@ func (t *CommTrans) GenerateMultiTxOutputs(selfAmount string, gasUsed string) ([
 	txOutputs = append(txOutputs, txOutputSelf)
 	if feeAmount != "" && feeAmount != "0" {
 		realFeeAmount, isSuccess := new(big.Int).SetString(feeAmount, 10)
-		if isSuccess != true {
+		if !isSuccess {
 			fmt.Printf("feeAmount convert to bigint failed")
 			return nil, ErrInvalidAmount
 		}
@@ -988,11 +986,13 @@ func (t *CommTrans) ComplianceCheck(tx *pb.Transaction, fee *pb.Transaction) (
 		RequestData: requestData,
 	}
 
+	//nolint:SA1019
 	conn, err := grpc.Dial(t.RootOptions.EndorseServiceHost, grpc.WithInsecure(), grpc.WithMaxMsgSize(64<<20-1))
 	if err != nil {
 		fmt.Printf("ComplianceCheck connect EndorseServiceHost err: %v", err)
 		return nil, err
 	}
+
 	defer conn.Close()
 	ctx, cancel := context.WithTimeout(context.Background(), 15000*time.Millisecond)
 	defer cancel()
@@ -1146,7 +1146,7 @@ func (t *CommTrans) GenerateTxOutput(to, amount, fee string) ([]*pb.TxOutput, er
 	return txOutputs, nil
 }
 
-func (t *CommTrans) signLockUtxo(bcName, account string, need *big.Int) (pb.SignatureInfo, error) {
+func (t *CommTrans) signLockUtxo(utxo *pb.UtxoInput) (pb.SignatureInfo, error) {
 
 	ak := newAK(t.Keys)
 	keyPair, err := ak.keyPair()
@@ -1159,5 +1159,6 @@ func (t *CommTrans) signLockUtxo(bcName, account string, need *big.Int) (pb.Sign
 		return pb.SignatureInfo{}, errors.New("Create crypto client error")
 	}
 
-	return keyPair.SignUtxo(bcName, account, need, crypto)
+	lockedUtxoAll := models.NewLockedUtxoAll(utxo.Bcname, utxo.Address)
+	return keyPair.SignUtxo(lockedUtxoAll, crypto)
 }
diff --git a/cmd/client/cmd/consensus.go b/cmd/client/cmd/consensus.go
index e6624b1ab..3d141bcbb 100644
--- a/cmd/client/cmd/consensus.go
+++ b/cmd/client/cmd/consensus.go
@@ -8,23 +8,15 @@ import (
 	"github.com/spf13/cobra"
 )
 
-// AccountCommand account cmd entrance
-type ConsensusCommand struct {
-	cli *Cli
-	cmd *cobra.Command
-}
-
-// NewAccountCommand new account cmd
+// NewConsensusCommand new consensus cmd
 func NewConsensusCommand(cli *Cli) *cobra.Command {
-	c := new(AccountCommand)
-	c.cli = cli
-	c.cmd = &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "consensus",
 		Short: "Consensus module: status|invoke.",
 	}
-	c.cmd.AddCommand(NewConsensusInvokeCommand(cli))
-	c.cmd.AddCommand(NewConsensusStatusCommand(cli))
-	return c.cmd
+	cmd.AddCommand(NewConsensusInvokeCommand(cli))
+	cmd.AddCommand(NewConsensusStatusCommand(cli))
+	return cmd
 }
 
 func init() {
diff --git a/cmd/client/cmd/consensus_invoke.go b/cmd/client/cmd/consensus_invoke.go
index d996f86b5..ac159c0e6 100644
--- a/cmd/client/cmd/consensus_invoke.go
+++ b/cmd/client/cmd/consensus_invoke.go
@@ -27,10 +27,9 @@ type ConsensusInvokeCommand struct {
 	cmd *cobra.Command
 
 	module     string
-	chain      string
 	bucket     string
 	method     string
-	descfile   string
+	descFile   string
 	account    string
 	fee        string
 	isMulti    bool
@@ -66,7 +65,7 @@ func NewConsensusInvokeCommand(cli *Cli) *cobra.Command {
 }
 
 func (c *ConsensusInvokeCommand) addFlags() {
-	c.cmd.Flags().StringVar(&c.descfile, "desc", "", "The json config file for consensus.")
+	c.cmd.Flags().StringVar(&c.descFile, "desc", "", "The json config file for consensus.")
 	c.cmd.Flags().StringVarP(&c.bucket, "type", "t", "", "consensus bucket name")
 	c.cmd.Flags().StringVarP(&c.method, "method", "", "", "kernel method name")
 	c.cmd.Flags().StringVarP(&c.account, "account", "", "", "account name")
@@ -114,11 +113,11 @@ func (c *ConsensusInvokeCommand) tdposInvoke(ctx context.Context, ct *CommTrans)
 		return nil
 	}
 	// tdpos必须有input json数据
-	if c.descfile == "" {
+	if c.descFile == "" {
 		return fmt.Errorf("tdpos needs desc file.\n")
 	}
 	args := make(map[string]interface{})
-	desc, err := ioutil.ReadFile(c.descfile)
+	desc, err := ioutil.ReadFile(c.descFile)
 	if err != nil {
 		return err
 	}
@@ -172,7 +171,7 @@ func (c *ConsensusInvokeCommand) xpoaInvoke(ctx context.Context, ct *CommTrans)
 		return err
 	}
 	args := make(map[string]interface{})
-	desc, err := ioutil.ReadFile(c.descfile)
+	desc, err := ioutil.ReadFile(c.descFile)
 	if err != nil {
 		return err
 	}
diff --git a/cmd/client/cmd/consensus_status.go b/cmd/client/cmd/consensus_status.go
index 99da43974..edcf04ebb 100644
--- a/cmd/client/cmd/consensus_status.go
+++ b/cmd/client/cmd/consensus_status.go
@@ -13,8 +13,6 @@ import (
 // 本文件封装了和共识模块有关的client调用接口, 具体格式为:
 // xchain-cli consensus status 当前共识状态
 
-const statusBucket = "$consensus"
-
 type ConsensusStatusCommand struct {
 	cli *Cli
 	cmd *cobra.Command
diff --git a/cmd/client/cmd/contract.go b/cmd/client/cmd/contract.go
index 81b8d2c83..6311a25e3 100644
--- a/cmd/client/cmd/contract.go
+++ b/cmd/client/cmd/contract.go
@@ -4,10 +4,6 @@ import (
 	"github.com/spf13/cobra"
 )
 
-// ContractCommand contract cmd
-type ContractCommand struct {
-}
-
 // NewContractCommand new contract cmd
 func NewContractCommand(cli *Cli) *cobra.Command {
 	cmd := &cobra.Command{
diff --git a/cmd/client/cmd/evm.go b/cmd/client/cmd/evm.go
index 12be37345..1a1f9838a 100644
--- a/cmd/client/cmd/evm.go
+++ b/cmd/client/cmd/evm.go
@@ -6,10 +6,6 @@ package cmd
 
 import "github.com/spf13/cobra"
 
-// EvmCommand evm cmd struct
-type EvmCommand struct {
-}
-
 // NewEvmCommand new evm cmd
 func NewEvmCommand(cli *Cli) *cobra.Command {
 	cmd := &cobra.Command{
diff --git a/cmd/client/cmd/govern_token.go b/cmd/client/cmd/govern_token.go
index 5e804dd22..47dd3f1ac 100644
--- a/cmd/client/cmd/govern_token.go
+++ b/cmd/client/cmd/govern_token.go
@@ -8,24 +8,16 @@ import (
 	"github.com/spf13/cobra"
 )
 
-// GovernTokenCommand govern token cmd entrance
-type GovernTokenCommand struct {
-	cli *Cli
-	cmd *cobra.Command
-}
-
 // NewGovernTokenCommand new govern token cmd
 func NewGovernTokenCommand(cli *Cli) *cobra.Command {
-	c := new(ProposalCommand)
-	c.cli = cli
-	c.cmd = &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "governToken",
 		Short: "governToken: init|transfer|query.",
 	}
-	c.cmd.AddCommand(NewGovernInitCommand(cli))
-	c.cmd.AddCommand(NewGovernTransferCommand(cli))
-	c.cmd.AddCommand(NewGovernTokenQueryCommand(cli))
-	return c.cmd
+	cmd.AddCommand(NewGovernInitCommand(cli))
+	cmd.AddCommand(NewGovernTransferCommand(cli))
+	cmd.AddCommand(NewGovernTokenQueryCommand(cli))
+	return cmd
 }
 
 func init() {
diff --git a/cmd/client/cmd/govern_token_init.go b/cmd/client/cmd/govern_token_init.go
index f43b68928..0d9b4787d 100644
--- a/cmd/client/cmd/govern_token_init.go
+++ b/cmd/client/cmd/govern_token_init.go
@@ -17,9 +17,7 @@ type GovernInitCommand struct {
 	cli *Cli
 	cmd *cobra.Command
 
-	receiver string
-	amount   string
-	fee      string
+	fee string
 }
 
 // NewGovernInitCommand new transfer govern token cmd
diff --git a/cmd/client/cmd/govern_token_query.go b/cmd/client/cmd/govern_token_query.go
index e5a709297..dd40f9447 100644
--- a/cmd/client/cmd/govern_token_query.go
+++ b/cmd/client/cmd/govern_token_query.go
@@ -18,8 +18,6 @@ type GovernTokenQueryCommand struct {
 	cmd *cobra.Command
 
 	module     string
-	args       string
-	methodName string
 	isMulti    bool
 	verbose    bool
 	multiAddrs string
diff --git a/cmd/client/cmd/multisig.go b/cmd/client/cmd/multisig.go
index 788e49fdd..09ad56fea 100644
--- a/cmd/client/cmd/multisig.go
+++ b/cmd/client/cmd/multisig.go
@@ -6,10 +6,6 @@ package cmd
 
 import "github.com/spf13/cobra"
 
-// MultisigCommand Multisig set command
-type MultisigCommand struct {
-}
-
 // MultisigData generated multisig data
 type MultisigData struct {
 	R       []byte   // common random value
diff --git a/cmd/client/cmd/multisig_get.go b/cmd/client/cmd/multisig_get.go
index 212e2099a..ef18342ae 100644
--- a/cmd/client/cmd/multisig_get.go
+++ b/cmd/client/cmd/multisig_get.go
@@ -42,17 +42,19 @@ func NewGetComplianceCheckSignCommand(cli *Cli) *cobra.Command {
 	return c.cmd
 }
 
-func (c *GetComplianceCheckSignCommand) initXendorserClient() error {
+func (c *GetComplianceCheckSignCommand) initXEndorserClient() error {
+	//nolint:SA1019
 	conn, err := grpc.Dial(c.cli.RootOptions.Host, grpc.WithInsecure(), grpc.WithMaxMsgSize(64<<20-1))
 	if err != nil {
 		return err
 	}
+
 	c.xendorserclient = pb.NewXendorserClient(conn)
 	return nil
 }
 
 func (c *GetComplianceCheckSignCommand) XEndorserClient() pb.XendorserClient {
-	c.initXendorserClient()
+	_ = c.initXEndorserClient()
 	return c.xendorserclient
 }
 
diff --git a/cmd/client/cmd/native.go b/cmd/client/cmd/native.go
index 8709f8ac3..e1f33a844 100644
--- a/cmd/client/cmd/native.go
+++ b/cmd/client/cmd/native.go
@@ -6,10 +6,6 @@ package cmd
 
 import "github.com/spf13/cobra"
 
-// NativeCommand native cmd struct
-type NativeCommand struct {
-}
-
 // NewNativeCommand new native cmd
 func NewNativeCommand(cli *Cli) *cobra.Command {
 	cmd := &cobra.Command{
diff --git a/cmd/client/cmd/neturl.go b/cmd/client/cmd/neturl.go
index 6ff34a145..75ad6a2b9 100644
--- a/cmd/client/cmd/neturl.go
+++ b/cmd/client/cmd/neturl.go
@@ -8,10 +8,6 @@ import (
 	"github.com/spf13/cobra"
 )
 
-// NetURLCommand neturl cmd
-type NetURLCommand struct {
-}
-
 // NewNetURLCommand new neturl cmd
 func NewNetURLCommand(cli *Cli) *cobra.Command {
 	cmd := &cobra.Command{
diff --git a/cmd/client/cmd/proposal.go b/cmd/client/cmd/proposal.go
index 345951fa0..71abc5a20 100644
--- a/cmd/client/cmd/proposal.go
+++ b/cmd/client/cmd/proposal.go
@@ -8,25 +8,17 @@ import (
 	"github.com/spf13/cobra"
 )
 
-// ProposalCommand proposal cmd entrance
-type ProposalCommand struct {
-	cli *Cli
-	cmd *cobra.Command
-}
-
 // NewProposalCommand new proposal cmd
 func NewProposalCommand(cli *Cli) *cobra.Command {
-	c := new(ProposalCommand)
-	c.cli = cli
-	c.cmd = &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "proposal",
 		Short: "proposal: propose|vote|thaw|query.",
 	}
-	c.cmd.AddCommand(NewProposalProposeCommand(cli))
-	c.cmd.AddCommand(NewProposalQueryCommand(cli))
-	c.cmd.AddCommand(NewProposalVoteCommand(cli))
-	c.cmd.AddCommand(NewProposalThawCommand(cli))
-	return c.cmd
+	cmd.AddCommand(NewProposalProposeCommand(cli))
+	cmd.AddCommand(NewProposalQueryCommand(cli))
+	cmd.AddCommand(NewProposalVoteCommand(cli))
+	cmd.AddCommand(NewProposalThawCommand(cli))
+	return cmd
 }
 
 func init() {
diff --git a/cmd/client/cmd/proposal_query.go b/cmd/client/cmd/proposal_query.go
index efbf601ed..1703d5c5d 100644
--- a/cmd/client/cmd/proposal_query.go
+++ b/cmd/client/cmd/proposal_query.go
@@ -18,8 +18,6 @@ type ProposalQueryCommand struct {
 	cmd *cobra.Command
 
 	module     string
-	args       string
-	methodName string
 	isMulti    bool
 	verbose    bool
 	multiAddrs string
diff --git a/cmd/client/cmd/proposal_thaw.go b/cmd/client/cmd/proposal_thaw.go
index 1ae100b6f..415fdd619 100644
--- a/cmd/client/cmd/proposal_thaw.go
+++ b/cmd/client/cmd/proposal_thaw.go
@@ -19,7 +19,6 @@ type ProposalThawCommand struct {
 	cmd *cobra.Command
 
 	proposalID string
-	amount     string
 	fee        string
 }
 
diff --git a/cmd/client/cmd/tdpos.go b/cmd/client/cmd/tdpos.go
index 27e27b1e7..d845ac2ae 100644
--- a/cmd/client/cmd/tdpos.go
+++ b/cmd/client/cmd/tdpos.go
@@ -6,10 +6,6 @@ package cmd
 
 import "github.com/spf13/cobra"
 
-// TDposCommand tdpos cmd
-type TDposCommand struct {
-}
-
 // NewTDposCommand new tdpos cmd
 func NewTDposCommand(cli *Cli) *cobra.Command {
 	cmd := &cobra.Command{
diff --git a/cmd/client/cmd/transfer.go b/cmd/client/cmd/transfer.go
index 98c8b013c..ae416c0bd 100644
--- a/cmd/client/cmd/transfer.go
+++ b/cmd/client/cmd/transfer.go
@@ -53,7 +53,7 @@ type TransferCommand struct {
 
 	to           string
 	amount       string
-	descfile     string
+	descFile     string
 	fee          string
 	frozenHeight int64
 	version      int32
@@ -69,7 +69,7 @@ func NewTransferCommand(cli *Cli) *cobra.Command {
 	t.cli = cli
 	t.cmd = &cobra.Command{
 		Use:   "transfer",
-		Short: "Operate transfer trasaction, transfer tokens between accounts or aks",
+		Short: "Operate transfer transaction, transfer tokens between accounts or aks",
 		RunE: func(cmd *cobra.Command, args []string) error {
 			ctx := context.TODO()
 			return t.transfer(ctx)
@@ -82,7 +82,7 @@ func NewTransferCommand(cli *Cli) *cobra.Command {
 func (t *TransferCommand) addFlags() {
 	t.cmd.Flags().StringVar(&t.to, "to", "", "common transfer transaction to whom")
 	t.cmd.Flags().StringVar(&t.amount, "amount", "0", "transfer tokens")
-	t.cmd.Flags().StringVar(&t.descfile, "desc", "", "desc file of tx, eg. contract or tdpos consensus")
+	t.cmd.Flags().StringVar(&t.descFile, "desc", "", "desc file of tx, eg. contract or tdpos consensus")
 	t.cmd.Flags().StringVar(&t.fee, "fee", "0", "fee of one tx")
 	t.cmd.Flags().Int64Var(&t.frozenHeight, "frozen", 0, "frozen height of one tx")
 	t.cmd.Flags().Int32Var(&t.version, "txversion", utxo.TxVersion, "tx version")
@@ -116,7 +116,7 @@ func readPrivateKey(path string) (string, error) {
 type invokeRequestWrapper struct {
 	pb.InvokeRequest
 	// 取巧的手段来shadow pb.InvokeRequest里面的Args字段
-	Args map[string]string `json:"args,omitempty"`
+	Args map[string]string `json:"args,omitempty"` //nolint:structtag
 }
 
 func newFeeAccount(fee string) *pb.TxDataAccount {
@@ -127,10 +127,10 @@ func newFeeAccount(fee string) *pb.TxDataAccount {
 }
 
 func (t *TransferCommand) getDesc() ([]byte, error) {
-	if t.descfile == "" {
+	if t.descFile == "" {
 		return []byte("transfer from console"), nil
 	}
-	return ioutil.ReadFile(t.descfile)
+	return ioutil.ReadFile(t.descFile)
 }
 
 func (t *TransferCommand) transfer(ctx context.Context) error {
diff --git a/cmd/client/cmd/tx.go b/cmd/client/cmd/tx.go
index 19f1f7ea5..42f03f2e7 100644
--- a/cmd/client/cmd/tx.go
+++ b/cmd/client/cmd/tx.go
@@ -8,10 +8,6 @@ import (
 	"github.com/spf13/cobra"
 )
 
-// TxCommand tx cmd
-type TxCommand struct {
-}
-
 // NewTxCommand new tx cmd
 func NewTxCommand(cli *Cli) *cobra.Command {
 	cmd := &cobra.Command{
diff --git a/cmd/client/cmd/utxo.go b/cmd/client/cmd/utxo.go
index bb4ebe3a7..b64c7528e 100644
--- a/cmd/client/cmd/utxo.go
+++ b/cmd/client/cmd/utxo.go
@@ -2,25 +2,17 @@ package cmd
 
 import "github.com/spf13/cobra"
 
-// UtxoCommand utxo cmd entry
-type UtxoCommand struct {
-	cli *Cli
-	cmd *cobra.Command
-}
-
 // NewUtxoCommand init child utxo command
 func NewUtxoCommand(cli *Cli) *cobra.Command {
-	c := new(UtxoCommand)
-	c.cli = cli
-	c.cmd = &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "utxo",
 		Short: "Operate an utxo: list|merge|split.",
 	}
-	c.cmd.AddCommand(NewListUtxoCommand(cli))
-	c.cmd.AddCommand(NewMergeUtxoCommand(cli))
-	c.cmd.AddCommand(NewSplitUtxoCommand(cli))
+	cmd.AddCommand(NewListUtxoCommand(cli))
+	cmd.AddCommand(NewMergeUtxoCommand(cli))
+	cmd.AddCommand(NewSplitUtxoCommand(cli))
 
-	return c.cmd
+	return cmd
 }
 
 func init() {
diff --git a/cmd/client/cmd/utxo_merge.go b/cmd/client/cmd/utxo_merge.go
index 4f1ce0189..df7c89c83 100644
--- a/cmd/client/cmd/utxo_merge.go
+++ b/cmd/client/cmd/utxo_merge.go
@@ -79,6 +79,9 @@ func (c *MergeUtxoCommand) mergeUtxo(_ context.Context) error {
 	}
 
 	txInputs, txOutput, err := ct.GenTxInputsWithMergeUTXO(context.Background())
+	if err != nil {
+		return err
+	}
 	tx.TxInputs = txInputs
 	// validation check
 	if len(tx.TxInputs) == 0 {
diff --git a/cmd/client/cmd/utxo_split.go b/cmd/client/cmd/utxo_split.go
index 9f319a027..7e5e3421f 100644
--- a/cmd/client/cmd/utxo_split.go
+++ b/cmd/client/cmd/utxo_split.go
@@ -104,6 +104,9 @@ func (c *SplitUtxoCommand) splitUtxo(_ context.Context) error {
 	}
 
 	txInputs, txOutput, err := ct.GenTxInputs(context.Background(), totalNeed)
+	if err != nil {
+		return err
+	}
 	tx.TxInputs = txInputs
 
 	txOutputs, err := c.genSplitOutputs(totalNeed)
diff --git a/cmd/client/cmd/wasm.go b/cmd/client/cmd/wasm.go
index 3733a8ac9..0a30826a0 100644
--- a/cmd/client/cmd/wasm.go
+++ b/cmd/client/cmd/wasm.go
@@ -6,10 +6,6 @@ package cmd
 
 import "github.com/spf13/cobra"
 
-// WasmCommand wasm cmd
-type WasmCommand struct {
-}
-
 // NewWasmCommand new wasm cmd
 func NewWasmCommand(cli *Cli) *cobra.Command {
 	cmd := &cobra.Command{
diff --git a/cmd/client/cmd/watch.go b/cmd/client/cmd/watch.go
index 5df6c25cc..f41071aaf 100644
--- a/cmd/client/cmd/watch.go
+++ b/cmd/client/cmd/watch.go
@@ -17,7 +17,7 @@ type watchCommand struct {
 	cmd *cobra.Command
 
 	filter      string
-	oneline     bool
+	oneLine     bool
 	skipEmptyTx bool
 }
 
@@ -38,7 +38,7 @@ func newWatchCommand(cli *Cli) *cobra.Command {
 
 func (c *watchCommand) addFlags() {
 	c.cmd.Flags().StringVarP(&c.filter, "filter", "f", "{}", "filter options")
-	c.cmd.Flags().BoolVarP(&c.oneline, "oneline", "", false, "whether print one event one line")
+	c.cmd.Flags().BoolVarP(&c.oneLine, "oneline", "", false, "whether print one event one line")
 	c.cmd.Flags().BoolVarP(&c.skipEmptyTx, "skip-empty-tx", "", false, "whether print block with no tx matched")
 }
 
@@ -57,8 +57,8 @@ func (c *watchCommand) watch(ctx context.Context) error {
 		Filter: buf,
 	}
 
-	xclient := c.cli.EventClient()
-	stream, err := xclient.Subscribe(ctx, request)
+	client := c.cli.EventClient()
+	stream, err := client.Subscribe(ctx, request)
 	if err != nil {
 		return err
 	}
@@ -80,13 +80,12 @@ func (c *watchCommand) watch(ctx context.Context) error {
 		}
 		c.printBlock(&block)
 	}
-	return nil
 }
 
 func (c *watchCommand) printBlock(pbblock *pb.FilteredBlock) {
 	block := FromFilteredBlockPB(pbblock)
 	var buf []byte
-	if c.oneline {
+	if c.oneLine {
 		buf, _ = json.Marshal(block)
 	} else {
 		buf, _ = json.MarshalIndent(block, "", "  ")
diff --git a/cmd/client/cmd/xkernel.go b/cmd/client/cmd/xkernel.go
index e74f3031f..d62bcc44b 100644
--- a/cmd/client/cmd/xkernel.go
+++ b/cmd/client/cmd/xkernel.go
@@ -6,10 +6,6 @@ package cmd
 
 import "github.com/spf13/cobra"
 
-// XKernelCommand xkernel cmd
-type XKernelCommand struct {
-}
-
 // NewXKernelCommand new xkernel cmd
 func NewXKernelCommand(cli *Cli) *cobra.Command {
 	cmd := &cobra.Command{
diff --git a/cmd/xchain/cmd/pruneledger.go b/cmd/xchain/cmd/pruneledger.go
index fe224c960..0886d0cd0 100644
--- a/cmd/xchain/cmd/pruneledger.go
+++ b/cmd/xchain/cmd/pruneledger.go
@@ -134,7 +134,10 @@ func (c *PruneLedgerCommand) pruneLedger(econf *xconfig.EnvConf) error {
 		log.Printf("meta proto marshal error:%v", err)
 		return pbErr
 	}
-	batch.Put([]byte(xldgpb.MetaTablePrefix), metaBuf)
+	if err := batch.Put([]byte(xldgpb.MetaTablePrefix), metaBuf); err != nil {
+		log.Printf("write meta error:%v", err)
+		return err
+	}
 	// 剪掉所有无效分支
 	// step1: 获取所有无效分支
 	branchHeadArr, branchErr := xledger.GetBranchInfo(targetBlockId, targetBlock.Height)
diff --git a/models/chain_handle.go b/models/chain_handle.go
index c74d8f1d8..2a020790b 100644
--- a/models/chain_handle.go
+++ b/models/chain_handle.go
@@ -2,19 +2,17 @@ package models
 
 import (
 	"math/big"
-	"strconv"
 
 	lpb "github.com/xuperchain/xupercore/bcs/ledger/xledger/xldgpb"
 	xCtx "github.com/xuperchain/xupercore/kernel/common/xcontext"
 	"github.com/xuperchain/xupercore/kernel/engines/xuperos/common"
 	"github.com/xuperchain/xupercore/kernel/engines/xuperos/reader"
 	"github.com/xuperchain/xupercore/kernel/engines/xuperos/xpb"
+	aclUtils "github.com/xuperchain/xupercore/kernel/permission/acl/utils"
 	"github.com/xuperchain/xupercore/lib/logs"
 	"github.com/xuperchain/xupercore/protos"
 
 	sCtx "github.com/xuperchain/xuperchain/service/context"
-	aclUtils "github.com/xuperchain/xupercore/kernel/permission/acl/utils"
-	cryptoHash "github.com/xuperchain/xupercore/lib/crypto/hash"
 )
 
 type ChainHandle struct {
@@ -178,11 +176,10 @@ func (h *ChainHandle) checkSelectUtxoSign(account, pubKey string, sign []byte,
 	if err != nil {
 		return false
 	}
-	hashKey := h.bcName + account + need.String() + strconv.FormatBool(isLock)
-	hashValue := cryptoHash.DoubleSha256([]byte(hashKey))
+	lockedUtxo := NewLockedUtxo(h.bcName, account, need)
 
 	// verify sign
-	passed, err := crypto.VerifyECDSA(publicKey, sign, hashValue)
+	passed, err := crypto.VerifyECDSA(publicKey, sign, lockedUtxo.Hash())
 	if err != nil {
 		return false
 	}
diff --git a/models/utxo.go b/models/utxo.go
new file mode 100644
index 000000000..e8fb1163a
--- /dev/null
+++ b/models/utxo.go
@@ -0,0 +1,36 @@
+package models
+
+import (
+	"math/big"
+	"strconv"
+
+	"github.com/xuperchain/xupercore/lib/crypto/hash"
+)
+
+// LockedUtxo UTXO to be locked for operation
+type LockedUtxo struct {
+	bcName  string // blockchain name
+	address string // address for UTXO belongs to
+	amount  *big.Int
+}
+
+// NewLockedUtxo creates a given amount UTXO of the address in the blockchain
+func NewLockedUtxo(bcName, address string, amount *big.Int) *LockedUtxo {
+	return &LockedUtxo{
+		bcName:  bcName,
+		address: address,
+		amount:  amount,
+	}
+}
+
+// NewLockedUtxoAll creates a locked UTXO denotes all UTXO of the address in the blockchain
+func NewLockedUtxoAll(bcName, address string) *LockedUtxo {
+	return NewLockedUtxo(bcName, address, big.NewInt(0))
+}
+
+// Hash gets hash value of locked UTXO for signature
+func (o *LockedUtxo) Hash() []byte {
+	hashKey := o.bcName + o.address + o.amount.String() + strconv.FormatBool(true)
+	hashValue := hash.DoubleSha256([]byte(hashKey))
+	return hashValue
+}
diff --git a/service/gateway/gateway.go b/service/gateway/gateway.go
index a2b1b8374..db83000b5 100644
--- a/service/gateway/gateway.go
+++ b/service/gateway/gateway.go
@@ -111,7 +111,7 @@ func (t *Gateway) runGateway() error {
 
 func (t *Gateway) stopGateway() {
 	if t.server != nil {
-		t.server.Shutdown(context.Background())
+		_ = t.server.Shutdown(context.Background())
 	}
 }
 
@@ -143,5 +143,4 @@ func (t *Gateway) preflightHandler(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Access-Control-Allow-Headers", strings.Join(headers, ","))
 	methods := []string{"GET", "HEAD", "POST", "PUT", "DELETE"}
 	w.Header().Set("Access-Control-Allow-Methods", strings.Join(methods, ","))
-	return
 }
diff --git a/service/manage.go b/service/manage.go
index 29e0581e6..f8bd9644f 100644
--- a/service/manage.go
+++ b/service/manage.go
@@ -54,7 +54,7 @@ func NewServMG(scfg *sconf.ServConf, engine engines.BCEngine) (*ServMG, error) {
 
 // 启动rpc服务
 func (t *ServMG) Run() error {
-	ch := make(chan error, 0)
+	ch := make(chan error)
 	defer close(ch)
 
 	for _, serv := range t.servers {
@@ -71,11 +71,9 @@ func (t *ServMG) Run() error {
 			break
 		}
 
-		select {
-		case err := <-ch:
-			t.log.Warn("service exit", "err", err)
-			exitCnt++
-		}
+		err := <-ch
+		t.log.Warn("service exit", "err", err)
+		exitCnt++
 	}
 
 	return nil
diff --git a/service/rpc/api.go b/service/rpc/api.go
index e50e00ac5..f223aec5e 100644
--- a/service/rpc/api.go
+++ b/service/rpc/api.go
@@ -51,7 +51,9 @@ func (t *RpcServ) PostTx(gctx context.Context, req *pb.TxStatus) (*pb.CommonRepl
 			p2p.WithBCName(req.GetBcname()),
 			p2p.WithLogId(rctx.GetLog().GetLogId()),
 		)
-		go t.engine.Context().Net.SendMessage(rctx, msg)
+		go func() {
+			_ = t.engine.Context().Net.SendMessage(rctx, msg)
+		}()
 	}
 	rctx.GetLog().SetInfoField("bc_name", req.GetBcname())
 	rctx.GetLog().SetInfoField("txid", utils.F(req.GetTxid()))
@@ -369,7 +371,7 @@ func (t *RpcServ) GetAccountContracts(gctx context.Context, req *pb.GetAccountCo
 		return resp, err
 	}
 	xchainContractStatus, err := acom.ContractStatusListToXchain(res)
-	if xchainContractStatus == nil {
+	if err != nil || xchainContractStatus == nil {
 		rctx.GetLog().Warn("convert acl failed")
 		return resp, ecom.ErrInternal
 	}


Test patch:
diff --git a/cmd/client/cmd/ak_test.go b/cmd/client/cmd/ak_test.go
index 4b3cf225b..d6f8eeb12 100644
--- a/cmd/client/cmd/ak_test.go
+++ b/cmd/client/cmd/ak_test.go
@@ -13,6 +13,8 @@ import (
 	"testing"
 
 	"github.com/xuperchain/crypto/common/account"
+
+	"github.com/xuperchain/xuperchain/models"
 	"github.com/xuperchain/xuperchain/service/pb"
 )
 
@@ -288,7 +290,6 @@ func TestAK_SignTx(t *testing.T) {
 // TODO: mock common.ComputeTxSign after unit test covers
 func TestKeyPair_SignTx(t *testing.T) {
 	type fields struct {
-		publicKey string
 		secretKey string
 	}
 	type args struct {
@@ -349,7 +350,6 @@ func TestKeyPair_SignTx(t *testing.T) {
 
 func TestKeyPair_SignUtxo(t *testing.T) {
 	type fields struct {
-		publicKey string
 		secretKey string
 	}
 	tests := []struct {
@@ -383,7 +383,8 @@ func TestKeyPair_SignUtxo(t *testing.T) {
 				publicKey: testPublicKey,
 				secretKey: tt.fields.secretKey,
 			}
-			got, err := p.SignUtxo("xuper", testAccount, big.NewInt(1), mockCryptoClient{})
+			utxo := models.NewLockedUtxo("xuper", testAccount, big.NewInt(1))
+			got, err := p.SignUtxo(utxo, mockCryptoClient{})
 			if (err != nil) != tt.wantErr {
 				t.Errorf("KeyPair.SignUtxo() error = %v, wantErr %v", err, tt.wantErr)
 				return
diff --git a/models/utxo_test.go b/models/utxo_test.go
new file mode 100644
index 000000000..50473003c
--- /dev/null
+++ b/models/utxo_test.go
@@ -0,0 +1,45 @@
+package models
+
+import (
+	"encoding/hex"
+	"math/big"
+	"testing"
+)
+
+func TestLockedUtxo_Hash(t *testing.T) {
+
+	type fields struct {
+		bcName  string
+		address string
+		amount  *big.Int
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		want   string // hex string format of hashed value
+	}{
+		{
+			name: "compatibility",
+			fields: fields{
+				bcName:  "xuper",
+				address: "TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY",
+				amount:  big.NewInt(0),
+			},
+			want: "21eb1c4c51abeb7c19cfffdb21b1cf685deee636d0aae77a6b73fa1ff2c4855c",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			o := &LockedUtxo{
+				bcName:  tt.fields.bcName,
+				address: tt.fields.address,
+				amount:  tt.fields.amount,
+			}
+			if got := o.Hash(); hex.EncodeToString(got) != tt.want {
+				t.Errorf("LockedUtxo.Hash() = %v,\n"+
+					"want %v",
+					hex.EncodeToString(got), tt.want)
+			}
+		})
+	}
+}
diff --git a/service/rpc/endorser_test.go b/service/rpc/endorser_test.go
index b33178604..96d04416b 100644
--- a/service/rpc/endorser_test.go
+++ b/service/rpc/endorser_test.go
@@ -48,7 +48,7 @@ func TestEndorserCall(t *testing.T) {
 	os.RemoveAll(workspace)
 	defer os.RemoveAll(workspace)
 	conf, _ := mock.NewEnvConfForTest()
-	defer RemoveLedger(conf)
+	defer removeLedger(conf)
 
 	engine, err := MockEngine()
 	if err != nil {
@@ -59,6 +59,9 @@ func TestEndorserCall(t *testing.T) {
 
 	endor := NewDefaultXEndorser(rpcServ, engine)
 	awardTx, err := txn.GenerateAwardTx("miner", "1000", []byte("award"))
+	if err != nil {
+		t.Fatalf("txn.GenerateAwardTx() err: %s", err)
+	}
 
 	txStatus := &pb.TxStatus{
 		Bcname: "xuper",
@@ -146,8 +149,7 @@ func MockEngine() (common.Engine, error) {
 		return nil, fmt.Errorf("new env conf error: %v", err)
 	}
 
-	RemoveLedger(conf)
-	if err = CreateLedger(conf); err != nil {
+	if err = createLedger(conf); err != nil {
 		return nil, err
 	}
 
@@ -164,16 +166,17 @@ func MockEngine() (common.Engine, error) {
 	return eng, nil
 }
 
-func RemoveLedger(conf *xconf.EnvConf) error {
+func removeLedger(conf *xconf.EnvConf) {
 	path := conf.GenDataAbsPath("blockchain")
 	if err := os.RemoveAll(path); err != nil {
 		log.Printf("remove ledger failed.err:%v\n", err)
-		return err
 	}
-	return nil
 }
 
-func CreateLedger(conf *xconf.EnvConf) error {
+func createLedger(conf *xconf.EnvConf) error {
+	// init env
+	removeLedger(conf)
+
 	mockConf, err := mock.NewEnvConfForTest()
 	if err != nil {
 		return fmt.Errorf("new mock env conf error: %v", err)