新注册的用户请输入邮箱并保存,随后登录邮箱激活账号。后续可直接使用邮箱登录!

Commit aed12b04 authored by anadanxu's avatar anadanxu

fix: unzip 7z file timeout when install go contract caused tx scheduling...

fix: unzip 7z file timeout when install go contract caused tx scheduling failed repeatedly --bug=1011088
parent fa8c23d4
......@@ -10,6 +10,7 @@ package contractmgr
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
......@@ -19,6 +20,7 @@ import (
"path/filepath"
"sort"
"strings"
"time"
"chainmaker.org/chainmaker/pb-go/v2/accesscontrol"
commonPb "chainmaker.org/chainmaker/pb-go/v2/common"
......@@ -37,6 +39,11 @@ const (
blockVersion231 = 2030100
blockVersion2312 = 2030102
blockVersion235 = 2030500
// unzipTimeout is the timeout for unzip go contract 7z files, unit: seconds
// The timeout period for transaction execution is set at 9 seconds,
// Therefore, 7 seconds is adopted here as the timeout period.
unzipTimeout = 7
)
var (
......@@ -723,7 +730,7 @@ func (r *ContractManagerRuntime) saveContract(context protocol.TxSimContext, nam
}
var extBytecode []byte
if context.GetBlockVersion() >= 2300 && runTime == commonPb.RuntimeType_DOCKER_GO {
extBytecode, err = r.checkGoContractVersion(contract, byteCode)
extBytecode, err = r.checkGoContractVersion(contract, byteCode, context.GetBlockVersion())
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to check contract bin version, %v", err)
}
......@@ -950,7 +957,7 @@ func (r *ContractManagerRuntime) upgrade(context protocol.TxSimContext, contract
var extBytecode []byte
var err error
if contract.RuntimeType == commonPb.RuntimeType_DOCKER_GO {
extBytecode, err = r.checkGoContractVersion(contract, byteCode)
extBytecode, err = r.checkGoContractVersion(contract, byteCode, context.GetBlockVersion())
if err != nil {
return nil, nil, fmt.Errorf("failed to check contract bin version, %v", err)
}
......@@ -1191,7 +1198,8 @@ func (r *ContractManagerRuntime) InitNewNativeContract(txSimContext protocol.TxS
return json.Marshal(returnContracts)
}
func (r *ContractManagerRuntime) checkGoContractVersion(contract *commonPb.Contract, byteCode []byte) ([]byte, error) {
func (r *ContractManagerRuntime) checkGoContractVersion(contract *commonPb.Contract,
byteCode []byte, blockVersion uint32) ([]byte, error) {
// tmp contract dir (include .7z and bin files)
tmpContractDir := "tmp-contract-" + uuid.New().String()
......@@ -1206,16 +1214,6 @@ func (r *ContractManagerRuntime) checkGoContractVersion(contract *commonPb.Contr
return nil, fmt.Errorf("failed to save tmp contract bin for version query")
}
// extract 7z file
unzipCommand := fmt.Sprintf("7z e %s -o%s -y", contractZipPath, tmpContractDir) // contract1
err = runCmd(unzipCommand)
if err != nil {
if strings.Contains(err.Error(), tmpContractDir) {
return nil, fmt.Errorf("failed to extract contract")
}
return nil, fmt.Errorf("failed to extract contract, %v", err)
}
// remove tmpContractDir in the end
defer func() {
if err = os.RemoveAll(tmpContractDir); err != nil {
......@@ -1223,6 +1221,37 @@ func (r *ContractManagerRuntime) checkGoContractVersion(contract *commonPb.Contr
}
}()
if blockVersion >= protocol.BlockVersion240 {
// extract 7z file with a timeout context
ctx, cancel := context.WithTimeout(context.Background(), unzipTimeout*time.Second)
defer cancel()
unzipCommand := exec.CommandContext(ctx, "7z", "e", contractZipPath, "-o"+tmpContractDir, "-y")
// set process group for the 7z command, in order to kill it and its child processes by once when timeout
setProcessGroup(unzipCommand)
err = unzipCommand.Run()
if err != nil {
if er := killProcess(unzipCommand); er != nil {
r.log.Errorf("kill unzip process failed, error: %+v", er)
}
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
return nil, fmt.Errorf("timeout: failed to extract contract in %d seconds", unzipTimeout)
}
r.log.Errorf("failed to extract contract, error: %+v", err)
return nil, fmt.Errorf("failed to extract contract")
}
} else {
// extract 7z file
unzipCommand := fmt.Sprintf("7z e %s -o%s -y", contractZipPath, tmpContractDir)
err = runCmd(unzipCommand)
if err != nil {
if strings.Contains(err.Error(), tmpContractDir) {
return nil, fmt.Errorf("failed to extract contract")
}
return nil, fmt.Errorf("failed to extract contract, %v", err)
}
}
// exec contract bin to get version
// read all files in tmpContractDir
fileInfoList, err := ioutil.ReadDir(tmpContractDir)
......
//go:build linux
// +build linux
/*
* Copyright (C) BABEC. All rights reserved.
* Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package contractmgr
import (
"os/exec"
"syscall"
)
// setProcessGroup sets process group
func setProcessGroup(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
}
// killProcess kills process group
func killProcess(cmd *exec.Cmd) error {
if cmd.Process == nil {
return nil
}
return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
}
//go:build darwin
// +build darwin
/*
* Copyright (C) BABEC. All rights reserved.
* Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package contractmgr
import (
"os/exec"
"syscall"
)
// setProcessGroup sets process group
func setProcessGroup(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
}
// killProcess kills process group
func killProcess(cmd *exec.Cmd) error {
if cmd.Process == nil {
return nil
}
return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
}
//go:build windows
// +build windows
/*
* Copyright (C) BABEC. All rights reserved.
* Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
package contractmgr
import (
"os/exec"
)
// setProcessGroup sets process group
func setProcessGroup(cmd *exec.Cmd) {
panic("windows doesn't support docker-go contracts")
}
// killProcess kills process group
func killProcess(cmd *exec.Cmd) error {
panic("windows doesn't support docker-go contracts")
}
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