Skip to content

Commit

Permalink
state: update SubmitPayForBlob api; api: add BlobAPI (#11)
Browse files Browse the repository at this point in the history
## Overview

This PR adds `type Blob`, adds `BlobAPI` and updates the API for
`SubmitPayForBlob` to the latest version of celestia-node.

Fixes #10 

## Checklist

<!-- 
Please complete the checklist to ensure that the PR is ready to be
reviewed.

IMPORTANT:
PRs should be left in Draft until the below checklist is completed.
-->

- [x] New and updated code has appropriate documentation
- [x] New and updated code has new and/or updated testing
- [x] Required CI checks are passing
- [x] Visual proof for any user facing features like CLI or
documentation updates
- [x] Linked issues closed with keywords
  • Loading branch information
tuxcanfly committed Jul 5, 2023
1 parent cb6b2cd commit f89b1d9
Show file tree
Hide file tree
Showing 13 changed files with 849 additions and 12 deletions.
15 changes: 11 additions & 4 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import (
"github.com/libp2p/go-libp2p/core/protocol"
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"

"github.com/rollkit/celestia-openrpc/types/blob"
"github.com/rollkit/celestia-openrpc/types/das"
"github.com/rollkit/celestia-openrpc/types/header"
"github.com/rollkit/celestia-openrpc/types/namespace"
"github.com/rollkit/celestia-openrpc/types/node"
"github.com/rollkit/celestia-openrpc/types/share"
"github.com/rollkit/celestia-openrpc/types/state"
Expand All @@ -36,6 +36,14 @@ type DASAPI struct {
WaitCatchUp func(ctx context.Context) error `perm:"read"`
}

type BlobAPI struct {
Submit func(context.Context, []*blob.Blob) (uint64, error) `perm:"write"`
Get func(context.Context, uint64, share.Namespace, blob.Commitment) (*blob.Blob, error) `perm:"read"`
GetAll func(context.Context, uint64, []share.Namespace) ([]*blob.Blob, error) `perm:"read"`
GetProof func(context.Context, uint64, share.Namespace, blob.Commitment) (*blob.Proof, error) `perm:"read"`
Included func(context.Context, uint64, share.Namespace, *blob.Proof, blob.Commitment) (bool, error) `perm:"read"`
}

type HeaderAPI struct {
LocalHead func(context.Context) (*header.ExtendedHeader, error) `perm:"read"`
GetByHash func(
Expand Down Expand Up @@ -68,10 +76,9 @@ type StateAPI struct {
SubmitTx func(ctx context.Context, tx state.Tx) (*state.TxResponse, error) `perm:"write"`
SubmitPayForBlob func(
ctx context.Context,
nID namespace.ID,
data []byte,
fee state.Int,
gasLim uint64,
blobs []*blob.Blob,
) (*state.TxResponse, error) `perm:"write"`
CancelUnbondingDelegation func(
ctx context.Context,
Expand Down Expand Up @@ -132,7 +139,7 @@ type ShareAPI struct {
GetSharesByNamespace func(
ctx context.Context,
root *share.Root,
namespace namespace.ID,
namespace share.Namespace,
) (share.NamespacedShares, error) `perm:"public"`
}
type P2PAPI struct {
Expand Down
7 changes: 6 additions & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const AuthKey = "Authorization"

type Client struct {
Fraud FraudAPI
Blob BlobAPI
Header HeaderAPI
State StateAPI
Share ShareAPI
Expand Down Expand Up @@ -45,12 +46,16 @@ func (c *Client) Close() {
}

func NewClient(ctx context.Context, addr string, token string) (*Client, error) {
authHeader := http.Header{AuthKey: []string{fmt.Sprintf("Bearer %s", token)}}
var authHeader http.Header
if token != "" {
authHeader = http.Header{AuthKey: []string{fmt.Sprintf("Bearer %s", token)}}
}

var client Client

modules := map[string]interface{}{
"fraud": &client.Fraud,
"blob": &client.Blob,
"header": &client.Header,
"state": &client.State,
"share": &client.Share,
Expand Down
78 changes: 78 additions & 0 deletions types/appconsts/global_consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package appconsts

import (
"math"

"github.com/celestiaorg/rsmt2d"
)

// These constants were originally sourced from:
// https://github.com/celestiaorg/celestia-specs/blob/master/src/specs/consensus.md#constants
//
// They can not change throughout the lifetime of a network.
const (
// NamespaceVersionSize is the size of a namespace version in bytes.
NamespaceVersionSize = 1
// NamespaceVersionMaxValue is the maximum value a namespace version can be.
// This const must be updated if NamespaceVersionSize is changed.
NamespaceVersionMaxValue = math.MaxUint8

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

// 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

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

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

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

var (
// DefaultCodec is the default codec creator used for data erasure.
DefaultCodec = rsmt2d.NewLeoRSCodec
)
29 changes: 29 additions & 0 deletions types/appconsts/initial_consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package appconsts

import "time"

// The following defaults correspond to initial parameters of the network that can be changed, not via app versions
// but other means such as on-chain governance, or the nodes local config
const (
// DefaultGovMaxSquareSize is the default value for the governance modifiable
// max square size.
DefaultGovMaxSquareSize = 64

// DefaultMaxBytes is the default value for the governance modifiable
// maximum number of bytes allowed in a valid block.
DefaultMaxBytes = DefaultGovMaxSquareSize * DefaultGovMaxSquareSize * ContinuationSparseShareContentSize

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

// DefaultMinGasPrice is the default min gas price that gets set in the app.toml file.
// The min gas price acts as a filter. Transactions below that limit will not pass
// a nodes `CheckTx` and thus not be proposed by that node.
DefaultMinGasPrice = 0.1

// DefaultUnbondingTime is the default time a validator must wait
// to unbond in a proof of stake system. Any validator within this
// time can be subject to slashing under conditions of misbehavior.
DefaultUnbondingTime = 3 * 7 * 24 * time.Hour
)
145 changes: 145 additions & 0 deletions types/blob/blob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package blob

import (
"bytes"
"encoding/json"
"errors"
"fmt"

"github.com/celestiaorg/nmt"

"github.com/rollkit/celestia-openrpc/types/appconsts"
"github.com/rollkit/celestia-openrpc/types/share"
)

const (
// NMTIgnoreMaxNamespace is currently used value for IgnoreMaxNamespace option in NMT.
// IgnoreMaxNamespace defines whether the largest possible Namespace MAX_NID should be 'ignored'.
// If set to true, this allows for shorter proofs in particular use-cases.
NMTIgnoreMaxNamespace = true
)

var (
ErrBlobNotFound = errors.New("blob: not found")
ErrInvalidProof = errors.New("blob: invalid proof")
)

// Commitment is a Merkle Root of the subtree built from shares of the Blob.
// It is computed by splitting the blob into shares and building the Merkle subtree to be included
// after Submit.
type Commitment []byte

func (com Commitment) String() string {
return string(com)
}

// Equal ensures that commitments are the same
func (com Commitment) Equal(c Commitment) bool {
return bytes.Equal(com, c)
}

// Proof is a collection of nmt.Proofs that verifies the inclusion of the data.
type Proof []*nmt.Proof

func (p Proof) Len() int { return len(p) }

type jsonProof struct {
Start int `json:"start"`
End int `json:"end"`
Nodes [][]byte `json:"nodes"`
}

func (p *Proof) MarshalJSON() ([]byte, error) {
proofs := make([]jsonProof, 0, p.Len())
for _, pp := range *p {
proofs = append(proofs, jsonProof{
Start: pp.Start(),
End: pp.End(),
Nodes: pp.Nodes(),
})
}

return json.Marshal(proofs)
}

func (p *Proof) UnmarshalJSON(data []byte) error {
var proofs []jsonProof
err := json.Unmarshal(data, &proofs)
if err != nil {
return err
}

nmtProofs := make([]*nmt.Proof, len(proofs))
for i, jProof := range proofs {
nmtProof := nmt.NewInclusionProof(jProof.Start, jProof.End, jProof.Nodes, NMTIgnoreMaxNamespace)
nmtProofs[i] = &nmtProof
}

*p = nmtProofs
return nil
}

// Blob represents any application-specific binary data that anyone can submit to Celestia.
type Blob struct {
Namespace []byte `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
ShareVersion uint32 `protobuf:"varint,3,opt,name=share_version,json=shareVersion,proto3" json:"share_version,omitempty"`
NamespaceVersion uint32 `protobuf:"varint,4,opt,name=namespace_version,json=namespaceVersion,proto3" json:"namespace_version,omitempty"`
Commitment []byte `protobuf:"bytes,5,opt,name=commitment,proto3" json:"commitment,omitempty"`
}

// NewBlobV0 constructs a new blob from the provided Namespace and data.
// The blob will be formatted as v0 shares.
func NewBlobV0(namespace share.Namespace, data []byte) (*Blob, error) {
return NewBlob(appconsts.ShareVersionZero, namespace, data)
}

// NewBlob constructs a new blob from the provided Namespace, data and share version.
func NewBlob(shareVersion uint8, namespace share.Namespace, data []byte) (*Blob, error) {
if len(data) == 0 || len(data) > appconsts.DefaultMaxBytes {
return nil, fmt.Errorf("blob data must be > 0 && <= %d, but it was %d bytes", appconsts.DefaultMaxBytes, len(data))
}
if err := namespace.ValidateForBlob(); err != nil {
return nil, err
}

return &Blob{
Namespace: namespace,
Data: data,
ShareVersion: uint32(shareVersion),
NamespaceVersion: 0,
Commitment: []byte{},
}, nil
}

type jsonBlob struct {
Namespace share.Namespace `json:"namespace"`
Data []byte `json:"data"`
ShareVersion uint32 `json:"share_version"`
Commitment Commitment `json:"commitment"`
}

func (b *Blob) MarshalJSON() ([]byte, error) {
blob := &jsonBlob{
Namespace: b.Namespace,
Data: b.Data,
ShareVersion: b.ShareVersion,
Commitment: b.Commitment,
}
return json.Marshal(blob)
}

func (b *Blob) UnmarshalJSON(data []byte) error {
var blob jsonBlob
err := json.Unmarshal(data, &blob)
if err != nil {
return err
}

b.NamespaceVersion = uint32(blob.Namespace.Version())
b.Data = blob.Data
b.ShareVersion = blob.ShareVersion
b.Commitment = blob.Commitment
b.Namespace = blob.Namespace
return nil
}
Loading

0 comments on commit f89b1d9

Please sign in to comment.