Skip to content

Commit

Permalink
postage: add create endpoint (#1142)
Browse files Browse the repository at this point in the history
  • Loading branch information
ralph-pichler authored and acud committed Jan 27, 2021
1 parent 891a756 commit d75b882
Show file tree
Hide file tree
Showing 14 changed files with 616 additions and 95 deletions.
70 changes: 35 additions & 35 deletions cmd/bee/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,40 @@ import (
)

const (
optionNameDataDir = "data-dir"
optionNameDBCapacity = "db-capacity"
optionNamePassword = "password"
optionNamePasswordFile = "password-file"
optionNameAPIAddr = "api-addr"
optionNameP2PAddr = "p2p-addr"
optionNameNATAddr = "nat-addr"
optionNameP2PWSEnable = "p2p-ws-enable"
optionNameP2PQUICEnable = "p2p-quic-enable"
optionNameDebugAPIEnable = "debug-api-enable"
optionNameDebugAPIAddr = "debug-api-addr"
optionNameBootnodes = "bootnode"
optionNameNetworkID = "network-id"
optionWelcomeMessage = "welcome-message"
optionCORSAllowedOrigins = "cors-allowed-origins"
optionNameStandalone = "standalone"
optionNameTracingEnabled = "tracing-enable"
optionNameTracingEndpoint = "tracing-endpoint"
optionNameTracingServiceName = "tracing-service-name"
optionNameVerbosity = "verbosity"
optionNameGlobalPinningEnabled = "global-pinning-enable"
optionNamePaymentThreshold = "payment-threshold"
optionNamePaymentTolerance = "payment-tolerance"
optionNamePaymentEarly = "payment-early"
optionNameResolverEndpoints = "resolver-options"
optionNameGatewayMode = "gateway-mode"
optionNameClefSignerEnable = "clef-signer-enable"
optionNameClefSignerEndpoint = "clef-signer-endpoint"
optionNameSwapEndpoint = "swap-endpoint"
optionNameSwapFactoryAddress = "swap-factory-address"
optionNameSwapInitialDeposit = "swap-initial-deposit"
optionNameSwapEnable = "swap-enable"
optionNamePostageStampAddress = "postage-stamp-address"
optionNamePriceOracleAddress = "price-oracle-address"
optionNameDataDir = "data-dir"
optionNameDBCapacity = "db-capacity"
optionNamePassword = "password"
optionNamePasswordFile = "password-file"
optionNameAPIAddr = "api-addr"
optionNameP2PAddr = "p2p-addr"
optionNameNATAddr = "nat-addr"
optionNameP2PWSEnable = "p2p-ws-enable"
optionNameP2PQUICEnable = "p2p-quic-enable"
optionNameDebugAPIEnable = "debug-api-enable"
optionNameDebugAPIAddr = "debug-api-addr"
optionNameBootnodes = "bootnode"
optionNameNetworkID = "network-id"
optionWelcomeMessage = "welcome-message"
optionCORSAllowedOrigins = "cors-allowed-origins"
optionNameStandalone = "standalone"
optionNameTracingEnabled = "tracing-enable"
optionNameTracingEndpoint = "tracing-endpoint"
optionNameTracingServiceName = "tracing-service-name"
optionNameVerbosity = "verbosity"
optionNameGlobalPinningEnabled = "global-pinning-enable"
optionNamePaymentThreshold = "payment-threshold"
optionNamePaymentTolerance = "payment-tolerance"
optionNamePaymentEarly = "payment-early"
optionNameResolverEndpoints = "resolver-options"
optionNameGatewayMode = "gateway-mode"
optionNameClefSignerEnable = "clef-signer-enable"
optionNameClefSignerEndpoint = "clef-signer-endpoint"
optionNameSwapEndpoint = "swap-endpoint"
optionNameSwapFactoryAddress = "swap-factory-address"
optionNameSwapInitialDeposit = "swap-initial-deposit"
optionNameSwapEnable = "swap-enable"
optionNamePostageContractAddress = "postage-stamp-address"
optionNamePriceOracleAddress = "price-oracle-address"
)

func init() {
Expand Down Expand Up @@ -206,6 +206,6 @@ func (c *command) setAllFlags(cmd *cobra.Command) {
cmd.Flags().String(optionNameSwapFactoryAddress, "", "swap factory address")
cmd.Flags().Uint64(optionNameSwapInitialDeposit, 100000000, "initial deposit if deploying a new chequebook")
cmd.Flags().Bool(optionNameSwapEnable, true, "enable swap")
cmd.Flags().String(optionNamePostageStampAddress, "", "postage stamp address")
cmd.Flags().String(optionNamePostageContractAddress, "", "postage stamp contract address")
cmd.Flags().String(optionNamePriceOracleAddress, "", "price oracle address")
}
2 changes: 1 addition & 1 deletion cmd/bee/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ Welcome to the Swarm.... Bzzz Bzzzz Bzzzz
SwapFactoryAddress: c.config.GetString(optionNameSwapFactoryAddress),
SwapInitialDeposit: c.config.GetUint64(optionNameSwapInitialDeposit),
SwapEnable: c.config.GetBool(optionNameSwapEnable),
PostageStampAddress: c.config.GetString(optionNamePostageStampAddress),
PostageContractAddress: c.config.GetString(optionNamePostageContractAddress),
PriceOracleAddress: c.config.GetString(optionNamePriceOracleAddress),
})
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/internal/file/io_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func newTestServer(t *testing.T, storer storage.Storer) *url.URL {
signer := crypto.NewDefaultSigner(pk)
mockPostage := mockpost.New()

s := api.New(tags.NewTags(store, logger), storer, nil, nil, nil, mockPostage, signer, logger, nil, api.Options{})
s := api.New(tags.NewTags(store, logger), storer, nil, nil, nil, mockPostage, nil, signer, logger, nil, api.Options{})
ts := httptest.NewServer(s)
srvUrl, err := url.Parse(ts.URL)
if err != nil {
Expand Down
47 changes: 25 additions & 22 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/ethersphere/bee/pkg/logging"
m "github.com/ethersphere/bee/pkg/metrics"
"github.com/ethersphere/bee/pkg/postage"
"github.com/ethersphere/bee/pkg/postage/postagecontract"
"github.com/ethersphere/bee/pkg/pss"
"github.com/ethersphere/bee/pkg/resolver"
"github.com/ethersphere/bee/pkg/storage"
Expand Down Expand Up @@ -66,15 +67,16 @@ type Service interface {
}

type server struct {
Tags *tags.Tags
Storer storage.Storer
Resolver resolver.Interface
Pss pss.Interface
Traversal traversal.Service
Logger logging.Logger
Tracer *tracing.Tracer
signer crypto.Signer
post postage.Service
Tags *tags.Tags
Storer storage.Storer
Resolver resolver.Interface
Pss pss.Interface
Traversal traversal.Service
Logger logging.Logger
Tracer *tracing.Tracer
signer crypto.Signer
post postage.Service
postageContract postagecontract.Interface
Options
http.Handler
metrics metrics
Expand All @@ -95,20 +97,21 @@ const (
)

// New will create a and initialize a new API service.
func New(tags *tags.Tags, storer storage.Storer, resolver resolver.Interface, pss pss.Interface, traversalService traversal.Service, post postage.Service, signer crypto.Signer, logger logging.Logger, tracer *tracing.Tracer, o Options) Service {
func New(tags *tags.Tags, storer storage.Storer, resolver resolver.Interface, pss pss.Interface, traversalService traversal.Service, post postage.Service, postageContract postagecontract.Interface, signer crypto.Signer, logger logging.Logger, tracer *tracing.Tracer, o Options) Service {
s := &server{
Tags: tags,
Storer: storer,
Resolver: resolver,
Pss: pss,
Traversal: traversalService,
post: post,
signer: signer,
Options: o,
Logger: logger,
Tracer: tracer,
metrics: newMetrics(),
quit: make(chan struct{}),
Tags: tags,
Storer: storer,
Resolver: resolver,
Pss: pss,
Traversal: traversalService,
post: post,
postageContract: postageContract,
signer: signer,
Options: o,
Logger: logger,
Tracer: tracer,
metrics: newMetrics(),
quit: make(chan struct{}),
}

s.setupRouting()
Expand Down
6 changes: 4 additions & 2 deletions pkg/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest"
"github.com/ethersphere/bee/pkg/logging"
mockpost "github.com/ethersphere/bee/pkg/postage/mock"
"github.com/ethersphere/bee/pkg/postage/postagecontract"
"github.com/ethersphere/bee/pkg/pss"
"github.com/ethersphere/bee/pkg/resolver"
resolverMock "github.com/ethersphere/bee/pkg/resolver/mock"
Expand All @@ -37,6 +38,7 @@ type testServerOptions struct {
Resolver resolver.Interface
Pss pss.Interface
Traversal traversal.Service
PostageContract postagecontract.Interface
WsPath string
Tags *tags.Tags
GatewayMode bool
Expand All @@ -59,7 +61,7 @@ func newTestServer(t *testing.T, o testServerOptions) (*http.Client, *websocket.
if o.WsPingPeriod == 0 {
o.WsPingPeriod = 60 * time.Second
}
s := api.New(o.Tags, o.Storer, o.Resolver, o.Pss, o.Traversal, mockPostage, signer, o.Logger, nil, api.Options{
s := api.New(o.Tags, o.Storer, o.Resolver, o.Pss, o.Traversal, mockPostage, o.PostageContract, signer, o.Logger, nil, api.Options{
GatewayMode: o.GatewayMode,
WsPingPeriod: o.WsPingPeriod,
})
Expand Down Expand Up @@ -160,7 +162,7 @@ func TestParseName(t *testing.T) {
signer := crypto.NewDefaultSigner(pk)
mockPostage := mockpost.New()

s := api.New(nil, nil, tC.res, nil, nil, mockPostage, signer, log, nil, api.Options{}).(*api.Server)
s := api.New(nil, nil, tC.res, nil, nil, mockPostage, nil, signer, log, nil, api.Options{}).(*api.Server)

t.Run(tC.desc, func(t *testing.T) {
got, err := s.ResolveNameOrAddress(tC.name)
Expand Down
1 change: 1 addition & 0 deletions pkg/api/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type (
PinnedChunk = pinnedChunk
ListPinnedChunksResponse = listPinnedChunksResponse
UpdatePinCounter = updatePinCounter
PostageCreateResponse = postageCreateResponse
)

var (
Expand Down
52 changes: 52 additions & 0 deletions pkg/api/postage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2021 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
"math/big"
"net/http"
"strconv"

"github.com/ethersphere/bee/pkg/jsonhttp"
"github.com/gorilla/mux"
)

type postageCreateResponse struct {
BatchID []byte `json:"batchID"`
}

func (s *server) postageCreateHandler(w http.ResponseWriter, r *http.Request) {
depthStr := mux.Vars(r)["depth"]

amount, ok := big.NewInt(0).SetString(mux.Vars(r)["amount"], 10)
if !ok {
s.Logger.Error("create batch: invalid amount")
jsonhttp.BadRequest(w, "invalid postage amount")
return

}

depth, err := strconv.ParseUint(depthStr, 10, 8)
if err != nil {
s.Logger.Debugf("create batch: invalid depth: %v", err)
s.Logger.Error("create batch: invalid depth")
jsonhttp.BadRequest(w, "invalid depth")
return
}

label := r.URL.Query().Get("label")

batchID, err := s.postageContract.CreateBatch(r.Context(), amount, uint8(depth), label)
if err != nil {
s.Logger.Debugf("create batch: failed to create: %v", err)
s.Logger.Error("create batch: failed to create")
jsonhttp.InternalServerError(w, "cannot create batch")
return
}

jsonhttp.OK(w, &postageCreateResponse{
BatchID: batchID,
})
}
95 changes: 95 additions & 0 deletions pkg/api/postage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2021 The Swarm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api_test

import (
"context"
"errors"
"fmt"
"math/big"
"net/http"
"testing"

"github.com/ethersphere/bee/pkg/api"
"github.com/ethersphere/bee/pkg/jsonhttp"
"github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest"
contractMock "github.com/ethersphere/bee/pkg/postage/postagecontract/mock"
)

func TestPostageCreateStamp(t *testing.T) {
batchID := []byte{1, 2, 3, 4}
initialBalance := int64(1000)
depth := uint8(1)
label := "label"
createBatch := func(amount int64, depth uint8, label string) string {
return fmt.Sprintf("/stamps/%d/%d?label=%s", amount, depth, label)
}

t.Run("ok", func(t *testing.T) {
contract := contractMock.New(
contractMock.WithCreateBatchFunc(func(ctx context.Context, ib *big.Int, d uint8, l string) ([]byte, error) {
if ib.Cmp(big.NewInt(initialBalance)) != 0 {
return nil, fmt.Errorf("called with wrong initial balance. wanted %d, got %d", initialBalance, ib)
}
if d != depth {
return nil, fmt.Errorf("called with wrong depth. wanted %d, got %d", depth, d)
}
if l != label {
return nil, fmt.Errorf("called with wrong label. wanted %s, got %s", label, l)
}
return batchID, nil
}),
)
client, _, _ := newTestServer(t, testServerOptions{
PostageContract: contract,
})

jsonhttptest.Request(t, client, http.MethodPost, createBatch(initialBalance, depth, label), http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(&api.PostageCreateResponse{
BatchID: batchID,
}),
)
})

t.Run("with-error", func(t *testing.T) {
contract := contractMock.New(
contractMock.WithCreateBatchFunc(func(ctx context.Context, ib *big.Int, d uint8, l string) ([]byte, error) {
return nil, errors.New("err")
}),
)
client, _, _ := newTestServer(t, testServerOptions{
PostageContract: contract,
})

jsonhttptest.Request(t, client, http.MethodPost, createBatch(initialBalance, depth, label), http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(&jsonhttp.StatusResponse{
Code: http.StatusInternalServerError,
Message: "cannot create batch",
}),
)
})

t.Run("invalid depth", func(t *testing.T) {
client, _, _ := newTestServer(t, testServerOptions{})

jsonhttptest.Request(t, client, http.MethodPost, "/stamps/1000/ab", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(&jsonhttp.StatusResponse{
Code: http.StatusBadRequest,
Message: "invalid depth",
}),
)
})

t.Run("invalid balance", func(t *testing.T) {
client, _, _ := newTestServer(t, testServerOptions{})

jsonhttptest.Request(t, client, http.MethodPost, "/stamps/abcd/2", http.StatusBadRequest,
jsonhttptest.WithExpectedJSONResponse(&jsonhttp.StatusResponse{
Code: http.StatusBadRequest,
Message: "invalid postage amount",
}),
)
})
}
7 changes: 7 additions & 0 deletions pkg/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@ func (s *server) setupRouting() {
})),
)

handle(router, "/stamps/{amount}/{depth}", web.ChainHandlers(
s.gatewayModeForbidEndpointHandler,
web.FinalHandler(jsonhttp.MethodHandler{
"POST": http.HandlerFunc(s.postageCreateHandler),
})),
)

s.Handler = web.ChainHandlers(
httpaccess.NewHTTPAccessLogHandler(s.Logger, logrus.InfoLevel, s.Tracer, "api access"),
handlers.CompressHandler,
Expand Down
Loading

0 comments on commit d75b882

Please sign in to comment.