恐慌:gob:类型 elliptic.p256Curve 没有导出字段

问题描述 投票:0回答:5

当我遇到有关 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 elliptic-curve gob
5个回答
1
投票

将您的 Go 版本更改为 1.18.10,花费更少。由于最新的 Go 版本,即 1.19.5,我遇到了同样的问题

我们需要用旧的方式降级 Go 版本,因为 Go 不提供像花哨的版本管理器这样的东西。

Go版本降级步骤:

  1. 卸载现有的Go版本

    要卸载 Go,请找到 Go 在系统上的位置。

    $where go
    此命令将定位程序 用户路径中的文件。

    要卸载,请删除

    /usr/local/go
    目录或源 您在上一个命令中作为输出收到的目录。 使用命令
    $ sudo rm -rf /usr/local/go
    删除 Go 目录。

    要确认运行命令

    $ go version
    , 如果你成功删除了Go目录,系统会提示“找不到命令”

  2. 安装新版本

    转到

    downloads 页面并下载与您的操作系统和架构兼容的版本发布(选择安装程序而不是存档以使事情变得简单)。解压缩并提取软件包安装程序,新的 Go 版本现已安装在您的系统中。

之后,您需要重新启动终端才能使更改生效。 要检查 Go 是否已成功安装,请运行命令

$go version

。该命令打印已安装的 Go 版本。另请确保 
GOROOT
GOPATH
 未更改。


1
投票
我这里有一个解决方案

在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, } }
    

0
投票
您似乎在这里尝试做的是从

crypto/elliptic

 包序列化 P256 曲线。问题是 
P256()
 函数返回一个名为 
elliptic.Curve
 的接口。

此错误告诉您的是

elliptic.Curve

 的基础类型(在本例中为 
elliptic.p256Curve
)没有任何导出的字段(以第一个字母大写命名)。 
reflect
 使用的 Go 的 
encoding/gob
 包仅适用于导出的字段。

您可能想尝试使用

crypto/elliptic

Marshal()
GenerateKey()
 函数。


0
投票
我们可以按照代码解决这个问题。该解决方案也可以在

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)
    }
}
    

-1
投票
它在 1.9.* 版本的 Go 中存在问题。例如,只需安装 1.8.7。在此之后一切都会正常)

© www.soinside.com 2019 - 2024. All rights reserved.