编解码器:将 vectorOfN 与 vlong 字段一起使用

Scodec: Using vectorOfN with a vlong field

我正在研究比特币区块链以学习 Scala 和一些有用的库。 目前我正在尝试使用 SCodec 解码和编码块,我的问题是 vectorOfN 函数将其大小作为 Int。如何在仍然 保留完整值范围 的同时使用长字段作为大小。 也就是说有没有vectorOfLongN函数?

这是我的代码,如果我使用 vintL 而不是 vlongL,它可以正常编译:

object Block {
  implicit val codec: Codec[Block] = {
    ("header" | Codec[BlockHeader]) ::
    (("numTx" | vlongL) >>:~
      { numTx => ("transactions" | vectorOfN(provide(numTx), Codec[Transaction]) ).hlist })
  }.as[Block]
}

您可以假设为块头和交易实施了适当的编解码器。实际上,vlong 被用作这个问题的简化,因为比特币使用自己的编解码器来处理可变大小的整数。

我不是 scodec 专家,但我的常识表明这是不可能的,因为 Scala 的 Vector 作为 GenSeqLike 的子类型仅限于 length 类型 Intapply 接受 Int 索引作为其参数。 AFAIU 这个限制来自于底层的 JVM 平台,在这个平台上你不能有一个大小超过 Integer.MAX_VALUE 的数组,即大约 2^31(另见 "Criticism of Java" wiki)。尽管 Vector 理论上可以绕过这个限制,但它并没有完成。所以 vectorOfN 也支持 Long 尺寸是没有意义的。

换句话说,如果您想要这样的东西,您可能应该从创建自己的 Vector-like class 开始,它确实支持 Long 绕过 JVM 限制的索引。

您可能想看看 scodec-stream,当您的所有数据无法立即使用或无法放入内存时,它会派上用场。

基本上,您可以使用常用的 codecs.X 并通过 scodec.stream.decode.many(normal_codec) 将其变成 StreamDecoder。这样您就可以通过 scodec 处理数据,而无需将其完全加载到内存中。

A StreamDecoder 然后提供像 decodeInputStreamscodec's 通常的方法 decode.

(我刚才在一个稍微不同的上下文中使用它——解析客户端发送到服务器的数据——但它看起来也适用于这里)。