Commit b3607c89 authored by metacertain's avatar metacertain Committed by GitHub

Chequebook endpoint (#718)

* Add chequebook/balance  &  /chequebook/address debug api endpoints
* Basic unit tests
parent b3bc0460
// 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 debugapi
import (
"math/big"
"net/http"
"github.com/ethersphere/bee/pkg/jsonhttp"
)
var (
errChequebookBalance = "cannot get chequebook balance"
)
type chequebookBalanceResponse struct {
Balance *big.Int `json:"balance"`
}
type chequebookAddressResponse struct {
Address string `json:"chequebookaddress"`
}
func (s *server) chequebookBalanceHandler(w http.ResponseWriter, r *http.Request) {
balance, err := s.Chequebook.Balance(r.Context())
if err != nil {
jsonhttp.InternalServerError(w, errChequebookBalance)
s.Logger.Debugf("debug api: chequebook balance: %v", err)
s.Logger.Error("debug api: cannot get chequebook balance")
return
}
jsonhttp.OK(w, chequebookBalanceResponse{Balance: balance})
}
func (s *server) chequebookAddressHandler(w http.ResponseWriter, r *http.Request) {
address := s.Chequebook.Address()
jsonhttp.OK(w, chequebookAddressResponse{Address: address.String()})
}
// 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 debugapi_test
import (
"context"
"errors"
"math/big"
"net/http"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/debugapi"
"github.com/ethersphere/bee/pkg/jsonhttp"
"github.com/ethersphere/bee/pkg/jsonhttp/jsonhttptest"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook/mock"
)
func TestChequebookBalance(t *testing.T) {
returnedBalance := big.NewInt(9000)
chequebookBalanceFunc := func(context.Context) (ret *big.Int, err error) {
return returnedBalance, nil
}
testServer := newTestServer(t, testServerOptions{
ChequebookOpts: []mock.Option{mock.WithChequebookBalanceFunc(chequebookBalanceFunc)},
})
expected := &debugapi.ChequebookBalanceResponse{
Balance: returnedBalance,
}
// We expect a list of items unordered by peer:
var got *debugapi.ChequebookBalanceResponse
jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/chequebook/balance", http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&got),
)
if !reflect.DeepEqual(got, expected) {
t.Errorf("got balance: %+v, expected: %+v", got, expected)
}
}
func TestChequebookBalanceError(t *testing.T) {
wantErr := errors.New("New errors")
chequebookBalanceFunc := func(context.Context) (ret *big.Int, err error) {
return big.NewInt(0), wantErr
}
testServer := newTestServer(t, testServerOptions{
ChequebookOpts: []mock.Option{mock.WithChequebookBalanceFunc(chequebookBalanceFunc)},
})
jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/chequebook/balance", http.StatusInternalServerError,
jsonhttptest.WithExpectedJSONResponse(jsonhttp.StatusResponse{
Message: debugapi.ErrChequebookBalance,
Code: http.StatusInternalServerError,
}),
)
}
func TestChequebookAddress(t *testing.T) {
chequebookAddressFunc := func() common.Address {
return common.HexToAddress("0xfffff")
}
testServer := newTestServer(t, testServerOptions{
ChequebookOpts: []mock.Option{mock.WithChequebookAddressFunc(chequebookAddressFunc)},
})
address := common.HexToAddress("0xfffff")
expected := &debugapi.ChequebookAddressResponse{
Address: address.String(),
}
var got *debugapi.ChequebookAddressResponse
jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/chequebook/address", http.StatusOK,
jsonhttptest.WithUnmarshalJSONResponse(&got),
)
if !reflect.DeepEqual(got, expected) {
t.Errorf("got address: %+v, expected: %+v", got, expected)
}
}
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"github.com/ethersphere/bee/pkg/p2p" "github.com/ethersphere/bee/pkg/p2p"
"github.com/ethersphere/bee/pkg/pingpong" "github.com/ethersphere/bee/pkg/pingpong"
"github.com/ethersphere/bee/pkg/settlement" "github.com/ethersphere/bee/pkg/settlement"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook"
"github.com/ethersphere/bee/pkg/storage" "github.com/ethersphere/bee/pkg/storage"
"github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/bee/pkg/swarm"
"github.com/ethersphere/bee/pkg/tags" "github.com/ethersphere/bee/pkg/tags"
...@@ -26,33 +27,37 @@ type Service interface { ...@@ -26,33 +27,37 @@ type Service interface {
} }
type server struct { type server struct {
Overlay swarm.Address Overlay swarm.Address
P2P p2p.DebugService P2P p2p.DebugService
Pingpong pingpong.Interface Pingpong pingpong.Interface
TopologyDriver topology.Driver TopologyDriver topology.Driver
Storer storage.Storer Storer storage.Storer
Logger logging.Logger Logger logging.Logger
Tracer *tracing.Tracer Tracer *tracing.Tracer
Tags *tags.Tags Tags *tags.Tags
Accounting accounting.Interface Accounting accounting.Interface
Settlement settlement.Interface Settlement settlement.Interface
ChequebookEnabled bool
Chequebook chequebook.Service
http.Handler http.Handler
metricsRegistry *prometheus.Registry metricsRegistry *prometheus.Registry
} }
func New(overlay swarm.Address, p2p p2p.DebugService, pingpong pingpong.Interface, topologyDriver topology.Driver, storer storage.Storer, logger logging.Logger, tracer *tracing.Tracer, tags *tags.Tags, accounting accounting.Interface, settlement settlement.Interface) Service { func New(overlay swarm.Address, p2p p2p.DebugService, pingpong pingpong.Interface, topologyDriver topology.Driver, storer storage.Storer, logger logging.Logger, tracer *tracing.Tracer, tags *tags.Tags, accounting accounting.Interface, settlement settlement.Interface, chequebookEnabled bool, chequebook chequebook.Service) Service {
s := &server{ s := &server{
Overlay: overlay, Overlay: overlay,
P2P: p2p, P2P: p2p,
Pingpong: pingpong, Pingpong: pingpong,
TopologyDriver: topologyDriver, TopologyDriver: topologyDriver,
Storer: storer, Storer: storer,
Logger: logger, Logger: logger,
Tracer: tracer, Tracer: tracer,
Tags: tags, Tags: tags,
Accounting: accounting, Accounting: accounting,
Settlement: settlement, Settlement: settlement,
metricsRegistry: newMetricsRegistry(), metricsRegistry: newMetricsRegistry(),
ChequebookEnabled: chequebookEnabled,
Chequebook: chequebook,
} }
s.setupRouting() s.setupRouting()
......
...@@ -18,6 +18,7 @@ import ( ...@@ -18,6 +18,7 @@ import (
"github.com/ethersphere/bee/pkg/pingpong" "github.com/ethersphere/bee/pkg/pingpong"
"github.com/ethersphere/bee/pkg/resolver" "github.com/ethersphere/bee/pkg/resolver"
settlementmock "github.com/ethersphere/bee/pkg/settlement/pseudosettle/mock" settlementmock "github.com/ethersphere/bee/pkg/settlement/pseudosettle/mock"
chequebookmock "github.com/ethersphere/bee/pkg/settlement/swap/chequebook/mock"
"github.com/ethersphere/bee/pkg/storage" "github.com/ethersphere/bee/pkg/storage"
"github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/bee/pkg/swarm"
"github.com/ethersphere/bee/pkg/tags" "github.com/ethersphere/bee/pkg/tags"
...@@ -36,6 +37,7 @@ type testServerOptions struct { ...@@ -36,6 +37,7 @@ type testServerOptions struct {
Tags *tags.Tags Tags *tags.Tags
AccountingOpts []accountingmock.Option AccountingOpts []accountingmock.Option
SettlementOpts []settlementmock.Option SettlementOpts []settlementmock.Option
ChequebookOpts []chequebookmock.Option
} }
type testServer struct { type testServer struct {
...@@ -47,8 +49,8 @@ func newTestServer(t *testing.T, o testServerOptions) *testServer { ...@@ -47,8 +49,8 @@ func newTestServer(t *testing.T, o testServerOptions) *testServer {
topologyDriver := topologymock.NewTopologyDriver(o.TopologyOpts...) topologyDriver := topologymock.NewTopologyDriver(o.TopologyOpts...)
acc := accountingmock.NewAccounting(o.AccountingOpts...) acc := accountingmock.NewAccounting(o.AccountingOpts...)
settlement := settlementmock.NewSettlement(o.SettlementOpts...) settlement := settlementmock.NewSettlement(o.SettlementOpts...)
chequebook := chequebookmock.NewChequebook(o.ChequebookOpts...)
s := debugapi.New(o.Overlay, o.P2P, o.Pingpong, topologyDriver, o.Storer, logging.New(ioutil.Discard, 0), nil, o.Tags, acc, settlement) s := debugapi.New(o.Overlay, o.P2P, o.Pingpong, topologyDriver, o.Storer, logging.New(ioutil.Discard, 0), nil, o.Tags, acc, settlement, true, chequebook)
ts := httptest.NewServer(s) ts := httptest.NewServer(s)
t.Cleanup(ts.Close) t.Cleanup(ts.Close)
......
...@@ -5,17 +5,19 @@ ...@@ -5,17 +5,19 @@
package debugapi package debugapi
type ( type (
StatusResponse = statusResponse StatusResponse = statusResponse
PingpongResponse = pingpongResponse PingpongResponse = pingpongResponse
PeerConnectResponse = peerConnectResponse PeerConnectResponse = peerConnectResponse
PeersResponse = peersResponse PeersResponse = peersResponse
AddressesResponse = addressesResponse AddressesResponse = addressesResponse
WelcomeMessageRequest = welcomeMessageRequest WelcomeMessageRequest = welcomeMessageRequest
WelcomeMessageResponse = welcomeMessageResponse WelcomeMessageResponse = welcomeMessageResponse
BalancesResponse = balancesResponse BalancesResponse = balancesResponse
BalanceResponse = balanceResponse BalanceResponse = balanceResponse
SettlementResponse = settlementResponse SettlementResponse = settlementResponse
SettlementsResponse = settlementsResponse SettlementsResponse = settlementsResponse
ChequebookBalanceResponse = chequebookBalanceResponse
ChequebookAddressResponse = chequebookAddressResponse
) )
var ( var (
...@@ -24,5 +26,6 @@ var ( ...@@ -24,5 +26,6 @@ var (
ErrNoBalance = errNoBalance ErrNoBalance = errNoBalance
ErrCantSettlementsPeer = errCantSettlementsPeer ErrCantSettlementsPeer = errCantSettlementsPeer
ErrCantSettlements = errCantSettlements ErrCantSettlements = errCantSettlements
ErrChequebookBalance = errChequebookBalance
ErrInvaliAddress = errInvaliAddress ErrInvaliAddress = errInvaliAddress
) )
...@@ -94,6 +94,16 @@ func (s *server) setupRouting() { ...@@ -94,6 +94,16 @@ func (s *server) setupRouting() {
"GET": http.HandlerFunc(s.peerSettlementsHandler), "GET": http.HandlerFunc(s.peerSettlementsHandler),
}) })
if s.ChequebookEnabled {
router.Handle("/chequebook/balance", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.chequebookBalanceHandler),
})
router.Handle("/chequebook/address", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.chequebookAddressHandler),
})
}
baseRouter.Handle("/", web.ChainHandlers( baseRouter.Handle("/", web.ChainHandlers(
logging.NewHTTPAccessLogHandler(s.Logger, logrus.InfoLevel, "debug api access"), logging.NewHTTPAccessLogHandler(s.Logger, logrus.InfoLevel, "debug api access"),
handlers.CompressHandler, handlers.CompressHandler,
......
...@@ -146,6 +146,8 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service, ...@@ -146,6 +146,8 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service,
b.stateStoreCloser = stateStore b.stateStoreCloser = stateStore
addressbook := addressbook.New(stateStore) addressbook := addressbook.New(stateStore)
var chequebookService chequebook.Service
if o.SwapEnable { if o.SwapEnable {
swapBackend, err := ethclient.Dial(o.SwapEndpoint) swapBackend, err := ethclient.Dial(o.SwapEndpoint)
if err != nil { if err != nil {
...@@ -178,7 +180,7 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service, ...@@ -178,7 +180,7 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service,
// initialize chequebook logic // initialize chequebook logic
// return value is ignored because we don't do anything yet after initialization. this will be passed into swap settlement. // return value is ignored because we don't do anything yet after initialization. this will be passed into swap settlement.
_, err = chequebook.Init(p2pCtx, chequebookService, err = chequebook.Init(p2pCtx,
chequebookFactory, chequebookFactory,
stateStore, stateStore,
logger, logger,
...@@ -388,7 +390,7 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service, ...@@ -388,7 +390,7 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service,
if o.DebugAPIAddr != "" { if o.DebugAPIAddr != "" {
// Debug API server // Debug API server
debugAPIService := debugapi.New(swarmAddress, p2ps, pingPong, kad, storer, logger, tracer, tagg, acc, settlement) debugAPIService := debugapi.New(swarmAddress, p2ps, pingPong, kad, storer, logger, tracer, tagg, acc, settlement, o.SwapEnable, chequebookService)
// register metrics from components // register metrics from components
debugAPIService.MustRegisterMetrics(p2ps.Metrics()...) debugAPIService.MustRegisterMetrics(p2ps.Metrics()...)
debugAPIService.MustRegisterMetrics(pingPong.Metrics()...) debugAPIService.MustRegisterMetrics(pingPong.Metrics()...)
......
...@@ -20,8 +20,8 @@ func newTestChequebook( ...@@ -20,8 +20,8 @@ func newTestChequebook(
t *testing.T, t *testing.T,
backend chequebook.Backend, backend chequebook.Backend,
transactionService chequebook.TransactionService, transactionService chequebook.TransactionService,
address common.Address, address,
erc20address common.Address, erc20address,
ownerAdress common.Address, ownerAdress common.Address,
simpleSwapBinding chequebook.SimpleSwapBinding, simpleSwapBinding chequebook.SimpleSwapBinding,
erc20Binding chequebook.ERC20Binding) (chequebook.Service, error) { erc20Binding chequebook.ERC20Binding) (chequebook.Service, error) {
......
// 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 mock
import (
"context"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook"
)
// Service is the mock chequebook service.
type Service struct {
chequebookBalanceFunc func(context.Context) (*big.Int, error)
chequebookAddressFunc func() common.Address
}
// WithChequebook*Functions set the mock chequebook functions
func WithChequebookBalanceFunc(f func(ctx context.Context) (*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.chequebookBalanceFunc = f
})
}
func WithChequebookAddressFunc(f func() common.Address) Option {
return optionFunc(func(s *Service) {
s.chequebookAddressFunc = f
})
}
// NewChequebook creates the mock chequebook implementation
func NewChequebook(opts ...Option) chequebook.Service {
mock := new(Service)
for _, o := range opts {
o.apply(mock)
}
return mock
}
// Balance mocks the chequebook .Balance function
func (s *Service) Balance(ctx context.Context) (bal *big.Int, err error) {
if s.chequebookBalanceFunc != nil {
return s.chequebookBalanceFunc(ctx)
}
return big.NewInt(0), errors.New("Error")
}
// Deposit mocks the chequebook .Deposit function
func (s *Service) Deposit(ctx context.Context, amount *big.Int) (hash common.Hash, err error) {
return common.Hash{}, errors.New("Error")
}
// WaitForDeposit mocks the chequebook .WaitForDeposit function
func (s *Service) WaitForDeposit(ctx context.Context, txHash common.Hash) error {
return errors.New("Error")
}
// Address mocks the chequebook .Address function
func (s *Service) Address() common.Address {
if s.chequebookAddressFunc != nil {
return s.chequebookAddressFunc()
}
return common.Address{}
}
// Option is the option passed to the mock Chequebook service
type Option interface {
apply(*Service)
}
type optionFunc func(*Service)
func (f optionFunc) apply(r *Service) { f(r) }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment