Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

postage: add create endpoint #1142

Merged
merged 15 commits into from
Jan 26, 2021
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
43 changes: 43 additions & 0 deletions pkg/api/postage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2020 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
acud marked this conversation as resolved.
Show resolved Hide resolved

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

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

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 {
jsonhttp.BadRequest(w, "invalid postage amount")
acud marked this conversation as resolved.
Show resolved Hide resolved
s.Logger.Error("api: invalid postage amount")
return
}

depth, err := strconv.ParseUint(depthStr, 10, 8)
if err != nil {
jsonhttp.InternalServerError(w, "invalid depth")
acud marked this conversation as resolved.
Show resolved Hide resolved
s.Logger.Error("api: invalid depth")
acud marked this conversation as resolved.
Show resolved Hide resolved
return
}

batchID, err := s.postageContract.CreateBatch(r.Context(), amount, uint8(depth))
if err != nil {
jsonhttp.InternalServerError(w, "cannot create batch")
s.Logger.Error("api: cannot create batch")
acud marked this conversation as resolved.
Show resolved Hide resolved
s.Logger.Debugf("api: cannot create batch: %v", err)
return
}

jsonhttp.OK(w, hex.EncodeToString(batchID))
acud marked this conversation as resolved.
Show resolved Hide resolved
}
46 changes: 46 additions & 0 deletions pkg/api/postage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2020 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"
"encoding/hex"
"fmt"
"math/big"
"net/http"
"testing"

"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)

contract := contractMock.New(
contractMock.WithCreateBatchFunc(func(ctx context.Context, ib *big.Int, d uint8) ([]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)
}
return batchId, nil
}),
)
createBatch := func(amount int64, depth uint8) string { return fmt.Sprintf("/stamps/%d/%d", amount, depth) }
client, _, _ := newTestServer(t, testServerOptions{
PostageContract: contract,
})

jsonhttptest.Request(t, client, http.MethodPost, createBatch(initialBalance, depth), http.StatusOK,
acud marked this conversation as resolved.
Show resolved Hide resolved
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: hex.EncodeToString(batchId),
Code: http.StatusOK,
}))
}
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
61 changes: 34 additions & 27 deletions pkg/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"fmt"
"io"
"log"
"math/big"
"net"
"net/http"
"path/filepath"
Expand All @@ -35,6 +36,7 @@ import (
"github.com/ethersphere/bee/pkg/postage/batchservice"
"github.com/ethersphere/bee/pkg/postage/batchstore"
"github.com/ethersphere/bee/pkg/postage/listener"
"github.com/ethersphere/bee/pkg/postage/postagecontract"
"github.com/ethersphere/bee/pkg/pricing"
"github.com/ethersphere/bee/pkg/pss"
"github.com/ethersphere/bee/pkg/puller"
Expand Down Expand Up @@ -150,19 +152,18 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
var chequeStore chequebook.ChequeStore
var cashoutService chequebook.CashoutService
var overlayEthAddress common.Address
if o.SwapEnable {
swapBackend, err := ethclient.Dial(o.SwapEndpoint)
if err != nil {
return nil, err
}
var erc20Address common.Address
var transactionService transaction.Service
var swapBackend *ethclient.Client
var chainID *big.Int

chainID, err := swapBackend.ChainID(p2pCtx)
if !o.Standalone {
swapBackend, err = ethclient.Dial(o.SwapEndpoint)
if err != nil {
logger.Infof("could not connect to backend at %v. A working blockchain node (for goerli network in production) is required. Check your node or specify another node using --swap-endpoint.", o.SwapEndpoint)
return nil, fmt.Errorf("could not get chain id from ethereum backend: %w", err)
return nil, err
}

transactionService, err := transaction.NewService(logger, swapBackend, signer)
transactionService, err = transaction.NewService(logger, swapBackend, signer)
if err != nil {
return nil, err
}
Expand All @@ -171,6 +172,14 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
return nil, err
}

chainID, err = swapBackend.ChainID(p2pCtx)
if err != nil {
logger.Infof("could not connect to backend at %v. A working blockchain node (for goerli network in production) is required. Check your node or specify another node using --swap-endpoint.", o.SwapEndpoint)
zelig marked this conversation as resolved.
Show resolved Hide resolved
return nil, fmt.Errorf("could not get chain id from ethereum backend: %w", err)
}
}

if !o.Standalone && o.SwapEnable {
var factoryAddress common.Address
if o.SwapFactoryAddress == "" {
var found bool
Expand Down Expand Up @@ -216,22 +225,19 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
if err != nil {
return nil, err
}
}

batchStore := batchstore.New(stateStore)

if !o.Standalone {
swapBackend, err := ethclient.Dial(o.SwapEndpoint)
erc20Address, err = chequebookFactory.ERC20Address(p2pCtx)
if err != nil {
return nil, err
}
}

chainID, err := swapBackend.ChainID(p2pCtx)
if err != nil {
logger.Infof("could not connect to backend at %v. A working blockchain node (for goerli network in production) is required. Check your node or specify another node using --swap-endpoint.", o.SwapEndpoint)
return nil, fmt.Errorf("could not get chain id from ethereum backend: %w", err)
}
batchStore := batchstore.New(stateStore)

post := postage.NewService(stateStore, chainID.Int64()) // do we have a config for this? which chain id are we using??

var postageContractService postagecontract.Interface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some TLC to naming here please.. i got no better idea though

if !o.Standalone {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

postageStampAddress is a misnomer below

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the contract is actually called PostageStamp. For now I went with postageContractAddress. We should also change the flag which currently is --postage-stamp-address but we should reach a decision on naming first as changing that also means changing the helm chart.

postageStampAddress, priceOracleAddress, found := listener.DiscoverAddresses(chainID.Int64())
if o.PostageStampAddress != "" {
if !common.IsHexAddress(o.PostageStampAddress) {
Expand Down Expand Up @@ -260,6 +266,14 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
if err != nil {
return nil, err
}

postageContractService = postagecontract.New(
overlayEthAddress,
postageStampAddress,
erc20Address,
transactionService,
post,
)
}

p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, logger, tracer, libp2p.Options{
Expand Down Expand Up @@ -438,17 +452,10 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
)
b.resolverCloser = multiResolver

post := postage.NewService(stateStore, 1) // do we have a config for this? which chain id are we using??

// this is needed until postage API gets wired in (since our actual API
// falls back to a 32 byte slice of zeros as batch id
fallbackBatch := make([]byte, 32)
post.Add(postage.NewStampIssuer("empty batch", "", fallbackBatch, 32, 8))

var apiService api.Service
if o.APIAddr != "" {
// API server
apiService = api.New(tagService, ns, multiResolver, pssService, traversalService, post, signer, logger, tracer, api.Options{
apiService = api.New(tagService, ns, multiResolver, pssService, traversalService, post, postageContractService, signer, logger, tracer, api.Options{
CORSAllowedOrigins: o.CORSAllowedOrigins,
GatewayMode: o.GatewayMode,
WsPingPeriod: 60 * time.Second,
Expand Down
Loading