Skip to content

Commit

Permalink
Copy share package into Rollkit (cosmos#888)
Browse files Browse the repository at this point in the history
Closes: cosmos#887

Copy parts of [share
package](https://github.com/celestiaorg/celestia-app/tree/main/pkg/shares)
relating to compact shares. We plan to later extract common code into a
separate repo that both `celestia-app` and `rollkit` can use.

Changes needed to this code for use in rollkit will be handled in a
later PR.

Also, extracts parts needed to resolve dependencies, specifically,
`namespace`, `appconsts`, and `testfactory.
  • Loading branch information
Manav-Aggarwal authored Apr 24, 2023
1 parent acf0090 commit c788fb1
Show file tree
Hide file tree
Showing 26 changed files with 3,335 additions and 0 deletions.
101 changes: 101 additions & 0 deletions libs/appconsts/appconsts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package appconsts

// These constants were originally sourced from:
// https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/consensus.md#constants
const (
// NamespaveVersionSize is the size of a namespace version in bytes.
NamespaceVersionSize = 1

// NamespaceIDSize is the size of a namespace ID in bytes.
NamespaceIDSize = 32

// NamespaceSize is the size of a namespace (version + ID) in bytes.
NamespaceSize = NamespaceVersionSize + NamespaceIDSize

// ShareSize is the size of a share in bytes.
ShareSize = 512

// ShareInfoBytes is the number of bytes reserved for information. The info
// byte contains the share version and a sequence start idicator.
ShareInfoBytes = 1

// SequenceLenBytes is the number of bytes reserved for the sequence length
// that is present in the first share of a sequence.
SequenceLenBytes = 4

// ShareVersionZero is the first share version format.
ShareVersionZero = uint8(0)

// DefaultShareVersion is the defacto share version. Use this if you are
// unsure of which version to use.
DefaultShareVersion = ShareVersionZero

// CompactShareReservedBytes is the number of bytes reserved for the location of
// the first unit (transaction, ISR) in a compact share.
CompactShareReservedBytes = 4

// FirstCompactShareContentSize is the number of bytes usable for data in
// the first compact share of a sequence.
FirstCompactShareContentSize = ShareSize - NamespaceSize - ShareInfoBytes - SequenceLenBytes - CompactShareReservedBytes

// ContinuationCompactShareContentSize is the number of bytes usable for
// data in a continuation compact share of a sequence.
ContinuationCompactShareContentSize = ShareSize - NamespaceSize - ShareInfoBytes - CompactShareReservedBytes

// FirstSparseShareContentSize is the number of bytes usable for data in the
// first sparse share of a sequence.
FirstSparseShareContentSize = ShareSize - NamespaceSize - ShareInfoBytes - SequenceLenBytes

// ContinuationSparseShareContentSize is the number of bytes usable for data
// in a continuation sparse share of a sequence.
ContinuationSparseShareContentSize = ShareSize - NamespaceSize - ShareInfoBytes

// DefaultMaxSquareSize is the maximum original square width.
//
// Note: 128 shares in a row * 128 shares in a column * 512 bytes in a share
// = 8 MiB
DefaultMaxSquareSize = 128

// MaxShareCount is the maximum number of shares allowed in the original
// data square.
MaxShareCount = DefaultMaxSquareSize * DefaultMaxSquareSize

// DefaultMinSquareSize is the smallest original square width.
DefaultMinSquareSize = 1

// MinshareCount is the minimum number of shares allowed in the original
// data square.
MinShareCount = DefaultMinSquareSize * DefaultMinSquareSize

// MaxShareVersion is the maximum value a share version can be.
MaxShareVersion = 127

// DefaultGasPerBlobByte is the default gas cost deducted per byte of blob
// included in a PayForBlobs txn
DefaultGasPerBlobByte = 8

// TransactionsPerBlockLimit is the maximum number of transactions a block
// producer will include in a block.
//
// NOTE: Currently this value is set at roughly the number of PFBs that
// would fill one quarter of the max square size.
TransactionsPerBlockLimit = 5090
)

var (

// TODO: Consider commenting back in. Removed to reduce unneeded dependency

// // NewBaseHashFunc is the base hash function used by NMT. Change accordingly
// // if another hash.Hash should be used as a base hasher in the NMT.
// NewBaseHashFunc = consts.NewBaseHashFunc
// // DefaultCodec is the default codec creator used for data erasure.
// DefaultCodec = rsmt2d.NewLeoRSCodec

// // DataCommitmentBlocksLimit is the limit to the number of blocks we can
// // generate a data commitment for.
// DataCommitmentBlocksLimit = consts.DataCommitmentBlocksLimit

// SupportedShareVersions is a list of supported share versions.
SupportedShareVersions = []uint8{ShareVersionZero}
)
8 changes: 8 additions & 0 deletions libs/appconsts/consensus_consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package appconsts

import "time"

const (
TimeoutPropose = time.Second * 10
TimeoutCommit = time.Second * 10
)
70 changes: 70 additions & 0 deletions libs/namespace/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package namespace

import (
"bytes"
"math"

"github.com/rollkit/rollkit/libs/appconsts"
)

const (
// NamespaveVersionSize is the size of a namespace version in bytes.
NamespaceVersionSize = appconsts.NamespaceVersionSize

// NamespaceIDSize is the size of a namespace ID in bytes.
NamespaceIDSize = appconsts.NamespaceIDSize

// NamespaceSize is the size of a namespace (version + ID) in bytes.
NamespaceSize = appconsts.NamespaceSize

// NamespaceVersionZero is the first namespace version.
NamespaceVersionZero = uint8(0)

// NamespaceVersionMax is the max namespace version.
NamespaceVersionMax = math.MaxUint8

// NamespaceZeroPrefixSize is the number of `0` bytes that are prefixed to
// namespace IDs for version 0.
NamespaceVersionZeroPrefixSize = 22

// NamespaceVersionZeroIDSize is the number of bytes available for
// user-specified namespace ID in a namespace ID for version 0.
NamespaceVersionZeroIDSize = NamespaceIDSize - NamespaceVersionZeroPrefixSize
)

var (
// NamespaceVersionZeroPrefix is the prefix of a namespace ID for version 0.
NamespaceVersionZeroPrefix = bytes.Repeat([]byte{0}, NamespaceVersionZeroPrefixSize)

// TxNamespace is the namespace reserved for transaction data.
TxNamespace = MustNewV0([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 1})

// IntermediateStateRootsNamespace is the namespace reserved for
// intermediate state root data.
IntermediateStateRootsNamespace = MustNewV0([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 2})

// PayForBlobNamespace is the namespace reserved for PayForBlobs transactions.
PayForBlobNamespace = MustNewV0([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 4})

// ReservedPaddingNamespace is the namespace used for padding after all
// reserved namespaces. In practice this padding is after transactions
// (ordinary and PFBs) but before blobs.
ReservedPaddingNamespace = MustNewV0([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 255})

// MaxReservedNamespace is lexicographically the largest namespace that is
// reserved for protocol use.
MaxReservedNamespace = MustNewV0([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 255})

// TailPaddingNamespace is the namespace reserved for tail padding. All data
// with this namespace will be ignored.
TailPaddingNamespace = Namespace{
Version: math.MaxUint8,
ID: append(bytes.Repeat([]byte{0xFF}, NamespaceIDSize-1), 0xFE),
}

// ParitySharesNamespace is the namespace reserved for erasure coded data.
ParitySharesNamespace = Namespace{
Version: math.MaxUint8,
ID: bytes.Repeat([]byte{0xFF}, NamespaceIDSize),
}
)
130 changes: 130 additions & 0 deletions libs/namespace/namespace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package namespace

import (
"bytes"
"fmt"
)

type Namespace struct {
Version uint8
ID []byte
}

// New returns a new namespace with the provided version and id.
func New(version uint8, id []byte) (Namespace, error) {
err := validateVersion(version)
if err != nil {
return Namespace{}, err
}

err = validateID(version, id)
if err != nil {
return Namespace{}, err
}

return Namespace{
Version: version,
ID: id,
}, nil
}

// MustNew returns a new namespace with the provided version and id. It panics
// if the provided version or id are not supported.
func MustNew(version uint8, id []byte) Namespace {
ns, err := New(version, id)
if err != nil {
panic(err)
}
return ns
}

// MustNewV0 returns a new namespace with version 0 and the provided id. This
// function panics if the provided id is not exactly NamespaceVersionZeroIDSize bytes.
func MustNewV0(id []byte) Namespace {
if len(id) != NamespaceVersionZeroIDSize {
panic(fmt.Sprintf("invalid namespace id length: %v must be %v", len(id), NamespaceVersionZeroIDSize))
}

ns, err := New(NamespaceVersionZero, append(NamespaceVersionZeroPrefix, id...))
if err != nil {
panic(err)
}
return ns
}

// From returns a namespace from the provided byte slice.
func From(b []byte) (Namespace, error) {
if len(b) != NamespaceSize {
return Namespace{}, fmt.Errorf("invalid namespace length: %v must be %v", len(b), NamespaceSize)
}
rawVersion := b[0]
rawNamespace := b[1:]
return New(rawVersion, rawNamespace)
}

// Bytes returns this namespace as a byte slice.
func (n Namespace) Bytes() []byte {
return append([]byte{n.Version}, n.ID...)
}

// ValidateBlobNamespace returns an error if this namespace is not a valid blob namespace.
func (n Namespace) ValidateBlobNamespace() error {
if n.IsReserved() {
return fmt.Errorf("invalid blob namespace: %v cannot use a reserved namespace ID, want > %v", n.Bytes(), MaxReservedNamespace.Bytes())
}

if n.IsParityShares() {
return fmt.Errorf("invalid blob namespace: %v cannot use parity shares namespace ID", n.Bytes())
}

if n.IsTailPadding() {
return fmt.Errorf("invalid blob namespace: %v cannot use tail padding namespace ID", n.Bytes())
}

return nil
}

// validateVersion returns an error if the version is not supported.
func validateVersion(version uint8) error {
if version != NamespaceVersionZero && version != NamespaceVersionMax {
return fmt.Errorf("unsupported namespace version %v", version)
}
return nil
}

// validateID returns an error if the provided id does not meet the requirements
// for the provided version.
func validateID(version uint8, id []byte) error {
if len(id) != NamespaceIDSize {
return fmt.Errorf("unsupported namespace id length: id %v must be %v bytes but it was %v bytes", id, NamespaceIDSize, len(id))
}

if version == NamespaceVersionZero && !bytes.HasPrefix(id, NamespaceVersionZeroPrefix) {
return fmt.Errorf("unsupported namespace id with version %v. ID %v must start with %v leading zeros", version, id, len(NamespaceVersionZeroPrefix))
}
return nil
}

func (n Namespace) IsReserved() bool {
return bytes.Compare(n.Bytes(), MaxReservedNamespace.Bytes()) < 1
}

func (n Namespace) IsParityShares() bool {
return bytes.Equal(n.Bytes(), ParitySharesNamespace.Bytes())
}

func (n Namespace) IsTailPadding() bool {
return bytes.Equal(n.Bytes(), TailPaddingNamespace.Bytes())
}

func (n Namespace) IsReservedPadding() bool {
return bytes.Equal(n.Bytes(), ReservedPaddingNamespace.Bytes())
}

func (n Namespace) IsTx() bool {
return bytes.Equal(n.Bytes(), TxNamespace.Bytes())
}

func (n Namespace) IsPayForBlob() bool {
return bytes.Equal(n.Bytes(), PayForBlobNamespace.Bytes())
}
Loading

0 comments on commit c788fb1

Please sign in to comment.