Skip to content

Commit

Permalink
Merge branch 'main' into evan/bump-app-rc4
Browse files Browse the repository at this point in the history
  • Loading branch information
Wondertan authored Jun 21, 2023
2 parents 3a12e3e + ce8ccb3 commit 759ad53
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 2 deletions.
8 changes: 8 additions & 0 deletions api/gateway/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ func (h *Handler) RegisterMiddleware(srv *Server) {
setContentType,
checkPostDisabled(h.state),
wrapRequestContext,
enableCors,
)
}

func enableCors(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
next.ServeHTTP(w, r)
})
}

func setContentType(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")
Expand Down
31 changes: 29 additions & 2 deletions api/gateway/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ import (
"github.com/stretchr/testify/require"
)

const (
address = "localhost"
port = "0"
)

func TestServer(t *testing.T) {
address, port := "localhost", "0"
server := NewServer(address, port)

ctx, cancel := context.WithCancel(context.Background())
Expand Down Expand Up @@ -42,10 +46,33 @@ func TestServer(t *testing.T) {
require.NoError(t, err)
}

func TestCorsEnabled(t *testing.T) {
server := NewServer(address, port)
server.RegisterMiddleware(enableCors)

ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)

err := server.Start(ctx)
require.NoError(t, err)

// register ping handler
ping := new(ping)
server.RegisterHandlerFunc("/ping", ping.ServeHTTP, http.MethodGet)

url := fmt.Sprintf("http://%s/ping", server.ListenAddr())

resp, err := http.Get(url)
require.NoError(t, err)
defer resp.Body.Close()

require.NoError(t, err)
require.Equal(t, resp.Header.Get("Access-Control-Allow-Origin"), "*")
}

// TestServer_contextLeakProtection tests to ensure a context
// deadline was added by the context wrapper middleware server-side.
func TestServer_contextLeakProtection(t *testing.T) {
address, port := "localhost", "0"
server := NewServer(address, port)
server.RegisterMiddleware(wrapRequestContext)

Expand Down
6 changes: 6 additions & 0 deletions header/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
tmjson "github.com/tendermint/tendermint/libs/json"
core "github.com/tendermint/tendermint/types"

"github.com/celestiaorg/celestia-app/pkg/appconsts"
"github.com/celestiaorg/celestia-app/pkg/da"
libhead "github.com/celestiaorg/go-header"
"github.com/celestiaorg/rsmt2d"
Expand Down Expand Up @@ -115,6 +116,11 @@ func (eh *ExtendedHeader) Validate() error {
return fmt.Errorf("ValidateBasic error on RawHeader at height %d: %w", eh.Height(), err)
}

if eh.RawHeader.Version.App != appconsts.LatestVersion {
return fmt.Errorf("app version mismatch, expected: %d, got %d", appconsts.LatestVersion,
eh.RawHeader.Version.App)
}

err = eh.Commit.ValidateBasic()
if err != nil {
return fmt.Errorf("ValidateBasic error on Commit at height %d: %w", eh.Height(), err)
Expand Down
8 changes: 8 additions & 0 deletions header/headertest/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/assert"
tmrand "github.com/tendermint/tendermint/libs/rand"

"github.com/celestiaorg/celestia-app/pkg/appconsts"
libhead "github.com/celestiaorg/go-header"
)

Expand Down Expand Up @@ -80,6 +81,13 @@ func TestVerify(t *testing.T) {
},
err: true,
},
{
prepare: func() libhead.Header {
untrustedAdj.RawHeader.Version.App = appconsts.LatestVersion + 1
return untrustedAdj
},
err: true,
},
}

for i, test := range tests {
Expand Down
151 changes: 151 additions & 0 deletions share/namespace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package share

import (
"bytes"
"encoding/hex"
"fmt"

appns "github.com/celestiaorg/celestia-app/pkg/namespace"
"github.com/celestiaorg/nmt/namespace"
)

// Various reserved namespaces.
var (
MaxReservedNamespace = Namespace(appns.MaxReservedNamespace.Bytes())
ParitySharesNamespace = Namespace(appns.ParitySharesNamespace.Bytes())
TailPaddingNamespace = Namespace(appns.TailPaddingNamespace.Bytes())
ReservedPaddingNamespace = Namespace(appns.ReservedPaddingNamespace.Bytes())
TxNamespace = Namespace(appns.TxNamespace.Bytes())
PayForBlobNamespace = Namespace(appns.PayForBlobNamespace.Bytes())
)

// Namespace represents namespace of a Share.
// Consists of version byte and namespace ID.
type Namespace []byte

// NamespaceFromBytes converts bytes into Namespace and validates it.
func NamespaceFromBytes(b []byte) (Namespace, error) {
n := Namespace(b)
return n, n.Validate()
}

// Version reports version of the Namespace.
func (n Namespace) Version() byte {
return n[appns.NamespaceVersionSize-1]
}

// ID reports ID of the Namespace.
func (n Namespace) ID() namespace.ID {
return namespace.ID(n[appns.NamespaceVersionSize:])
}

// ToNMT converts the whole Namespace(both Version and ID parts) into NMT's namespace.ID
// NOTE: Once https://github.com/celestiaorg/nmt/issues/206 is closed Namespace should become NNT's
// type.
func (n Namespace) ToNMT() namespace.ID {
return namespace.ID(n)
}

// ToAppNamespace converts the Namespace to App's definition of Namespace.
// TODO: Unify types between node and app
func (n Namespace) ToAppNamespace() appns.Namespace {
return appns.Namespace{Version: n.Version(), ID: n.ID()}
}

// Len reports the total length of the namespace.
func (n Namespace) Len() int {
return len(n)
}

// String stringifies the Namespace.
func (n Namespace) String() string {
return hex.EncodeToString(n)
}

// Equals compares two Namespaces.
func (n Namespace) Equals(target Namespace) bool {
return bytes.Equal(n, target)
}

// Validate checks if the namespace is correct.
func (n Namespace) Validate() error {
if n.Len() != NamespaceSize {
return fmt.Errorf("invalid namespace length: expected %d, got %d", NamespaceSize, n.Len())
}
if n.Version() != appns.NamespaceVersionZero && n.Version() != appns.NamespaceVersionMax {
return fmt.Errorf("invalid namespace version %v", n.Version())
}
if len(n.ID()) != appns.NamespaceIDSize {
return fmt.Errorf("invalid namespace id length: expected %d, got %d", appns.NamespaceIDSize, n.ID().Size())
}
if n.Version() == appns.NamespaceVersionZero && !bytes.HasPrefix(n.ID(), appns.NamespaceVersionZeroPrefix) {
return fmt.Errorf("invalid namespace id: expect %d leading zeroes", len(appns.NamespaceVersionZeroPrefix))
}
return nil
}

// ValidateDataNamespace checks if the Namespace contains real/useful data.
func (n Namespace) ValidateDataNamespace() error {
if err := n.Validate(); err != nil {
return err
}
if n.Equals(ParitySharesNamespace) || n.Equals(TailPaddingNamespace) {
return fmt.Errorf("invalid data namespace(%s): parity and tail padding namespace are forbidden", n)
}
return nil
}

// ValidateBlobNamespace checks if the Namespace is valid blob namespace.
func (n Namespace) ValidateBlobNamespace() error {
if err := n.ValidateDataNamespace(); err != nil {
return err
}
if bytes.Compare(n, MaxReservedNamespace) < 1 {
return fmt.Errorf("invalid blob namespace(%s): reserved namespaces are forbidden", n)
}
return nil
}

// IsAboveMax checks if the namespace is above the maximum namespace of the given hash.
func (n Namespace) IsAboveMax(nodeHash []byte) bool {
return !n.IsLessOrEqual(nodeHash[n.Len() : n.Len()*2])
}

// IsBelowMin checks if the target namespace is below the minimum namespace of the given hash.
func (n Namespace) IsBelowMin(nodeHash []byte) bool {
return n.IsLess(nodeHash[:n.Len()])
}

// IsOutsideRange checks if the namespace is outside the min-max range of the given hashes.
func (n Namespace) IsOutsideRange(leftNodeHash, rightNodeHash []byte) bool {
return n.IsBelowMin(leftNodeHash) || n.IsAboveMax(rightNodeHash)
}

// Repeat copies the Namespace t times.
func (n Namespace) Repeat(t int) []Namespace {
ns := make([]Namespace, t)
for i := 0; i < t; i++ {
ns[i] = n
}
return ns
}

// IsLess reports if the Namespace is less than the target.
func (n Namespace) IsLess(target Namespace) bool {
return bytes.Compare(n, target) == -1
}

// IsLessOrEqual reports if the Namespace is less than the target.
func (n Namespace) IsLessOrEqual(target Namespace) bool {
return bytes.Compare(n, target) < 1
}

// IsGreater reports if the Namespace is greater than the target.
func (n Namespace) IsGreater(target Namespace) bool {
return bytes.Compare(n, target) == 1
}

// IsGreaterOrEqualThan reports if the Namespace is greater or equal than the target.
func (n Namespace) IsGreaterOrEqualThan(target Namespace) bool {
return bytes.Compare(n, target) > -1
}
84 changes: 84 additions & 0 deletions share/namespace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package share

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"

appns "github.com/celestiaorg/celestia-app/pkg/namespace"
)

var (
validID = append(
appns.NamespaceVersionZeroPrefix,
bytes.Repeat([]byte{1}, appns.NamespaceVersionZeroIDSize)...,
)
tooShortID = append(appns.NamespaceVersionZeroPrefix, []byte{1}...)
tooLongID = append(appns.NamespaceVersionZeroPrefix, bytes.Repeat([]byte{1}, NamespaceSize)...)
invalidPrefixID = bytes.Repeat([]byte{1}, NamespaceSize)
)

func TestFrom(t *testing.T) {
type testCase struct {
name string
bytes []byte
wantErr bool
want Namespace
}
validNamespace := []byte{}
validNamespace = append(validNamespace, appns.NamespaceVersionZero)
validNamespace = append(validNamespace, appns.NamespaceVersionZeroPrefix...)
validNamespace = append(validNamespace, bytes.Repeat([]byte{0x1}, appns.NamespaceVersionZeroIDSize)...)
parityNamespace := bytes.Repeat([]byte{0xFF}, NamespaceSize)

testCases := []testCase{
{
name: "valid namespace",
bytes: validNamespace,
wantErr: false,
want: append([]byte{appns.NamespaceVersionZero}, validID...),
},
{
name: "parity namespace",
bytes: parityNamespace,
wantErr: false,
want: append([]byte{appns.NamespaceVersionMax}, bytes.Repeat([]byte{0xFF}, appns.NamespaceIDSize)...),
},
{
name: "unsupported version",
bytes: append([]byte{1}, append(
appns.NamespaceVersionZeroPrefix,
bytes.Repeat([]byte{1}, NamespaceSize-len(appns.NamespaceVersionZeroPrefix))...,
)...),
wantErr: true,
},
{
name: "unsupported id: too short",
bytes: append([]byte{appns.NamespaceVersionZero}, tooShortID...),
wantErr: true,
},
{
name: "unsupported id: too long",
bytes: append([]byte{appns.NamespaceVersionZero}, tooLongID...),
wantErr: true,
},
{
name: "unsupported id: invalid prefix",
bytes: append([]byte{appns.NamespaceVersionZero}, invalidPrefixID...),
wantErr: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
got, err := NamespaceFromBytes(tc.bytes)
if tc.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tc.want, got)
})
}
}
1 change: 1 addition & 0 deletions share/nid.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
// NewNamespaceV0 takes a variable size byte slice and creates a version 0 Namespace ID.
// The byte slice must be <= 10 bytes.
// If it is less than 10 bytes, it will be left padded to size 10 with 0s.
// TODO: Adapt for Namespace in the integration PR
func NewNamespaceV0(subNId []byte) (namespace.ID, error) {
if lnid := len(subNId); lnid > appns.NamespaceVersionZeroIDSize {
return nil, fmt.Errorf("namespace id must be <= %v, but it was %v bytes", appns.NamespaceVersionZeroIDSize, lnid)
Expand Down

0 comments on commit 759ad53

Please sign in to comment.