我如何编码来自 golang 的长度 32 []byte nonce 以命中 rust 的 jormungandr rpc 服务器?

问题描述

如果你看看这个 go-cardano-client 如何使它的握手请求有效负载

https://github.com/gocardano/go-cardano-client/blob/master/shelley/handshake.go#L64

  versionTable.Add(cbor.NewPositiveInteger8(1),cbor.NewPositiveInteger(764824073))
  versionTable.Add(cbor.NewPositiveInteger16(32770),cbor.NewPositiveInteger(764824073))
  versionTable.Add(cbor.NewPositiveInteger16(32771),cbor.NewPositiveInteger(764824073))

但是grpc生成的struct是:

type HandshakeRequest struct {
  // Nonce for the server to authenticate its node ID with.
  Nonce []byte `protobuf:"bytes,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
}

并且这个 []byte 需要通过 nonce 引用:

https://github.com/input-output-hk/jormungandr/blob/master/jormungandr/src/network/service.rs#L60

长度为 32:

https://github.com/input-output-hk/jormungandr/blob/master/jormungandr/src/network/client/connect.rs#L58

https://github.com/input-output-hk/jormungandr/blob/6f324b706a13273afb6a0808e589735020bb59da/jormungandr/src/network/mod.rs#L73

golang 代码中的这一行:

  versionTable.Add(cbor.NewPositiveInteger8(1),cbor.NewPositiveInteger(764824073))

长度不能是 32 []byte 对吗?我该如何编码:

  req := HandshakeRequest{}
  req.Nonce = []byte{}
  for i := 0; i < 32; i++ {
    req.Nonce = append(req.Nonce,byte(rand.Intn(256)))
  }

进入这个版本表“params”?

see alsoproto

解决方法

编辑:您似乎假设来自 gocardano/go-cardano-client 的握手和 node.proto 中描述的握手以某种方式与相同的实现相关。实际上,我认为他们不会。

基于 TCP 的握手遵循雪莱协议规范,并发送带有编码 versionTable 的负载。正如您所考虑的那样,基于 gRPC 的 HandshakeRequest 只是一个随机数。原型模式中没有任何内容暗示雪莱协议。 Nonce 字段上的注释也非常明确地说:“Nonce 用于服务器验证其节点 ID。

所以假设这个 nonce 和 versionTable 有效负载有任何共同点会有点奇怪。

Edit 2:另外,似乎“Jormungandr”锈节点实现根本不支持雪莱,所以当你说你无法连接到 {{3}我认为您不应该在 Jormungandr 存储库中寻找答案。相反,我认为中继运行 relay topology 的 Haskell 实现。

现在至于为什么无法连接,go-cardano 客户端会因某些未经检查的类型断言而恐慌,因为在 QueryTip 雪莱消息 chainSyncBlocks.RequestNext 之后,中继服务器以不同的响应完全是迷你协议,transactionSubmission.msgRequestTxIds 如通过使用 TCP 运行客户端并跟踪消息所示:

MiniProtocol: 4 / MessageMode: 1 / f1bb7f80800400058400f50003
Array: [4]
  PositiveInteger8(0)
  False
  PositiveInteger8(0)
  PositiveInteger8(3)

使用 MiniProtocol 2 (ChainSyncHeaders) 发送同步链请求时,您也会得到相同的结果。我检查了雪莱协议规范,但找不到关于服务器为什么会切换协议的明确指示......不幸的是,我对 Haskell 不够熟悉,无法从 Ouroboros 来源获得进一步的见解。


在原型 HandshakeRequest 中的 nonce 确实与雪莱协议相关的意外情况下,其内容可能是您链接的卡尔达诺客户端中的 CBOR 数组(推测如下):

    arr := cbor.NewArray()
    arr.Add(cbor.NewPositiveInteger8(handshakeMessagePropose))
    versionTable := cbor.NewMap()
    arr.Add(versionTable)

    versionTable.Add(...)
    versionTable.Add(...)
    versionTable.Add(...)

    return []cbor.DataItem{arr}

通过检查使用握手请求的客户端,我们可以看到:

messageResponse,err := c.queryNode(multiplex.MiniProtocolIDMuxControl,handshakeRequest())

然后在 queryNode 中:

sdu := multiplex.NewServiceDataUnit(miniProtocol,multiplex.MessageModeInitiator,dataItems)
...
c.socket.Write(sdu.Bytes())

sdu.Bytes() 方法序列化整个有效负载,特别是:

// EncodeList return CBOR representation for each item in the list
func EncodeList(list []DataItem) []byte {
    result := []byte{}
    for _,item := range list {
        result = append(result,item.EncodeCBOR()...)
    }
    return result
}

EncodeCBOR() 方法由 ArrayMap 函数中使用的 handshakeRequest() []cbor.DataItem 实现。注意握手函数返回一个切片 []cbor.DataItem,其中包含一个 Array 项,其中包含(如文档所述)handshakeMessageProposeversionTable 映射。

如果你仔细观察序列化是如何进行的,你最终会得到字节数组的细分——以下是十进制的:

[130 0 163 1 26 45 150 74 9 25 128 2 26 45 150 74 9 25 128 3 26 45 150 74 9]

地点:

  • 130 是数组数据项前缀
  • 0 是 handshakeMessagePropose
  • 163 是地图数据项前缀
  • 和随后的字节是 versionTable 映射

总共 25 个字节。在这一点上,我不知道 queryNode 函数中内置的多路复用包装器是否是 nonce 的一部分。使用完整包装器,序列化字节数组的长度可达 33。因此,排除一些控制位或其他内容,这可能是您应该写入 HandshakeRequest.Nonce 的内容。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...