Commit c1e87cef authored by Ralph Pichler's avatar Ralph Pichler Committed by GitHub

feat: time based settlements (#1711)

parent 4b730a6f
......@@ -64,7 +64,7 @@ jobs:
run: |
echo -e "127.0.0.10\tregistry.localhost" | sudo tee -a /etc/hosts
for ((i=0; i<REPLICA; i++)); do echo -e "127.0.1.$((i+1))\tbee-${i}.localhost bee-${i}-debug.localhost"; done | sudo tee -a /etc/hosts
timeout 30m ./beeinfra.sh install --local -r "${REPLICA}" --bootnode /dnsaddr/localhost --geth --k3s --pay-threshold 2000000000000 --postage
timeout 30m ./beeinfra.sh install --local -r "${REPLICA}" --bootnode /dnsaddr/localhost --geth --k3s --pay-threshold 1500000000000 --postage
- name: Test pingpong
id: pingpong-1
run: until ./beekeeper check pingpong --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}"; do echo "waiting for pingpong..."; sleep .3; done
......@@ -73,7 +73,15 @@ jobs:
run: ./beekeeper check fullconnectivity --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}"
- name: Test settlements
id: settlements-1
run: ./beekeeper check settlements --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}" --upload-node-count "${REPLICA}" -t 2000000000000
run: |
./beekeeper check settlements --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}" --upload-node-count "${REPLICA}" -t 1500000000000
sleep 2
- name: Test pss
id: pss
run: ./beekeeper check pss --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}" --timeout 5m
- name: Test soc
id: soc
run: ./beekeeper check soc --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}"
- name: Test pushsync (chunks)
id: pushsync-chunks-1
run: ./beekeeper check pushsync --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}" --upload-node-count "${REPLICA}" --chunks-per-node 3 --upload-chunks --retry-delay 15s
......@@ -83,12 +91,6 @@ jobs:
- name: Test manifest
id: manifest-1
run: ./beekeeper check manifest --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}"
- name: Test pss
id: pss
run: ./beekeeper check pss --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}" --timeout 5m
- name: Test soc
id: soc
run: ./beekeeper check soc --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}"
- name: Destroy the cluster
run: |
./beeinfra.sh uninstall
......@@ -101,7 +103,7 @@ jobs:
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
- name: Set testing cluster (Node connection and clef enabled)
run: |
timeout 30m ./beeinfra.sh install --local -r "${REPLICA}" --geth --clef --k3s --pay-threshold 2000000000000 --postage
timeout 30m ./beeinfra.sh install --local -r "${REPLICA}" --geth --clef --k3s --pay-threshold 1500000000000 --postage
- name: Test pingpong
id: pingpong-2
run: until ./beekeeper check pingpong --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}"; do echo "waiting for pingpong..."; sleep .3; done
......@@ -110,7 +112,7 @@ jobs:
run: ./beekeeper check fullconnectivity --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}"
- name: Test settlements
id: settlements-2
run: ./beekeeper check settlements --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}" --upload-node-count "${REPLICA}" -t 2000000000000
run: ./beekeeper check settlements --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}" --upload-node-count "${REPLICA}" -t 1500000000000
- name: Destroy the cluster
run: |
./beeinfra.sh uninstall
......@@ -126,7 +128,7 @@ jobs:
cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
- name: Set testing cluster (storage incentives setup)
run: |
timeout 10m ./beeinfra.sh install --local -r "${REPLICA}" --geth --k3s --pay-threshold 2000000000000 --postage --db-capacity 100
timeout 10m ./beeinfra.sh install --local -r "${REPLICA}" --geth --k3s --pay-threshold 1500000000000 --postage --db-capacity 100
- name: Test gc
id: gc-chunk-1
run: ./beekeeper check gc --cache-capacity 100 --api-scheme http --debug-api-scheme http --disable-namespace --debug-api-domain localhost --api-domain localhost --node-count "${REPLICA}"
......
......@@ -218,7 +218,7 @@ func (c *command) setAllFlags(cmd *cobra.Command) {
cmd.Flags().String(optionWelcomeMessage, "", "send a welcome message string during handshakes")
cmd.Flags().Bool(optionNameGlobalPinningEnabled, false, "enable global pinning")
cmd.Flags().String(optionNamePaymentThreshold, "10000000000000", "threshold in BZZ where you expect to get paid from your peers")
cmd.Flags().String(optionNamePaymentTolerance, "50000000000000", "excess debt above payment threshold in BZZ where you disconnect from your peer")
cmd.Flags().String(optionNamePaymentTolerance, "10000000000000", "excess debt above payment threshold in BZZ where you disconnect from your peer")
cmd.Flags().String(optionNamePaymentEarly, "1000000000000", "amount in BZZ below the peers payment threshold when we initiate settlement")
cmd.Flags().StringSlice(optionNameResolverEndpoints, []string{}, "ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url")
cmd.Flags().Bool(optionNameGatewayMode, false, "disable a set of sensitive features in the api")
......
......@@ -52,8 +52,8 @@ password-file: /var/lib/bee/password
# payment-early: 1000000000000
## threshold in BZZ where you expect to get paid from your peers (default 10000000000000)
# payment-threshold: 10000000000000
## excess debt above payment threshold in BZZ where you disconnect from your peer (default 50000000000000)
# payment-tolerance: 50000000000000
## excess debt above payment threshold in BZZ where you disconnect from your peer (default 10000000000000)
# payment-tolerance: 10000000000000
## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url
# resolver-options: []
## whether we want the node to start with no listen addresses for p2p
......
......@@ -55,12 +55,12 @@ BEE_CLEF_SIGNER_ENABLE=true
# BEE_PASSWORD=
## path to a file that contains password for decrypting keys
# BEE_PASSWORD_FILE=
## amount in BZZ below the peers payment threshold when we initiate settlement (default 10000)
# BEE_PAYMENT_EARLY=10000
## threshold in BZZ where you expect to get paid from your peers (default 100000)
# BEE_PAYMENT_THRESHOLD=100000
## excess debt above payment threshold in BZZ where you disconnect from your peer (default 10000)
# BEE_PAYMENT_TOLERANCE=10000
## amount in BZZ below the peers payment threshold when we initiate settlement (default 1000000000000)
# BEE_PAYMENT_EARLY=1000000000000
## threshold in BZZ where you expect to get paid from your peers (default 10000000000000)
# BEE_PAYMENT_THRESHOLD=10000000000000
## excess debt above payment threshold in BZZ where you disconnect from your peer (default 10000000000000)
# BEE_PAYMENT_TOLERANCE=10000000000000
## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url
# BEE_RESOLVER_OPTIONS=[]
## whether we want the node to start with no listen addresses for p2p
......
......@@ -52,8 +52,8 @@ password-file: /usr/local/var/lib/swarm-bee/password
# payment-early: 1000000000000
## threshold in BZZ where you expect to get paid from your peers (default 10000000000000)
# payment-threshold: 10000000000000
## excess debt above payment threshold in BZZ where you disconnect from your peer (default 50000000000000)
# payment-tolerance: 50000000000000
## excess debt above payment threshold in BZZ where you disconnect from your peer (default 10000000000000)
# payment-tolerance: 10000000000000
## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url
# resolver-options: []
## whether we want the node to start with no listen addresses for p2p
......
......@@ -38,12 +38,12 @@ data-dir: ./data
# password: ""
## path to a file that contains password for decrypting keys
password-file: ./password
## amount in BZZ below the peers payment threshold when we initiate settlement (default 10000)
# payment-early: 10000
## threshold in BZZ where you expect to get paid from your peers (default 100000)
# payment-threshold: 100000
## excess debt above payment threshold in BZZ where you disconnect from your peer (default 10000)
# payment-tolerance: 10000
## amount in BZZ below the peers payment threshold when we initiate settlement (default 1000000000000)
# payment-early: 1000000000000
## threshold in BZZ where you expect to get paid from your peers (default 10000000000000)
# payment-threshold: 10000000000000
## excess debt above payment threshold in BZZ where you disconnect from your peer (default 10000000000000)
# payment-tolerance: 10000000000000
## ENS compatible API endpoint for a TLD and with contract address, can be repeated, format [tld:][contract-addr@]url
# resolver-options: []
## whether we want the node to start with no listen addresses for p2p
......
This diff is collapsed.
This diff is collapsed.
package accounting
import (
"time"
"github.com/ethersphere/bee/pkg/swarm"
)
func (s *Accounting) SetTimeNow(f func() time.Time) {
s.timeNow = f
}
func (s *Accounting) SetTime(k int64) {
s.SetTimeNow(func() time.Time {
return time.Unix(k, 0)
})
}
func (a *Accounting) IsPaymentOngoing(peer swarm.Address) bool {
return a.getAccountingPeer(peer).paymentOngoing
}
......@@ -22,8 +22,9 @@ type Service struct {
reserveFunc func(ctx context.Context, peer swarm.Address, price uint64) error
releaseFunc func(peer swarm.Address, price uint64)
creditFunc func(peer swarm.Address, price uint64) error
debitFunc func(peer swarm.Address, price uint64) error
prepareDebitFunc func(peer swarm.Address, price uint64) accounting.Action
balanceFunc func(swarm.Address) (*big.Int, error)
shadowBalanceFunc func(swarm.Address) (*big.Int, error)
balancesFunc func() (map[string]*big.Int, error)
compensatedBalanceFunc func(swarm.Address) (*big.Int, error)
compensatedBalancesFunc func() (map[string]*big.Int, error)
......@@ -31,6 +32,13 @@ type Service struct {
balanceSurplusFunc func(swarm.Address) (*big.Int, error)
}
type debitAction struct {
accounting *Service
price *big.Int
peer swarm.Address
applied bool
}
// WithReserveFunc sets the mock Reserve function
func WithReserveFunc(f func(ctx context.Context, peer swarm.Address, price uint64) error) Option {
return optionFunc(func(s *Service) {
......@@ -53,9 +61,9 @@ func WithCreditFunc(f func(peer swarm.Address, price uint64) error) Option {
}
// WithDebitFunc sets the mock Debit function
func WithDebitFunc(f func(peer swarm.Address, price uint64) error) Option {
func WithPrepareDebitFunc(f func(peer swarm.Address, price uint64) accounting.Action) Option {
return optionFunc(func(s *Service) {
s.debitFunc = f
s.prepareDebitFunc = f
})
}
......@@ -136,21 +144,36 @@ func (s *Service) Credit(peer swarm.Address, price uint64) error {
}
// Debit is the mock function wrapper that calls the set implementation
func (s *Service) Debit(peer swarm.Address, price uint64) error {
if s.debitFunc != nil {
return s.debitFunc(peer, price)
func (s *Service) PrepareDebit(peer swarm.Address, price uint64) accounting.Action {
if s.prepareDebitFunc != nil {
return s.prepareDebitFunc(peer, price)
}
s.lock.Lock()
defer s.lock.Unlock()
if bal, ok := s.balances[peer.String()]; ok {
s.balances[peer.String()] = new(big.Int).Add(bal, new(big.Int).SetUint64(price))
bigPrice := new(big.Int).SetUint64(price)
return &debitAction{
accounting: s,
price: bigPrice,
peer: peer,
applied: false,
}
}
func (a *debitAction) Apply() error {
a.accounting.lock.Lock()
defer a.accounting.lock.Unlock()
if bal, ok := a.accounting.balances[a.peer.String()]; ok {
a.accounting.balances[a.peer.String()] = new(big.Int).Add(bal, new(big.Int).Set(a.price))
} else {
s.balances[peer.String()] = new(big.Int).SetUint64(price)
a.accounting.balances[a.peer.String()] = new(big.Int).Set(a.price)
}
return nil
}
func (a *debitAction) Cleanup() {}
// Balance is the mock function wrapper that calls the set implementation
func (s *Service) Balance(peer swarm.Address) (*big.Int, error) {
if s.balanceFunc != nil {
......@@ -165,6 +188,19 @@ func (s *Service) Balance(peer swarm.Address) (*big.Int, error) {
}
}
func (s *Service) ShadowBalance(peer swarm.Address) (*big.Int, error) {
if s.shadowBalanceFunc != nil {
return s.shadowBalanceFunc(peer)
}
s.lock.Lock()
defer s.lock.Unlock()
if bal, ok := s.balances[peer.String()]; ok {
return new(big.Int).Neg(bal), nil
} else {
return big.NewInt(0), nil
}
}
// Balances is the mock function wrapper that calls the set implementation
func (s *Service) Balances() (map[string]*big.Int, error) {
if s.balancesFunc != nil {
......
......@@ -44,10 +44,10 @@ type Service struct {
tracer *tracing.Tracer
tags *tags.Tags
accounting accounting.Interface
settlement settlement.Interface
pseudosettle settlement.Interface
chequebookEnabled bool
chequebook chequebook.Service
swap swap.ApiInterface
swap swap.Interface
batchStore postage.Storer
corsAllowedOrigins []string
metricsRegistry *prometheus.Registry
......@@ -80,19 +80,19 @@ func New(overlay swarm.Address, publicKey, pssPublicKey ecdsa.PublicKey, ethereu
// Configure injects required dependencies and configuration parameters and
// constructs HTTP routes that depend on them. It is intended and safe to call
// this method only once.
func (s *Service) Configure(p2p p2p.DebugService, pingpong pingpong.Interface, topologyDriver topology.Driver, lightNodes *lightnode.Container, storer storage.Storer, tags *tags.Tags, accounting accounting.Interface, settlement settlement.Interface, chequebookEnabled bool, swap swap.ApiInterface, chequebook chequebook.Service, batchStore postage.Storer) {
func (s *Service) Configure(p2p p2p.DebugService, pingpong pingpong.Interface, topologyDriver topology.Driver, lightNodes *lightnode.Container, storer storage.Storer, tags *tags.Tags, accounting accounting.Interface, pseudosettle settlement.Interface, chequebookEnabled bool, swap swap.Interface, chequebook chequebook.Service, batchStore postage.Storer) {
s.p2p = p2p
s.pingpong = pingpong
s.topologyDriver = topologyDriver
s.storer = storer
s.tags = tags
s.accounting = accounting
s.settlement = settlement
s.chequebookEnabled = chequebookEnabled
s.chequebook = chequebook
s.swap = swap
s.lightNodes = lightNodes
s.batchStore = batchStore
s.pseudosettle = pseudosettle
s.setRouter(s.newRouter())
}
......
......@@ -65,7 +65,7 @@ func newTestServer(t *testing.T, o testServerOptions) *testServer {
acc := accountingmock.NewAccounting(o.AccountingOpts...)
settlement := swapmock.New(o.SettlementOpts...)
chequebook := chequebookmock.NewChequebook(o.ChequebookOpts...)
swapserv := swapmock.NewApiInterface(o.SwapOpts...)
swapserv := swapmock.New(o.SwapOpts...)
ln := lightnode.NewContainer()
s := debugapi.New(o.Overlay, o.PublicKey, o.PSSPublicKey, o.EthereumAddress, logging.New(ioutil.Discard, 0), nil, o.CORSAllowedOrigins)
s.Configure(o.P2P, o.Pingpong, topologyDriver, ln, o.Storer, o.Tags, acc, settlement, true, swapserv, chequebook, o.BatchStore)
......@@ -132,7 +132,7 @@ func TestServer_Configure(t *testing.T) {
acc := accountingmock.NewAccounting(o.AccountingOpts...)
settlement := swapmock.New(o.SettlementOpts...)
chequebook := chequebookmock.NewChequebook(o.ChequebookOpts...)
swapserv := swapmock.NewApiInterface(o.SwapOpts...)
swapserv := swapmock.New(o.SwapOpts...)
ln := lightnode.NewContainer()
s := debugapi.New(o.Overlay, o.PublicKey, o.PSSPublicKey, o.EthereumAddress, logging.New(ioutil.Discard, 0), nil, nil)
ts := httptest.NewServer(s)
......
......@@ -125,15 +125,18 @@ func (s *Service) newRouter() *mux.Router {
"GET": http.HandlerFunc(s.peerBalanceHandler),
})
router.Handle("/settlements", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.settlementsHandler),
})
router.Handle("/settlements/{peer}", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.peerSettlementsHandler),
router.Handle("/timesettlements", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.settlementsHandlerPseudosettle),
})
if s.chequebookEnabled {
router.Handle("/settlements", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.settlementsHandler),
})
router.Handle("/settlements/{peer}", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.peerSettlementsHandler),
})
router.Handle("/chequebook/balance", jsonhttp.MethodHandler{
"GET": http.HandlerFunc(s.chequebookBalanceHandler),
})
......
......@@ -34,14 +34,14 @@ type settlementsResponse struct {
func (s *Service) settlementsHandler(w http.ResponseWriter, r *http.Request) {
settlementsSent, err := s.settlement.SettlementsSent()
settlementsSent, err := s.swap.SettlementsSent()
if err != nil {
jsonhttp.InternalServerError(w, errCantSettlements)
s.logger.Debugf("debug api: sent settlements: %v", err)
s.logger.Error("debug api: can not get sent settlements")
return
}
settlementsReceived, err := s.settlement.SettlementsReceived()
settlementsReceived, err := s.swap.SettlementsReceived()
if err != nil {
jsonhttp.InternalServerError(w, errCantSettlements)
s.logger.Debugf("debug api: received settlements: %v", err)
......@@ -100,7 +100,7 @@ func (s *Service) peerSettlementsHandler(w http.ResponseWriter, r *http.Request)
peerexists := false
received, err := s.settlement.TotalReceived(peer)
received, err := s.swap.TotalReceived(peer)
if err != nil {
if !errors.Is(err, settlement.ErrPeerNoSettlements) {
s.logger.Debugf("debug api: settlements peer: get peer %s received settlement: %v", peer.String(), err)
......@@ -116,7 +116,7 @@ func (s *Service) peerSettlementsHandler(w http.ResponseWriter, r *http.Request)
peerexists = true
}
sent, err := s.settlement.TotalSent(peer)
sent, err := s.swap.TotalSent(peer)
if err != nil {
if !errors.Is(err, settlement.ErrPeerNoSettlements) {
s.logger.Debugf("debug api: settlements peer: get peer %s sent settlement: %v", peer.String(), err)
......@@ -143,3 +143,59 @@ func (s *Service) peerSettlementsHandler(w http.ResponseWriter, r *http.Request)
SettlementSent: sent,
})
}
func (s *Service) settlementsHandlerPseudosettle(w http.ResponseWriter, r *http.Request) {
settlementsSent, err := s.pseudosettle.SettlementsSent()
if err != nil {
jsonhttp.InternalServerError(w, errCantSettlements)
s.logger.Debugf("debug api: sent settlements: %v", err)
s.logger.Error("debug api: can not get sent settlements")
return
}
settlementsReceived, err := s.pseudosettle.SettlementsReceived()
if err != nil {
jsonhttp.InternalServerError(w, errCantSettlements)
s.logger.Debugf("debug api: received settlements: %v", err)
s.logger.Error("debug api: can not get received settlements")
return
}
totalReceived := big.NewInt(0)
totalSent := big.NewInt(0)
settlementResponses := make(map[string]settlementResponse)
for a, b := range settlementsSent {
settlementResponses[a] = settlementResponse{
Peer: a,
SettlementSent: b,
SettlementReceived: big.NewInt(0),
}
totalSent.Add(b, totalSent)
}
for a, b := range settlementsReceived {
if _, ok := settlementResponses[a]; ok {
t := settlementResponses[a]
t.SettlementReceived = b
settlementResponses[a] = t
} else {
settlementResponses[a] = settlementResponse{
Peer: a,
SettlementSent: big.NewInt(0),
SettlementReceived: b,
}
}
totalReceived.Add(b, totalReceived)
}
settlementResponsesArray := make([]settlementResponse, len(settlementResponses))
i := 0
for k := range settlementResponses {
settlementResponsesArray[i] = settlementResponses[k]
i++
}
jsonhttp.OK(w, settlementsResponse{TotalSettlementReceived: totalReceived, TotalSettlementSent: totalSent, Settlements: settlementResponsesArray})
}
......@@ -36,7 +36,7 @@ func TestSettlements(t *testing.T) {
}
testServer := newTestServer(t, testServerOptions{
SettlementOpts: []mock.Option{mock.WithSettlementsSentFunc(settlementsSentFunc), mock.WithSettlementsRecvFunc(settlementsRecvFunc)},
SwapOpts: []mock.Option{mock.WithSettlementsSentFunc(settlementsSentFunc), mock.WithSettlementsRecvFunc(settlementsRecvFunc)},
})
expected := &debugapi.SettlementsResponse{
......@@ -84,7 +84,7 @@ func TestSettlementsError(t *testing.T) {
return nil, wantErr
}
testServer := newTestServer(t, testServerOptions{
SettlementOpts: []mock.Option{mock.WithSettlementsSentFunc(settlementsSentFunc)},
SwapOpts: []mock.Option{mock.WithSettlementsSentFunc(settlementsSentFunc)},
})
jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/settlements", http.StatusInternalServerError,
......@@ -101,7 +101,7 @@ func TestSettlementsPeers(t *testing.T) {
return big.NewInt(1000000000000000000), nil
}
testServer := newTestServer(t, testServerOptions{
SettlementOpts: []mock.Option{mock.WithSettlementSentFunc(settlementSentFunc)},
SwapOpts: []mock.Option{mock.WithSettlementSentFunc(settlementSentFunc)},
})
jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/settlements/"+peer, http.StatusOK,
......@@ -124,7 +124,7 @@ func TestSettlementsPeersNoSettlements(t *testing.T) {
t.Run("no sent", func(t *testing.T) {
testServer := newTestServer(t, testServerOptions{
SettlementOpts: []mock.Option{
SwapOpts: []mock.Option{
mock.WithSettlementSentFunc(errFunc),
mock.WithSettlementRecvFunc(noErrFunc),
},
......@@ -141,7 +141,7 @@ func TestSettlementsPeersNoSettlements(t *testing.T) {
t.Run("no received", func(t *testing.T) {
testServer := newTestServer(t, testServerOptions{
SettlementOpts: []mock.Option{
SwapOpts: []mock.Option{
mock.WithSettlementSentFunc(noErrFunc),
mock.WithSettlementRecvFunc(errFunc),
},
......@@ -164,7 +164,7 @@ func TestSettlementsPeersError(t *testing.T) {
return nil, wantErr
}
testServer := newTestServer(t, testServerOptions{
SettlementOpts: []mock.Option{mock.WithSettlementSentFunc(settlementSentFunc)},
SwapOpts: []mock.Option{mock.WithSettlementSentFunc(settlementSentFunc)},
})
jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/settlements/"+peer, http.StatusInternalServerError,
......
......@@ -203,7 +203,7 @@ func InitSwap(
chequebookService chequebook.Service,
chequeStore chequebook.ChequeStore,
cashoutService chequebook.CashoutService,
accountingAPI settlement.AccountingAPI,
accounting settlement.Accounting,
) (*swap.Service, error) {
swapProtocol := swapprotocol.New(p2ps, logger, overlayEthAddress)
swapAddressBook := swap.NewAddressbook(stateStore)
......@@ -218,7 +218,7 @@ func InitSwap(
networkID,
cashoutService,
p2ps,
accountingAPI,
accounting,
)
swapProtocol.SetSwap(swapService)
......
......@@ -54,7 +54,6 @@ import (
"github.com/ethersphere/bee/pkg/recovery"
"github.com/ethersphere/bee/pkg/resolver/multiresolver"
"github.com/ethersphere/bee/pkg/retrieval"
settlement "github.com/ethersphere/bee/pkg/settlement"
"github.com/ethersphere/bee/pkg/settlement/pseudosettle"
"github.com/ethersphere/bee/pkg/settlement/swap"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook"
......@@ -136,6 +135,11 @@ type Options struct {
BlockTime uint64
}
const (
refreshRate = int64(1000000000000)
basePrice = 1000000000
)
func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey, signer crypto.Signer, networkID uint64, logger logging.Logger, libp2pPrivateKey, pssPrivateKey *ecdsa.PrivateKey, o Options) (b *Bee, err error) {
tracer, tracerCloser, err := tracing.NewTracer(&tracing.Options{
Enabled: o.TracingEnabled,
......@@ -419,7 +423,6 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
}
}
var settlement settlement.Interface
var swapService *swap.Service
kad := kademlia.New(swarmAddress, addressbook, hive, p2ps, logger, kademlia.Options{Bootnodes: bootnodes, StandaloneMode: o.Standalone, BootnodeMode: o.BootnodeMode})
......@@ -445,7 +448,7 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
return nil, fmt.Errorf("invalid payment threshold: %s", paymentThreshold)
}
pricer := pricer.NewFixedPricer(swarmAddress, 1000000000)
pricer := pricer.NewFixedPricer(swarmAddress, basePrice)
minThreshold := pricer.MostExpensive()
......@@ -472,6 +475,7 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
if !ok {
return nil, fmt.Errorf("invalid payment early: %s", paymentEarly)
}
acc, err := accounting.NewAccounting(
paymentThreshold,
paymentTolerance,
......@@ -479,11 +483,19 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
logger,
stateStore,
pricing,
big.NewInt(refreshRate),
)
if err != nil {
return nil, fmt.Errorf("accounting: %w", err)
}
pseudosettleService := pseudosettle.New(p2ps, logger, stateStore, acc, big.NewInt(refreshRate), p2ps)
if err = p2ps.AddProtocol(pseudosettleService.Protocol()); err != nil {
return nil, fmt.Errorf("pseudosettle service: %w", err)
}
acc.SetRefreshFunc(pseudosettleService.Pay)
if o.SwapEnable {
swapService, err = InitSwap(
p2ps,
......@@ -499,17 +511,9 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
if err != nil {
return nil, err
}
settlement = swapService
} else {
pseudosettleService := pseudosettle.New(p2ps, logger, stateStore, acc)
if err = p2ps.AddProtocol(pseudosettleService.Protocol()); err != nil {
return nil, fmt.Errorf("pseudosettle service: %w", err)
}
settlement = pseudosettleService
acc.SetPayFunc(swapService.Pay)
}
acc.SetPayFunc(settlement.Pay)
pricing.SetPaymentThresholdObserver(acc)
retrieve := retrieval.New(swarmAddress, storer, p2ps, kad, logger, acc, pricer, tracer)
......@@ -645,12 +649,14 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
debugAPIService.MustRegisterMetrics(l.Metrics()...)
}
if l, ok := settlement.(metrics.Collector); ok {
debugAPIService.MustRegisterMetrics(l.Metrics()...)
debugAPIService.MustRegisterMetrics(pseudosettleService.Metrics()...)
if swapService != nil {
debugAPIService.MustRegisterMetrics(swapService.Metrics()...)
}
// inject dependencies and configure full debug api http path routes
debugAPIService.Configure(p2ps, pingPong, kad, lightNodes, storer, tagService, acc, settlement, o.SwapEnable, swapService, chequebookService, batchStore)
debugAPIService.Configure(p2ps, pingPong, kad, lightNodes, storer, tagService, acc, pseudosettleService, o.SwapEnable, swapService, chequebookService, batchStore)
}
if err := kad.Start(p2pCtx); err != nil {
......
......@@ -27,7 +27,7 @@ import (
"github.com/ethersphere/bee/pkg/tags"
"github.com/ethersphere/bee/pkg/topology"
"github.com/ethersphere/bee/pkg/tracing"
"github.com/hashicorp/golang-lru"
lru "github.com/hashicorp/golang-lru"
opentracing "github.com/opentracing/opentracing-go"
)
......@@ -158,12 +158,15 @@ func (ps *PushSync) handler(ctx context.Context, p p2p.Peer, stream p2p.Stream)
ps.logger.Errorf("pushsync: chunk store: %v", err)
}
debit := ps.accounting.PrepareDebit(p.Address, price)
defer debit.Cleanup()
// return back receipt
receipt := pb.Receipt{Address: chunk.Address().Bytes()}
if err := w.WriteMsgWithContext(ctxd, &receipt); err != nil {
return fmt.Errorf("send receipt to peer %s: %w", p.Address.String(), err)
}
return ps.accounting.Debit(p.Address, price)
return debit.Apply()
}
return ErrOutOfDepthReplication
......@@ -283,23 +286,29 @@ func (ps *PushSync) handler(ctx context.Context, p p2p.Peer, stream p2p.Stream)
}
// return back receipt
debit := ps.accounting.PrepareDebit(p.Address, price)
defer debit.Cleanup()
receipt := pb.Receipt{Address: chunk.Address().Bytes(), Signature: signature}
if err := w.WriteMsgWithContext(ctx, &receipt); err != nil {
return fmt.Errorf("send receipt to peer %s: %w", p.Address.String(), err)
}
return ps.accounting.Debit(p.Address, price)
return debit.Apply()
}
return fmt.Errorf("handler: push to closest: %w", err)
}
debit := ps.accounting.PrepareDebit(p.Address, price)
defer debit.Cleanup()
// pass back the receipt
if err := w.WriteMsgWithContext(ctx, receipt); err != nil {
return fmt.Errorf("send receipt to peer %s: %w", p.Address.String(), err)
}
return ps.accounting.Debit(p.Address, price)
return debit.Apply()
}
// PushChunkToClosest sends chunk to the closest peer by opening a stream. It then waits for
......
......@@ -362,6 +362,11 @@ func (s *Service) handler(ctx context.Context, p p2p.Peer, stream p2p.Stream) (e
if err != nil {
return fmt.Errorf("stamp marshal: %w", err)
}
chunkPrice := s.pricer.Price(chunk.Address())
debit := s.accounting.PrepareDebit(p.Address, chunkPrice)
defer debit.Cleanup()
if err := w.WriteMsgWithContext(ctx, &pb.Delivery{
Data: chunk.Data(),
Stamp: stamp,
......@@ -371,8 +376,6 @@ func (s *Service) handler(ctx context.Context, p p2p.Peer, stream p2p.Stream) (e
s.logger.Tracef("retrieval protocol debiting peer %s", p.Address.String())
chunkPrice := s.pricer.Price(chunk.Address())
// debit price from p's balance
return s.accounting.Debit(p.Address, chunkPrice)
return debit.Apply()
}
......@@ -5,7 +5,6 @@
package settlement
import (
"context"
"errors"
"math/big"
......@@ -18,9 +17,6 @@ var (
// Interface is the interface used by Accounting to trigger settlement
type Interface interface {
// Pay initiates a payment to the given peer
// It should return without error it is likely that the payment worked
Pay(ctx context.Context, peer swarm.Address, amount *big.Int)
// TotalSent returns the total amount sent to a peer
TotalSent(peer swarm.Address) (totalSent *big.Int, err error)
// TotalReceived returns the total amount received from a peer
......@@ -31,8 +27,9 @@ type Interface interface {
SettlementsReceived() (map[string]*big.Int, error)
}
type AccountingAPI interface {
type Accounting interface {
PeerDebt(peer swarm.Address) (*big.Int, error)
NotifyPaymentReceived(peer swarm.Address, amount *big.Int) error
NotifyPaymentSent(peer swarm.Address, amount *big.Int, receivedError error)
NotifyRefreshmentReceived(peer swarm.Address, amount *big.Int) error
}
// 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 pseudosettle
import (
"context"
"time"
"github.com/ethersphere/bee/pkg/p2p"
)
func (s *Service) SetTimeNow(f func() time.Time) {
s.timeNow = f
}
func (s *Service) SetTime(k int64) {
s.SetTimeNow(func() time.Time {
return time.Unix(k, 0)
})
}
func (s *Service) Init(ctx context.Context, peer p2p.Peer) error {
return s.init(ctx, peer)
}
func (s *Service) Terminate(peer p2p.Peer) error {
return s.terminate(peer)
}
......@@ -23,7 +23,7 @@ var _ = math.Inf
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type Payment struct {
Amount uint64 `protobuf:"varint,1,opt,name=Amount,proto3" json:"Amount,omitempty"`
Amount []byte `protobuf:"bytes,1,opt,name=Amount,proto3" json:"Amount,omitempty"`
}
func (m *Payment) Reset() { *m = Payment{} }
......@@ -59,29 +59,84 @@ func (m *Payment) XXX_DiscardUnknown() {
var xxx_messageInfo_Payment proto.InternalMessageInfo
func (m *Payment) GetAmount() uint64 {
func (m *Payment) GetAmount() []byte {
if m != nil {
return m.Amount
}
return nil
}
type PaymentAck struct {
Amount []byte `protobuf:"bytes,1,opt,name=Amount,proto3" json:"Amount,omitempty"`
Timestamp int64 `protobuf:"varint,2,opt,name=Timestamp,proto3" json:"Timestamp,omitempty"`
}
func (m *PaymentAck) Reset() { *m = PaymentAck{} }
func (m *PaymentAck) String() string { return proto.CompactTextString(m) }
func (*PaymentAck) ProtoMessage() {}
func (*PaymentAck) Descriptor() ([]byte, []int) {
return fileDescriptor_3ff21bb6c9cf5e84, []int{1}
}
func (m *PaymentAck) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *PaymentAck) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_PaymentAck.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *PaymentAck) XXX_Merge(src proto.Message) {
xxx_messageInfo_PaymentAck.Merge(m, src)
}
func (m *PaymentAck) XXX_Size() int {
return m.Size()
}
func (m *PaymentAck) XXX_DiscardUnknown() {
xxx_messageInfo_PaymentAck.DiscardUnknown(m)
}
var xxx_messageInfo_PaymentAck proto.InternalMessageInfo
func (m *PaymentAck) GetAmount() []byte {
if m != nil {
return m.Amount
}
return nil
}
func (m *PaymentAck) GetTimestamp() int64 {
if m != nil {
return m.Timestamp
}
return 0
}
func init() {
proto.RegisterType((*Payment)(nil), "pseudosettle.Payment")
proto.RegisterType((*PaymentAck)(nil), "pseudosettle.PaymentAck")
}
func init() { proto.RegisterFile("pseudosettle.proto", fileDescriptor_3ff21bb6c9cf5e84) }
var fileDescriptor_3ff21bb6c9cf5e84 = []byte{
// 114 bytes of a gzipped FileDescriptorProto
// 148 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2a, 0x28, 0x4e, 0x2d,
0x4d, 0xc9, 0x2f, 0x4e, 0x2d, 0x29, 0xc9, 0x49, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2,
0x41, 0x16, 0x53, 0x52, 0xe4, 0x62, 0x0f, 0x48, 0xac, 0xcc, 0x4d, 0xcd, 0x2b, 0x11, 0x12, 0xe3,
0x62, 0x73, 0xcc, 0xcd, 0x2f, 0xcd, 0x2b, 0x91, 0x60, 0x54, 0x60, 0xd4, 0x60, 0x09, 0x82, 0xf2,
0x9c, 0x64, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09,
0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x8a, 0xa9, 0x20, 0x29,
0x89, 0x0d, 0x6c, 0xaa, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x97, 0x5c, 0xf8, 0x6b, 0x00,
0x00, 0x00,
0x62, 0x73, 0xcc, 0xcd, 0x2f, 0xcd, 0x2b, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x09, 0x82, 0xf2,
0x94, 0x9c, 0xb8, 0xb8, 0xa0, 0x4a, 0x1c, 0x93, 0xb3, 0x71, 0xa9, 0x12, 0x92, 0xe1, 0xe2, 0x0c,
0xc9, 0xcc, 0x4d, 0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0x90, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x0e, 0x42,
0x08, 0x38, 0xc9, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c,
0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x14, 0x53, 0x41,
0x52, 0x12, 0x1b, 0xd8, 0x65, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x87, 0xcb, 0xb8, 0x18,
0xaf, 0x00, 0x00, 0x00,
}
func (m *Payment) Marshal() (dAtA []byte, err error) {
......@@ -104,10 +159,47 @@ func (m *Payment) MarshalToSizedBuffer(dAtA []byte) (int, error) {
_ = i
var l int
_ = l
if m.Amount != 0 {
i = encodeVarintPseudosettle(dAtA, i, uint64(m.Amount))
if len(m.Amount) > 0 {
i -= len(m.Amount)
copy(dAtA[i:], m.Amount)
i = encodeVarintPseudosettle(dAtA, i, uint64(len(m.Amount)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *PaymentAck) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *PaymentAck) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *PaymentAck) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Timestamp != 0 {
i = encodeVarintPseudosettle(dAtA, i, uint64(m.Timestamp))
i--
dAtA[i] = 0x8
dAtA[i] = 0x10
}
if len(m.Amount) > 0 {
i -= len(m.Amount)
copy(dAtA[i:], m.Amount)
i = encodeVarintPseudosettle(dAtA, i, uint64(len(m.Amount)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
......@@ -129,8 +221,25 @@ func (m *Payment) Size() (n int) {
}
var l int
_ = l
if m.Amount != 0 {
n += 1 + sovPseudosettle(uint64(m.Amount))
l = len(m.Amount)
if l > 0 {
n += 1 + l + sovPseudosettle(uint64(l))
}
return n
}
func (m *PaymentAck) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Amount)
if l > 0 {
n += 1 + l + sovPseudosettle(uint64(l))
}
if m.Timestamp != 0 {
n += 1 + sovPseudosettle(uint64(m.Timestamp))
}
return n
}
......@@ -171,10 +280,131 @@ func (m *Payment) Unmarshal(dAtA []byte) error {
}
switch fieldNum {
case 1:
if wireType != 0 {
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType)
}
m.Amount = 0
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPseudosettle
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthPseudosettle
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthPseudosettle
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Amount = append(m.Amount[:0], dAtA[iNdEx:postIndex]...)
if m.Amount == nil {
m.Amount = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipPseudosettle(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthPseudosettle
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthPseudosettle
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *PaymentAck) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPseudosettle
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: PaymentAck: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: PaymentAck: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPseudosettle
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthPseudosettle
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthPseudosettle
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Amount = append(m.Amount[:0], dAtA[iNdEx:postIndex]...)
if m.Amount == nil {
m.Amount = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType)
}
m.Timestamp = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPseudosettle
......@@ -184,7 +414,7 @@ func (m *Payment) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.Amount |= uint64(b&0x7F) << shift
m.Timestamp |= int64(b&0x7F) << shift
if b < 0x80 {
break
}
......
......@@ -9,5 +9,10 @@ package pseudosettle;
option go_package = "pb";
message Payment {
uint64 Amount = 1;
bytes Amount = 1;
}
message PaymentAck {
bytes Amount = 1;
int64 Timestamp = 2;
}
\ No newline at end of file
This diff is collapsed.
......@@ -10,7 +10,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/pkg/settlement"
"github.com/ethersphere/bee/pkg/settlement/swap"
"github.com/ethersphere/bee/pkg/settlement/swap/chequebook"
"github.com/ethersphere/bee/pkg/swarm"
......@@ -120,7 +119,7 @@ func WithCashoutStatusFunc(f func(ctx context.Context, peer swarm.Address) (*che
}
// New creates the mock swap implementation
func New(opts ...Option) settlement.Interface {
func New(opts ...Option) swap.Interface {
mock := new(Service)
mock.settlementsSent = make(map[string]*big.Int)
mock.settlementsRecv = make(map[string]*big.Int)
......@@ -130,14 +129,6 @@ func New(opts ...Option) settlement.Interface {
return mock
}
func NewApiInterface(opts ...Option) swap.ApiInterface {
mock := new(Service)
for _, o := range opts {
o.apply(mock)
}
return mock
}
// ReceiveCheque is the mock ReceiveCheque function of swap.
func (s *Service) ReceiveCheque(ctx context.Context, peer swarm.Address, cheque *chequebook.SignedCheque) (err error) {
if s.receiveChequeFunc != nil {
......
......@@ -30,7 +30,8 @@ var (
ErrUnknownBeneficary = errors.New("unknown beneficiary for peer")
)
type ApiInterface interface {
type Interface interface {
settlement.Interface
// LastSentCheque returns the last sent cheque for the peer
LastSentCheque(peer swarm.Address) (*chequebook.SignedCheque, error)
// LastSentCheques returns the list of last sent cheques for all peers
......@@ -47,33 +48,33 @@ type ApiInterface interface {
// Service is the implementation of the swap settlement layer.
type Service struct {
proto swapprotocol.Interface
logger logging.Logger
store storage.StateStorer
accountingAPI settlement.AccountingAPI
metrics metrics
chequebook chequebook.Service
chequeStore chequebook.ChequeStore
cashout chequebook.CashoutService
p2pService p2p.Service
addressbook Addressbook
networkID uint64
proto swapprotocol.Interface
logger logging.Logger
store storage.StateStorer
accounting settlement.Accounting
metrics metrics
chequebook chequebook.Service
chequeStore chequebook.ChequeStore
cashout chequebook.CashoutService
p2pService p2p.Service
addressbook Addressbook
networkID uint64
}
// New creates a new swap Service.
func New(proto swapprotocol.Interface, logger logging.Logger, store storage.StateStorer, chequebook chequebook.Service, chequeStore chequebook.ChequeStore, addressbook Addressbook, networkID uint64, cashout chequebook.CashoutService, p2pService p2p.Service, accountingAPI settlement.AccountingAPI) *Service {
func New(proto swapprotocol.Interface, logger logging.Logger, store storage.StateStorer, chequebook chequebook.Service, chequeStore chequebook.ChequeStore, addressbook Addressbook, networkID uint64, cashout chequebook.CashoutService, p2pService p2p.Service, accounting settlement.Accounting) *Service {
return &Service{
proto: proto,
logger: logger,
store: store,
metrics: newMetrics(),
chequebook: chequebook,
chequeStore: chequeStore,
addressbook: addressbook,
networkID: networkID,
cashout: cashout,
p2pService: p2pService,
accountingAPI: accountingAPI,
proto: proto,
logger: logger,
store: store,
metrics: newMetrics(),
chequebook: chequebook,
chequeStore: chequeStore,
addressbook: addressbook,
networkID: networkID,
cashout: cashout,
p2pService: p2pService,
accounting: accounting,
}
}
......@@ -101,10 +102,11 @@ func (s *Service) ReceiveCheque(ctx context.Context, peer swarm.Address, cheque
}
}
s.metrics.TotalReceived.Add(float64(amount.Uint64()))
tot, _ := big.NewFloat(0).SetInt(amount).Float64()
s.metrics.TotalReceived.Add(tot)
s.metrics.ChequesReceived.Inc()
return s.accountingAPI.NotifyPaymentReceived(peer, amount)
return s.accounting.NotifyPaymentReceived(peer, amount)
}
// Pay initiates a payment to the given peer
......@@ -112,7 +114,7 @@ func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount *big.Int)
var err error
defer func() {
if err != nil {
s.accountingAPI.NotifyPaymentSent(peer, nil, err)
s.accounting.NotifyPaymentSent(peer, amount, err)
}
}()
beneficiary, known, err := s.addressbook.Beneficiary(peer)
......@@ -136,14 +138,14 @@ func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount *big.Int)
}
bal, _ := big.NewFloat(0).SetInt(balance).Float64()
s.metrics.AvailableBalance.Set(bal)
s.accountingAPI.NotifyPaymentSent(peer, amount, nil)
s.accounting.NotifyPaymentSent(peer, amount, nil)
amountFloat, _ := big.NewFloat(0).SetInt(amount).Float64()
s.metrics.TotalSent.Add(amountFloat)
s.metrics.ChequesSent.Inc()
}
func (s *Service) SetAccountingAPI(accountingAPI settlement.AccountingAPI) {
s.accountingAPI = accountingAPI
func (s *Service) SetAccounting(accounting settlement.Accounting) {
s.accounting = accounting
}
// TotalSent returns the total amount sent to a peer
......
......@@ -70,6 +70,10 @@ func (t *testObserver) NotifyPaymentReceived(peer swarm.Address, amount *big.Int
return nil
}
func (t *testObserver) NotifyRefreshmentReceived(peer swarm.Address, amount *big.Int) error {
return nil
}
func (t *testObserver) NotifyPaymentSent(peer swarm.Address, amount *big.Int, err error) {
t.sentCalled <- notifyPaymentSentCall{
peer: peer,
......@@ -423,7 +427,7 @@ func TestPayIssueError(t *testing.T) {
)
observer := newTestObserver()
swap.SetAccountingAPI(observer)
swap.SetAccounting(observer)
swap.Pay(context.Background(), peer, amount)
select {
......
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