SDK 内部的 GlobalStateStore 为 nil,导致调用 PutStateByte 时空指针访问,代码检查没有问题
使用SmartEditor编写的go合约部署成功后,在合约容器中执行时,出现: ChainMaker Sandbox/VM 中运行时触发 nil pointer panic,原因为SDK 内部的 GlobalStateStore 为 nil,导致调用 PutStateByte 时空指针访问。 go合约代码如下: package main
import ( "encoding/json" "fmt" "log" "strconv"
"chainmaker/pb/protogo"
"chainmaker/sandbox"
"chainmaker/sdk"
)
// 合约主结构 type FactContract struct { }
// 存证对象:用户信息 type Fact struct { ID string Username string Sex string Age int }
// 新建存证对象 func NewFact(id, username, sex string, age int) *Fact { return &Fact{ ID: id, Username: username, Sex: sex, Age: age, } }
// 初始化合约 func (f *FactContract) InitContract() protogo.Response { return sdk.Success([]byte("Init contract success")) }
// 升级合约 func (f *FactContract) UpgradeContract() protogo.Response { return sdk.Success([]byte("Upgrade contract success")) }
// 合约调用入口 func (f *FactContract) InvokeContract(method string) protogo.Response { switch method { case "save": return f.Save() case "findByID": return f.FindByID() default: return sdk.Error("invalid method") } }
// 保存存证对象 func (f *FactContract) Save() protogo.Response { sdkInstance := sdk.Instance if sdkInstance == nil { return sdk.Error("SDK instance is nil") }
params := sdkInstance.GetArgs()
if params == nil {
return sdk.Error("transaction args are nil")
}
// 参数检查
idBytes, ok := params["id"]
if !ok || len(idBytes) == 0 {
return sdk.Error("missing 'id' argument")
}
usernameBytes, ok := params["username"]
if !ok || len(usernameBytes) == 0 {
return sdk.Error("missing 'username' argument")
}
sexBytes, ok := params["sex"]
if !ok {
sexBytes = []byte("")
}
ageBytes, ok := params["age"]
if !ok || len(ageBytes) == 0 {
return sdk.Error("missing 'age' argument")
}
id := string(idBytes)
username := string(usernameBytes)
sex := string(sexBytes)
age, err := strconv.Atoi(string(ageBytes))
if err != nil {
msg := fmt.Sprintf("age is [%s] not int", string(ageBytes))
sdkInstance.Errorf(msg)
return sdk.Error(msg)
}
// 构建 Fact 对象
fact := NewFact(id, username, sex, age)
// 序列化
factBytes, err := json.Marshal(fact)
if err != nil {
return sdk.Error(fmt.Sprintf("marshal fact failed, err: %s", err))
}
// 发送事件
sdkInstance.EmitEvent("user_event", []string{fact.ID, fact.Username})
// 存储状态
err = sdkInstance.PutStateByte("fact_bytes", fact.ID, factBytes)
if err != nil {
return sdk.Error(fmt.Sprintf("fail to save fact bytes, err: %s", err))
}
// 日志记录
sdkInstance.Infof("[save] id=%s, username=%s", fact.ID, fact.Username)
return sdk.Success([]byte(fmt.Sprintf("save success, id=%s", fact.ID)))
}
// 根据 ID 查询存证对象 func (f *FactContract) FindByID() protogo.Response { sdkInstance := sdk.Instance if sdkInstance == nil { return sdk.Error("SDK instance is nil") }
params := sdkInstance.GetArgs()
if params == nil {
return sdk.Error("transaction args are nil")
}
idBytes, ok := params["id"]
if !ok || len(idBytes) == 0 {
return sdk.Error("missing 'id' argument")
}
id := string(idBytes)
// 查询存储的数据
result, err := sdkInstance.GetStateByte("fact_bytes", id)
if err != nil {
return sdk.Error(fmt.Sprintf("failed to call GetStateByte, err: %s", err))
}
if result == nil {
return sdk.Error("no record found for id: " + id)
}
// 反序列化
var fact Fact
if err = json.Unmarshal(result, &fact); err != nil {
return sdk.Error(fmt.Sprintf("unmarshal fact failed, err: %s", err))
}
// 日志记录
sdkInstance.Infof("[find_by_id] id=%s, username=%s", fact.ID, fact.Username)
return sdk.Success(result)
}
// 合约入口 func main() { err := sandbox.Start(new(FactContract)) if err != nil { log.Fatal(err) } }