2022-10-08 14:15:44 +00:00
|
|
|
/*
|
|
|
|
Copyright 2022 Erigon-Lightclient contributors
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2022-09-29 17:07:57 +00:00
|
|
|
package ssz_snappy
|
|
|
|
|
|
|
|
import (
|
2022-10-06 12:34:39 +00:00
|
|
|
"bufio"
|
2022-10-12 17:55:43 +00:00
|
|
|
"bytes"
|
2022-10-06 12:34:39 +00:00
|
|
|
"encoding/binary"
|
2022-09-29 17:07:57 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2023-05-04 13:18:42 +00:00
|
|
|
"sync"
|
2022-09-29 17:07:57 +00:00
|
|
|
|
2023-01-24 16:36:02 +00:00
|
|
|
"github.com/c2h5oh/datasize"
|
2022-09-29 17:07:57 +00:00
|
|
|
"github.com/golang/snappy"
|
2023-01-24 16:36:02 +00:00
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
2023-05-11 11:54:20 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/types/ssz"
|
2023-01-24 16:36:02 +00:00
|
|
|
"github.com/ledgerwatch/erigon/cl/clparams"
|
|
|
|
"github.com/ledgerwatch/erigon/cl/fork"
|
2022-09-29 17:07:57 +00:00
|
|
|
)
|
|
|
|
|
2023-05-04 13:18:42 +00:00
|
|
|
var writerPool = sync.Pool{
|
|
|
|
New: func() any {
|
|
|
|
return snappy.NewBufferedWriter(nil)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-03-12 14:41:53 +00:00
|
|
|
func EncodeAndWrite(w io.Writer, val ssz.Marshaler, prefix ...byte) error {
|
2023-08-29 00:37:30 +00:00
|
|
|
enc := make([]byte, 0, val.EncodingSizeSSZ())
|
|
|
|
var err error
|
|
|
|
enc, err = val.EncodeSSZ(enc)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-10-10 13:58:31 +00:00
|
|
|
// create prefix for length of packet
|
|
|
|
lengthBuf := make([]byte, 10)
|
2023-08-29 00:37:30 +00:00
|
|
|
vin := binary.PutUvarint(lengthBuf, uint64(len(enc)))
|
|
|
|
|
2022-10-10 13:58:31 +00:00
|
|
|
// Create writer size
|
2023-08-29 00:37:30 +00:00
|
|
|
wr := bufio.NewWriterSize(w, 10+len(enc))
|
2022-10-10 13:58:31 +00:00
|
|
|
defer wr.Flush()
|
|
|
|
// Write length of packet
|
|
|
|
wr.Write(prefix)
|
|
|
|
wr.Write(lengthBuf[:vin])
|
|
|
|
// start using streamed snappy compression
|
2023-05-04 13:18:42 +00:00
|
|
|
sw, _ := writerPool.Get().(*snappy.Writer)
|
|
|
|
sw.Reset(wr)
|
|
|
|
defer func() {
|
|
|
|
sw.Flush()
|
|
|
|
writerPool.Put(sw)
|
|
|
|
}()
|
2022-10-10 13:58:31 +00:00
|
|
|
// Marshall and snap it
|
|
|
|
_, err = sw.Write(enc)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-03-12 14:41:53 +00:00
|
|
|
func DecodeAndRead(r io.Reader, val ssz.EncodableSSZ, b *clparams.BeaconChainConfig, genesisValidatorRoot libcommon.Hash) error {
|
2023-01-24 16:36:02 +00:00
|
|
|
var forkDigest [4]byte
|
2022-10-29 11:02:26 +00:00
|
|
|
// TODO(issues/5884): assert the fork digest matches the expectation for
|
|
|
|
// a specific configuration.
|
2023-01-24 16:36:02 +00:00
|
|
|
if _, err := r.Read(forkDigest[:]); err != nil {
|
2022-10-10 13:58:31 +00:00
|
|
|
return err
|
|
|
|
}
|
2023-01-24 16:36:02 +00:00
|
|
|
version, err := fork.ForkDigestVersion(forkDigest, b, genesisValidatorRoot)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return DecodeAndReadNoForkDigest(r, val, version)
|
2022-11-10 13:14:26 +00:00
|
|
|
}
|
2022-10-11 21:44:02 +00:00
|
|
|
|
2023-03-12 14:41:53 +00:00
|
|
|
func DecodeAndReadNoForkDigest(r io.Reader, val ssz.EncodableSSZ, version clparams.StateVersion) error {
|
2022-10-29 11:02:26 +00:00
|
|
|
// Read varint for length of message.
|
2022-12-23 21:31:08 +00:00
|
|
|
encodedLn, _, err := ReadUvarint(r)
|
2022-10-10 13:58:31 +00:00
|
|
|
if err != nil {
|
2022-10-29 11:02:26 +00:00
|
|
|
return fmt.Errorf("unable to read varint from message prefix: %v", err)
|
|
|
|
}
|
2023-01-24 16:36:02 +00:00
|
|
|
if encodedLn > uint64(16*datasize.MB) {
|
|
|
|
return fmt.Errorf("payload too big")
|
2022-10-10 13:58:31 +00:00
|
|
|
}
|
2022-10-11 21:44:02 +00:00
|
|
|
|
2022-10-29 11:02:26 +00:00
|
|
|
sr := snappy.NewReader(r)
|
2023-01-24 16:36:02 +00:00
|
|
|
raw := make([]byte, encodedLn)
|
2022-10-29 11:02:26 +00:00
|
|
|
if _, err := io.ReadFull(sr, raw); err != nil {
|
|
|
|
return fmt.Errorf("unable to readPacket: %w", err)
|
|
|
|
}
|
2022-10-11 21:44:02 +00:00
|
|
|
|
2023-05-05 09:19:24 +00:00
|
|
|
err = val.DecodeSSZ(raw, int(version))
|
2022-10-29 11:02:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("enable to unmarshall message: %v", err)
|
|
|
|
}
|
|
|
|
return nil
|
2022-10-10 13:58:31 +00:00
|
|
|
}
|
|
|
|
|
2022-12-23 21:31:08 +00:00
|
|
|
func ReadUvarint(r io.Reader) (x, n uint64, err error) {
|
2022-10-10 13:58:31 +00:00
|
|
|
currByte := make([]byte, 1)
|
|
|
|
for shift := uint(0); shift < 64; shift += 7 {
|
|
|
|
_, err := r.Read(currByte)
|
2022-10-29 19:51:32 +00:00
|
|
|
n++
|
2022-10-06 12:34:39 +00:00
|
|
|
if err != nil {
|
2022-10-29 19:51:32 +00:00
|
|
|
return 0, 0, err
|
2022-10-06 12:34:39 +00:00
|
|
|
}
|
2022-10-10 13:58:31 +00:00
|
|
|
b := uint64(currByte[0])
|
|
|
|
x |= (b & 0x7F) << shift
|
|
|
|
if (b & 0x80) == 0 {
|
2022-10-29 19:51:32 +00:00
|
|
|
return x, n, nil
|
2022-10-06 12:34:39 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-10 13:58:31 +00:00
|
|
|
|
|
|
|
// The number is too large to represent in a 64-bit value.
|
2022-10-29 19:51:32 +00:00
|
|
|
return 0, n, nil
|
2022-10-06 12:34:39 +00:00
|
|
|
}
|
2022-10-12 17:55:43 +00:00
|
|
|
|
2023-03-12 14:41:53 +00:00
|
|
|
func DecodeListSSZ(data []byte, count uint64, list []ssz.EncodableSSZ, b *clparams.BeaconChainConfig, genesisValidatorRoot libcommon.Hash) error {
|
2023-01-21 21:33:50 +00:00
|
|
|
objSize := list[0].EncodingSizeSSZ()
|
2022-10-12 17:55:43 +00:00
|
|
|
|
2022-10-29 19:51:32 +00:00
|
|
|
r := bytes.NewReader(data)
|
2023-01-24 16:36:02 +00:00
|
|
|
var forkDigest [4]byte
|
2023-02-28 21:17:10 +00:00
|
|
|
|
2023-01-24 16:36:02 +00:00
|
|
|
if _, err := r.Read(forkDigest[:]); err != nil {
|
2022-10-29 19:51:32 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-10-12 17:55:43 +00:00
|
|
|
|
2023-01-24 16:36:02 +00:00
|
|
|
version, err := fork.ForkDigestVersion(forkDigest, b, genesisValidatorRoot)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-10-29 19:51:32 +00:00
|
|
|
// Read varint for length of message.
|
2022-12-23 21:31:08 +00:00
|
|
|
encodedLn, bytesCount, err := ReadUvarint(r)
|
2022-10-12 17:55:43 +00:00
|
|
|
if err != nil {
|
2022-10-29 19:51:32 +00:00
|
|
|
return fmt.Errorf("unable to read varint from message prefix: %v", err)
|
|
|
|
}
|
|
|
|
pos := 4 + bytesCount
|
2023-02-28 21:17:10 +00:00
|
|
|
if len(list) != int(count) {
|
2022-10-29 19:51:32 +00:00
|
|
|
return fmt.Errorf("encoded length not equal to expected size: want %d, got %d", objSize, encodedLn)
|
2022-10-12 17:55:43 +00:00
|
|
|
}
|
|
|
|
|
2022-10-29 19:51:32 +00:00
|
|
|
sr := snappy.NewReader(r)
|
|
|
|
for i := 0; i < int(count); i++ {
|
|
|
|
var n int
|
2023-02-28 21:17:10 +00:00
|
|
|
raw := make([]byte, encodedLn)
|
2022-10-29 19:51:32 +00:00
|
|
|
if n, err = sr.Read(raw); err != nil {
|
|
|
|
return fmt.Errorf("readPacket: %w", err)
|
|
|
|
}
|
|
|
|
pos += uint64(n)
|
|
|
|
|
2023-05-05 09:19:24 +00:00
|
|
|
if err := list[i].DecodeSSZ(raw, int(version)); err != nil {
|
2022-10-29 19:51:32 +00:00
|
|
|
return fmt.Errorf("unmarshalling: %w", err)
|
|
|
|
}
|
|
|
|
r.Reset(data[pos:])
|
|
|
|
sr.Reset(r)
|
2022-10-12 17:55:43 +00:00
|
|
|
}
|
|
|
|
|
2022-10-29 19:51:32 +00:00
|
|
|
return nil
|
2022-10-12 17:55:43 +00:00
|
|
|
}
|