当我遇到有关 gob Serialize 的问题时,我正在尝试构建一个区块链项目。 我有一个使用 elliptic.P256() Curve 结构的 struct Wallet,当我尝试序列化 Wallet 时,出现了没有导出字段的错误。
真心希望得到一些帮助。
这是我的代码。
const walletFile = "Wallets.dat"
type Wallets struct {
WalletsMap map[string]*Wallet
}
type Wallet struct {
PrivateKey ecdsa.PrivateKey
PublicKey []byte
}
func (w *Wallets) SaveWallets() {
var content bytes.Buffer
gob.Register(elliptic.P256())
encoder := gob.NewEncoder(&content)
err := encoder.Encode(&w)
if err != nil {
log.Panic(err)
}
err = ioutil.WriteFile(walletFile, content.Bytes(), 0644)
if err != nil {
log.Panic(err)
}
}
func NewWallets() (*Wallets, error) {
if _, err := os.Stat(walletFile); os.IsNotExist(err) {
wallets := &Wallets{}
wallets.WalletsMap = make(map[string]*Wallet)
return wallets, err
}
fileContent, err := ioutil.ReadFile(walletFile)
if err != nil {
log.Panic(err)
}
var wallets Wallets
gob.Register(elliptic.P256())
decoder := gob.NewDecoder(bytes.NewReader(fileContent))
err = decoder.Decode(&wallets)
if err != nil {
log.Panic(err)
}
return &wallets, nil
}
问题
2022/09/18 19:42:33 gob: type elliptic.p256Curve has no exported fields
panic: gob: type elliptic.p256Curve has no exported fields
将您的 Go 版本更改为 1.18.10,花费更少。由于最新的 Go 版本,即 1.19.5,我遇到了同样的问题
我们需要用旧的方式降级 Go 版本,因为 Go 不提供像花哨的版本管理器这样的东西。
Go版本降级步骤:
卸载现有的Go版本
要卸载 Go,请找到 Go 在系统上的位置。
$where go
此命令将定位程序
用户路径中的文件。
要卸载,请删除
/usr/local/go
目录或源
您在上一个命令中作为输出收到的目录。
使用命令 $ sudo rm -rf /usr/local/go
删除 Go 目录。
要确认运行命令
$ go version
,
如果你成功删除了Go目录,系统会提示“找不到命令”。
安装新版本
转到downloads 页面并下载与您的操作系统和架构兼容的版本发布(选择安装程序而不是存档以使事情变得简单)。解压缩并提取软件包安装程序,新的 Go 版本现已安装在您的系统中。
$go version
。该命令打印已安装的 Go 版本。另请确保
GOROOT
和
GOPATH
未更改。
在go1.20中,god的序列化需要反射,而
ecdsa.PrivateKey
类型的属性中有接口,可能无法使用。如何解决?
Ecdsa.PrivateKey
也许有专门的序列化方法。演示如下:
type Wallet struct {
PrivateKey ecdsa.PrivateKey
PublicKey []byte
}
func (w *Wallet) Save() {
filename := filepath.Join(constcoe.Wallets, string(w.Address())+".wlt")
privKeyBytes, err := x509.MarshalECPrivateKey(&w.PrivateKey)
utils.Handle(err)
privKeyFile, err := os.Create(filename)
utils.Handle(err)
err = pem.Encode(privKeyFile, &pem.Block{
// Type: "EC PRIVATE KEY",
Bytes: privKeyBytes,
})
utils.Handle(err)
privKeyFile.Close()
}
func LoadWallet(address string) *Wallet {
filename := filepath.Join(constcoe.Wallets, address+".wlt")
if !utils.FileExists(filename) {
utils.Handle(errors.New("no wallet with such address"))
}
privKeyFile, err := os.ReadFile(filename)
utils.Handle(err)
pemBlock, _ := pem.Decode(privKeyFile)
utils.Handle(err)
privKey, err := x509.ParseECPrivateKey(pemBlock.Bytes)
utils.Handle(err)
publicKey := append(privKey.PublicKey.X.Bytes(), privKey.PublicKey.Y.Bytes()...)
return &Wallet{
PrivateKey: *privKey,
PublicKey: publicKey,
}
}
crypto/elliptic
包序列化 P256 曲线。问题是
P256()
函数返回一个名为
elliptic.Curve
的接口。此错误告诉您的是
elliptic.Curve
的基础类型(在本例中为
elliptic.p256Curve
)没有任何导出的字段(以第一个字母大写命名)。
reflect
使用的 Go 的
encoding/gob
包仅适用于导出的字段。您可能想尝试使用
crypto/elliptic
的
Marshal()
或 GenerateKey()
函数。
Github 上找到。我会尝试使用MarshalBinary
。
// wallet.go
func (w Wallet) MarshalJSON() ([]byte, error) {
mapStringAny := map[string]any{
"PrivateKey": map[string]any{
"D": w.PrivateKey.D,
"PublicKey": map[string]any{
"X": w.PrivateKey.PublicKey.X,
"Y": w.PrivateKey.PublicKey.Y,
},
"X": w.PrivateKey.X,
"Y": w.PrivateKey.Y,
},
"PublicKey": w.PublicKey,
}
return json.Marshal(mapStringAny)
}
// wallets.go
// LoadFromFile loads wallets from the file
func (ws *Wallets) LoadFromFile() error {
if _, err := os.Stat(walletFile); os.IsNotExist(err) {
return err
}
fileContent, err := os.ReadFile(walletFile)
if err != nil {
log.Panic(err)
}
err = json.Unmarshal(fileContent, ws)
if err != nil {
log.Panic(err)
}
return nil
}
// SaveToFile saves wallets to a file
func (ws Wallets) SaveToFile() {
jsonData, err := json.Marshal(ws)
if err != nil {
log.Panic(err)
}
err = os.WriteFile(walletFile, jsonData, 0666)
if err != nil {
log.Panic(err)
}
}