This repository has been archived by the owner on Sep 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
move ssz from erigon/cl/cltypes to erigon-lib/types so it can be used…
… by txpool blob tx parser
- Loading branch information
1 parent
b182304
commit 1fde101
Showing
3 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package clonable | ||
|
||
type Clonable interface { | ||
Clone() Clonable | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package ssz | ||
|
||
import "errors" | ||
|
||
var ( | ||
ErrLowBufferSize = errors.New("ssz(DecodeSSZ): bad encoding size") | ||
ErrBadDynamicLength = errors.New("ssz(DecodeSSZ): bad dynamic length") | ||
ErrBadOffset = errors.New("ssz(DecodeSSZ): invalid offset") | ||
ErrBufferNotRounded = errors.New("ssz(DecodeSSZ): badly rounded operator") | ||
ErrTooBigList = errors.New("ssz(DecodeSSZ): list too big") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
package ssz | ||
|
||
import ( | ||
"encoding/binary" | ||
|
||
libcommon "github.com/ledgerwatch/erigon-lib/common" | ||
"github.com/ledgerwatch/erigon-lib/common/length" | ||
|
||
"github.com/ledgerwatch/erigon-lib/types/clonable" | ||
) | ||
|
||
var ( | ||
BaseExtraDataSSZOffsetHeader = 536 | ||
BaseExtraDataSSZOffsetBlock = 508 | ||
) | ||
|
||
type HashableSSZ interface { | ||
HashSSZ() ([32]byte, error) | ||
} | ||
|
||
type EncodableSSZ interface { | ||
Marshaler | ||
Unmarshaler | ||
} | ||
|
||
type Marshaler interface { | ||
EncodeSSZ([]byte) ([]byte, error) | ||
EncodingSizeSSZ() int | ||
} | ||
|
||
type Unmarshaler interface { | ||
DecodeSSZ(buf []byte) error | ||
DecodeSSZWithVersion(buf []byte, version int) error | ||
clonable.Clonable | ||
} | ||
|
||
func MarshalUint64SSZ(buf []byte, x uint64) { | ||
binary.LittleEndian.PutUint64(buf, x) | ||
} | ||
|
||
func Uint64SSZ(x uint64) []byte { | ||
b := make([]byte, 8) | ||
binary.LittleEndian.PutUint64(b, x) | ||
return b | ||
} | ||
|
||
func BoolSSZ(b bool) byte { | ||
if b { | ||
return 1 | ||
} | ||
return 0 | ||
} | ||
|
||
func OffsetSSZ(x uint32) []byte { | ||
b := make([]byte, 4) | ||
binary.LittleEndian.PutUint32(b, x) | ||
return b | ||
} | ||
|
||
// EncodeOffset marshals a little endian uint32 to buf | ||
func EncodeOffset(buf []byte, offset uint32) { | ||
binary.LittleEndian.PutUint32(buf, offset) | ||
} | ||
|
||
// ReadOffset unmarshals a little endian uint32 to dst | ||
func DecodeOffset(x []byte) uint32 { | ||
return binary.LittleEndian.Uint32(x) | ||
} | ||
|
||
func UnmarshalUint64SSZ(x []byte) uint64 { | ||
return binary.LittleEndian.Uint64(x) | ||
} | ||
|
||
func DecodeDynamicList[T Unmarshaler](bytes []byte, start, end uint32, max uint64) ([]T, error) { | ||
if start > end || len(bytes) < int(end) { | ||
return nil, ErrBadOffset | ||
} | ||
buf := bytes[start:end] | ||
var elementsNum, currentOffset uint32 | ||
if len(buf) > 4 { | ||
currentOffset = DecodeOffset(buf) | ||
elementsNum = currentOffset / 4 | ||
} | ||
inPos := 4 | ||
if uint64(elementsNum) > max { | ||
return nil, ErrTooBigList | ||
} | ||
objs := make([]T, elementsNum) | ||
for i := range objs { | ||
endOffset := uint32(len(buf)) | ||
if i != len(objs)-1 { | ||
if len(buf[inPos:]) < 4 { | ||
return nil, ErrLowBufferSize | ||
} | ||
endOffset = DecodeOffset(buf[inPos:]) | ||
} | ||
inPos += 4 | ||
if endOffset < currentOffset || len(buf) < int(endOffset) { | ||
return nil, ErrBadOffset | ||
} | ||
objs[i] = objs[i].Clone().(T) | ||
if err := objs[i].DecodeSSZ(buf[currentOffset:endOffset]); err != nil { | ||
return nil, err | ||
} | ||
currentOffset = endOffset | ||
} | ||
return objs, nil | ||
} | ||
|
||
func DecodeStaticList[T Unmarshaler](bytes []byte, start, end, bytesPerElement uint32, max uint64) ([]T, error) { | ||
if start > end || len(bytes) < int(end) { | ||
return nil, ErrBadOffset | ||
} | ||
buf := bytes[start:end] | ||
elementsNum := uint64(len(buf)) / uint64(bytesPerElement) | ||
// Check for errors | ||
if uint32(len(buf))%bytesPerElement != 0 { | ||
return nil, ErrBufferNotRounded | ||
} | ||
if elementsNum > max { | ||
return nil, ErrTooBigList | ||
} | ||
objs := make([]T, elementsNum) | ||
for i := range objs { | ||
objs[i] = objs[i].Clone().(T) | ||
if err := objs[i].DecodeSSZ(buf[i*int(bytesPerElement):]); err != nil { | ||
return nil, err | ||
} | ||
} | ||
return objs, nil | ||
} | ||
|
||
func DecodeHashList(bytes []byte, start, end, max uint32) ([]libcommon.Hash, error) { | ||
if start > end || len(bytes) < int(end) { | ||
return nil, ErrBadOffset | ||
} | ||
buf := bytes[start:end] | ||
elementsNum := uint32(len(buf)) / length.Hash | ||
// Check for errors | ||
if uint32(len(buf))%length.Hash != 0 { | ||
return nil, ErrBufferNotRounded | ||
} | ||
if elementsNum > max { | ||
return nil, ErrTooBigList | ||
} | ||
objs := make([]libcommon.Hash, elementsNum) | ||
for i := range objs { | ||
copy(objs[i][:], buf[i*length.Hash:]) | ||
} | ||
return objs, nil | ||
} | ||
|
||
func DecodeNumbersList(bytes []byte, start, end uint32, max uint64) ([]uint64, error) { | ||
if start > end || len(bytes) < int(end) { | ||
return nil, ErrBadOffset | ||
} | ||
buf := bytes[start:end] | ||
elementsNum := uint64(len(buf)) / length.BlockNum | ||
// Check for errors | ||
if uint64(len(buf))%length.BlockNum != 0 { | ||
return nil, ErrBufferNotRounded | ||
} | ||
if elementsNum > max { | ||
return nil, ErrTooBigList | ||
} | ||
objs := make([]uint64, elementsNum) | ||
for i := range objs { | ||
objs[i] = UnmarshalUint64SSZ(buf[i*length.BlockNum:]) | ||
} | ||
return objs, nil | ||
} | ||
|
||
func CalculateIndiciesLimit(maxCapacity, numItems, size uint64) uint64 { | ||
limit := (maxCapacity*size + 31) / 32 | ||
if limit != 0 { | ||
return limit | ||
} | ||
if numItems == 0 { | ||
return 1 | ||
} | ||
return numItems | ||
} | ||
|
||
func DecodeString(bytes []byte, start, end, max uint64) ([]byte, error) { | ||
if start > end || len(bytes) < int(end) { | ||
return nil, ErrBadOffset | ||
} | ||
buf := bytes[start:end] | ||
if uint64(len(buf)) > max { | ||
return nil, ErrTooBigList | ||
} | ||
return buf, nil | ||
} | ||
|
||
func EncodeDynamicList[T Marshaler](buf []byte, objs []T) (dst []byte, err error) { | ||
dst = buf | ||
// Attestation | ||
subOffset := len(objs) * 4 | ||
for _, attestation := range objs { | ||
dst = append(dst, OffsetSSZ(uint32(subOffset))...) | ||
subOffset += attestation.EncodingSizeSSZ() | ||
} | ||
for _, obj := range objs { | ||
dst, err = obj.EncodeSSZ(dst) | ||
if err != nil { | ||
return | ||
} | ||
} | ||
return | ||
} |