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 (
"github.com/ethersphere/bee/pkg/p2p"
"github.com/ethersphere/bee/pkg/pingpong"
"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/swarm"
"github.com/ethersphere/bee/pkg/tags"
......@@ -36,11 +37,13 @@ type server struct {
Tags *tags.Tags
Accounting accounting.Interface
Settlement settlement.Interface
ChequebookEnabled bool
Chequebook chequebook.Service
http.Handler
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{
Overlay: overlay,
P2P: p2p,
......@@ -53,6 +56,8 @@ func New(overlay swarm.Address, p2p p2p.DebugService, pingpong pingpong.Interfac
Accounting: accounting,
Settlement: settlement,
metricsRegistry: newMetricsRegistry(),
ChequebookEnabled: chequebookEnabled,
Chequebook: chequebook,
}
s.setupRouting()
......
......@@ -18,6 +18,7 @@ import (
"github.com/ethersphere/bee/pkg/pingpong"
"github.com/ethersphere/bee/pkg/resolver"
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/swarm"
"github.com/ethersphere/bee/pkg/tags"
......@@ -36,6 +37,7 @@ type testServerOptions struct {
Tags *tags.Tags
AccountingOpts []accountingmock.Option
SettlementOpts []settlementmock.Option
ChequebookOpts []chequebookmock.Option
}
type testServer struct {
......@@ -47,8 +49,8 @@ func newTestServer(t *testing.T, o testServerOptions) *testServer {
topologyDriver := topologymock.NewTopologyDriver(o.TopologyOpts...)
acc := accountingmock.NewAccounting(o.AccountingOpts...)
settlement := settlementmock.NewSettlement(o.SettlementOpts...)
s := debugapi.New(o.Overlay, o.P2P, o.Pingpong, topologyDriver, o.Storer, logging.New(ioutil.Discard, 0), nil, o.Tags, acc, settlement)
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, true, chequebook)
ts := httptest.NewServer(s)
t.Cleanup(ts.Close)
......
......@@ -16,6 +16,8 @@ type (
BalanceResponse = balanceResponse
SettlementResponse = settlementResponse
SettlementsResponse = settlementsResponse
ChequebookBalanceResponse = chequebookBalanceResponse
ChequebookAddressResponse = chequebookAddressResponse
)
var (
......@@ -24,5 +26,6 @@ var (
ErrNoBalance = errNoBalance
ErrCantSettlementsPeer = errCantSettlementsPeer
ErrCantSettlements = errCantSettlements
ErrChequebookBalance = errChequebookBalance
ErrInvaliAddress = errInvaliAddress
)
......@@ -94,6 +94,16 @@ func (s *server) setupRouting() {
"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(
logging.NewHTTPAccessLogHandler(s.Logger, logrus.InfoLevel, "debug api access"),
handlers.CompressHandler,
......
......@@ -146,6 +146,8 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service,
b.stateStoreCloser = stateStore
addressbook := addressbook.New(stateStore)
var chequebookService chequebook.Service
if o.SwapEnable {
swapBackend, err := ethclient.Dial(o.SwapEndpoint)
if err != nil {
......@@ -178,7 +180,7 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service,
// initialize chequebook logic
// 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,
stateStore,
logger,
......@@ -388,7 +390,7 @@ func NewBee(addr string, swarmAddress swarm.Address, keystore keystore.Service,
if o.DebugAPIAddr != "" {
// 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
debugAPIService.MustRegisterMetrics(p2ps.Metrics()...)
debugAPIService.MustRegisterMetrics(pingPong.Metrics()...)
......
......@@ -20,8 +20,8 @@ func newTestChequebook(
t *testing.T,
backend chequebook.Backend,
transactionService chequebook.TransactionService,
address common.Address,
erc20address common.Address,
address,
erc20address,
ownerAdress common.Address,
simpleSwapBinding chequebook.SimpleSwapBinding,
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