Example #1
0
    /// <summary>
    /// Deserializes a <see cref="NodeRecord"/> from an <see cref="RlpStream"/>.
    /// </summary>
    /// <param name="rlpStream">A stream to read the serialized data from.</param>
    /// <returns>A deserialized <see cref="NodeRecord"/></returns>
    public NodeRecord Deserialize(RlpStream rlpStream)
    {
        int startPosition   = rlpStream.Position;
        int recordRlpLength = rlpStream.ReadSequenceLength();

        NodeRecord nodeRecord = new();

        ReadOnlySpan <byte> sigBytes  = rlpStream.DecodeByteArraySpan();
        Signature           signature = new(sigBytes, 0);

        bool canVerify   = true;
        long enrSequence = rlpStream.DecodeLong();

        while (rlpStream.Position < startPosition + recordRlpLength)
        {
            string key = rlpStream.DecodeString();
            switch (key)
            {
            case EnrContentKey.Eth:
                _ = rlpStream.ReadSequenceLength();
                _ = rlpStream.ReadSequenceLength();
                byte[] forkHash  = rlpStream.DecodeByteArray();
                long   nextBlock = rlpStream.DecodeLong();
                nodeRecord.SetEntry(new EthEntry(forkHash, nextBlock));
                break;

            case EnrContentKey.Id:
                rlpStream.SkipItem();
                nodeRecord.SetEntry(IdEntry.Instance);
                break;

            case EnrContentKey.Ip:
                ReadOnlySpan <byte> ipBytes = rlpStream.DecodeByteArraySpan();
                IPAddress           address = new(ipBytes);
                nodeRecord.SetEntry(new IpEntry(address));
                break;

            case EnrContentKey.Tcp:
                int tcpPort = rlpStream.DecodeInt();
                nodeRecord.SetEntry(new TcpEntry(tcpPort));
                break;

            case EnrContentKey.Udp:
                int udpPort = rlpStream.DecodeInt();
                nodeRecord.SetEntry(new UdpEntry(udpPort));
                break;

            case EnrContentKey.Secp256K1:
                ReadOnlySpan <byte> keyBytes    = rlpStream.DecodeByteArraySpan();
                CompressedPublicKey reportedKey = new(keyBytes);
                nodeRecord.SetEntry(new Secp256K1Entry(reportedKey));
                break;

            // snap
            default:
                canVerify = false;
                rlpStream.SkipItem();
                nodeRecord.Snap = true;
                break;
            }
        }

        if (!canVerify)
        {
            rlpStream.Position = startPosition;
            rlpStream.ReadSequenceLength();
            rlpStream.SkipItem(); // signature
            int       noSigContentLength    = rlpStream.Length - rlpStream.Position;
            int       noSigSequenceLength   = Rlp.LengthOfSequence(noSigContentLength);
            byte[]    originalContent       = new byte[noSigSequenceLength];
            RlpStream originalContentStream = new (originalContent);
            originalContentStream.StartSequence(noSigContentLength);
            originalContentStream.Write(rlpStream.Read(noSigContentLength));
            rlpStream.Position            = startPosition;
            nodeRecord.OriginalContentRlp = originalContentStream.Data !;
        }

        nodeRecord.EnrSequence = enrSequence;
        nodeRecord.Signature   = signature;

        return(nodeRecord);
    }