Commit 273f120e authored by Ralph Pichler's avatar Ralph Pichler Committed by GitHub

swap, accounting: move to bigint (#1187)

parent 7ac406d3
......@@ -193,15 +193,15 @@ func (c *command) setAllFlags(cmd *cobra.Command) {
cmd.Flags().String(optionNameVerbosity, "info", "log verbosity level 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=trace")
cmd.Flags().String(optionWelcomeMessage, "", "send a welcome message string during handshakes")
cmd.Flags().Bool(optionNameGlobalPinningEnabled, false, "enable global pinning")
cmd.Flags().Uint64(optionNamePaymentThreshold, 100000, "threshold in BZZ where you expect to get paid from your peers")
cmd.Flags().Uint64(optionNamePaymentTolerance, 10000, "excess debt above payment threshold in BZZ where you disconnect from your peer")
cmd.Flags().Uint64(optionNamePaymentEarly, 10000, "amount in BZZ below the peers payment threshold when we initiate settlement")
cmd.Flags().String(optionNamePaymentThreshold, "100000", "threshold in BZZ where you expect to get paid from your peers")
cmd.Flags().String(optionNamePaymentTolerance, "10000", "excess debt above payment threshold in BZZ where you disconnect from your peer")
cmd.Flags().String(optionNamePaymentEarly, "10000", "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")
cmd.Flags().Bool(optionNameClefSignerEnable, false, "enable clef signer")
cmd.Flags().String(optionNameClefSignerEndpoint, "", "clef signer endpoint")
cmd.Flags().String(optionNameSwapEndpoint, "http://localhost:8545", "swap ethereum blockchain endpoint")
cmd.Flags().String(optionNameSwapFactoryAddress, "", "swap factory address")
cmd.Flags().Uint64(optionNameSwapInitialDeposit, 100000000, "initial deposit if deploying a new chequebook")
cmd.Flags().String(optionNameSwapInitialDeposit, "100000000", "initial deposit if deploying a new chequebook")
cmd.Flags().Bool(optionNameSwapEnable, true, "enable swap")
}
......@@ -137,14 +137,14 @@ Welcome to the Swarm.... Bzzz Bzzzz Bzzzz
TracingServiceName: c.config.GetString(optionNameTracingServiceName),
Logger: logger,
GlobalPinningEnabled: c.config.GetBool(optionNameGlobalPinningEnabled),
PaymentThreshold: c.config.GetUint64(optionNamePaymentThreshold),
PaymentTolerance: c.config.GetUint64(optionNamePaymentTolerance),
PaymentEarly: c.config.GetUint64(optionNamePaymentEarly),
PaymentThreshold: c.config.GetString(optionNamePaymentThreshold),
PaymentTolerance: c.config.GetString(optionNamePaymentTolerance),
PaymentEarly: c.config.GetString(optionNamePaymentEarly),
ResolverConnectionCfgs: resolverCfgs,
GatewayMode: c.config.GetBool(optionNameGatewayMode),
SwapEndpoint: c.config.GetString(optionNameSwapEndpoint),
SwapFactoryAddress: c.config.GetString(optionNameSwapFactoryAddress),
SwapInitialDeposit: c.config.GetUint64(optionNameSwapInitialDeposit),
SwapInitialDeposit: c.config.GetString(optionNameSwapInitialDeposit),
SwapEnable: c.config.GetBool(optionNameSwapEnable),
})
if err != nil {
......
This diff is collapsed.
This diff is collapsed.
......@@ -6,6 +6,7 @@ package mock
import (
"context"
"math/big"
"sync"
"github.com/ethersphere/bee/pkg/accounting"
......@@ -15,17 +16,17 @@ import (
// Service is the mock Accounting service.
type Service struct {
lock sync.Mutex
balances map[string]int64
balances map[string]*big.Int
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
balanceFunc func(swarm.Address) (int64, error)
balancesFunc func() (map[string]int64, error)
compensatedBalanceFunc func(swarm.Address) (int64, error)
compensatedBalancesFunc func() (map[string]int64, error)
balanceFunc 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)
balanceSurplusFunc func(swarm.Address) (int64, error)
balanceSurplusFunc func(swarm.Address) (*big.Int, error)
}
// WithReserveFunc sets the mock Reserve function
......@@ -57,35 +58,35 @@ func WithDebitFunc(f func(peer swarm.Address, price uint64) error) Option {
}
// WithBalanceFunc sets the mock Balance function
func WithBalanceFunc(f func(swarm.Address) (int64, error)) Option {
func WithBalanceFunc(f func(swarm.Address) (*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.balanceFunc = f
})
}
// WithBalancesFunc sets the mock Balances function
func WithBalancesFunc(f func() (map[string]int64, error)) Option {
func WithBalancesFunc(f func() (map[string]*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.balancesFunc = f
})
}
// WithCompensatedBalanceFunc sets the mock Balance function
func WithCompensatedBalanceFunc(f func(swarm.Address) (int64, error)) Option {
func WithCompensatedBalanceFunc(f func(swarm.Address) (*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.compensatedBalanceFunc = f
})
}
// WithCompensatedBalancesFunc sets the mock Balances function
func WithCompensatedBalancesFunc(f func() (map[string]int64, error)) Option {
func WithCompensatedBalancesFunc(f func() (map[string]*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.compensatedBalancesFunc = f
})
}
// WithBalanceSurplusFunc sets the mock SurplusBalance function
func WithBalanceSurplusFunc(f func(swarm.Address) (int64, error)) Option {
func WithBalanceSurplusFunc(f func(swarm.Address) (*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.balanceSurplusFunc = f
})
......@@ -94,7 +95,7 @@ func WithBalanceSurplusFunc(f func(swarm.Address) (int64, error)) Option {
// NewAccounting creates the mock accounting implementation
func NewAccounting(opts ...Option) accounting.Interface {
mock := new(Service)
mock.balances = make(map[string]int64)
mock.balances = make(map[string]*big.Int)
for _, o := range opts {
o.apply(mock)
}
......@@ -123,7 +124,12 @@ func (s *Service) Credit(peer swarm.Address, price uint64) error {
}
s.lock.Lock()
defer s.lock.Unlock()
s.balances[peer.String()] -= int64(price)
if bal, ok := s.balances[peer.String()]; ok {
s.balances[peer.String()] = new(big.Int).Sub(bal, new(big.Int).SetUint64(price))
} else {
s.balances[peer.String()] = big.NewInt(-int64(price))
}
return nil
}
......@@ -134,22 +140,31 @@ func (s *Service) Debit(peer swarm.Address, price uint64) error {
}
s.lock.Lock()
defer s.lock.Unlock()
s.balances[peer.String()] += int64(price)
if bal, ok := s.balances[peer.String()]; ok {
s.balances[peer.String()] = new(big.Int).Add(bal, new(big.Int).SetUint64(price))
} else {
s.balances[peer.String()] = new(big.Int).SetUint64(price)
}
return nil
}
// Balance is the mock function wrapper that calls the set implementation
func (s *Service) Balance(peer swarm.Address) (int64, error) {
func (s *Service) Balance(peer swarm.Address) (*big.Int, error) {
if s.balanceFunc != nil {
return s.balanceFunc(peer)
}
s.lock.Lock()
defer s.lock.Unlock()
return s.balances[peer.String()], nil
if bal, ok := s.balances[peer.String()]; ok {
return 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]int64, error) {
func (s *Service) Balances() (map[string]*big.Int, error) {
if s.balancesFunc != nil {
return s.balancesFunc()
}
......@@ -157,7 +172,7 @@ func (s *Service) Balances() (map[string]int64, error) {
}
// CompensatedBalance is the mock function wrapper that calls the set implementation
func (s *Service) CompensatedBalance(peer swarm.Address) (int64, error) {
func (s *Service) CompensatedBalance(peer swarm.Address) (*big.Int, error) {
if s.compensatedBalanceFunc != nil {
return s.compensatedBalanceFunc(peer)
}
......@@ -167,7 +182,7 @@ func (s *Service) CompensatedBalance(peer swarm.Address) (int64, error) {
}
// CompensatedBalances is the mock function wrapper that calls the set implementation
func (s *Service) CompensatedBalances() (map[string]int64, error) {
func (s *Service) CompensatedBalances() (map[string]*big.Int, error) {
if s.compensatedBalancesFunc != nil {
return s.compensatedBalancesFunc()
}
......@@ -175,13 +190,13 @@ func (s *Service) CompensatedBalances() (map[string]int64, error) {
}
//
func (s *Service) SurplusBalance(peer swarm.Address) (int64, error) {
func (s *Service) SurplusBalance(peer swarm.Address) (*big.Int, error) {
if s.balanceFunc != nil {
return s.balanceSurplusFunc(peer)
}
s.lock.Lock()
defer s.lock.Unlock()
return 0, nil
return big.NewInt(0), nil
}
// Option is the option passed to the mock accounting service
......
......@@ -6,6 +6,7 @@ package debugapi
import (
"errors"
"math/big"
"net/http"
"github.com/ethersphere/bee/pkg/accounting"
......@@ -23,7 +24,7 @@ var (
type balanceResponse struct {
Peer string `json:"peer"`
Balance int64 `json:"balance"`
Balance *big.Int `json:"balance"`
}
type balancesResponse struct {
......
......@@ -6,6 +6,7 @@ package debugapi_test
import (
"errors"
"math/big"
"net/http"
"reflect"
"testing"
......@@ -19,11 +20,11 @@ import (
)
func TestBalances(t *testing.T) {
compensatedBalancesFunc := func() (ret map[string]int64, err error) {
ret = make(map[string]int64)
ret["DEAD"] = 1000000000000000000
ret["BEEF"] = -100000000000000000
ret["PARTY"] = 0
compensatedBalancesFunc := func() (ret map[string]*big.Int, err error) {
ret = make(map[string]*big.Int)
ret["DEAD"] = big.NewInt(1000000000000000000)
ret["BEEF"] = big.NewInt(-100000000000000000)
ret["PARTY"] = big.NewInt(0)
return ret, err
}
testServer := newTestServer(t, testServerOptions{
......@@ -34,15 +35,15 @@ func TestBalances(t *testing.T) {
[]debugapi.BalanceResponse{
{
Peer: "DEAD",
Balance: 1000000000000000000,
Balance: big.NewInt(1000000000000000000),
},
{
Peer: "BEEF",
Balance: -100000000000000000,
Balance: big.NewInt(-100000000000000000),
},
{
Peer: "PARTY",
Balance: 0,
Balance: big.NewInt(0),
},
},
}
......@@ -61,7 +62,7 @@ func TestBalances(t *testing.T) {
func TestBalancesError(t *testing.T) {
wantErr := errors.New("ASDF")
compensatedBalancesFunc := func() (ret map[string]int64, err error) {
compensatedBalancesFunc := func() (ret map[string]*big.Int, err error) {
return nil, wantErr
}
testServer := newTestServer(t, testServerOptions{
......@@ -78,8 +79,8 @@ func TestBalancesError(t *testing.T) {
func TestBalancesPeers(t *testing.T) {
peer := "bff2c89e85e78c38bd89fca1acc996afb876c21bf5a8482ad798ce15f1c223fa"
compensatedBalanceFunc := func(swarm.Address) (int64, error) {
return 1000000000000000000, nil
compensatedBalanceFunc := func(swarm.Address) (*big.Int, error) {
return big.NewInt(100000000000000000), nil
}
testServer := newTestServer(t, testServerOptions{
AccountingOpts: []mock.Option{mock.WithCompensatedBalanceFunc(compensatedBalanceFunc)},
......@@ -88,7 +89,7 @@ func TestBalancesPeers(t *testing.T) {
jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/balances/"+peer, http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.BalanceResponse{
Peer: peer,
Balance: 1000000000000000000,
Balance: big.NewInt(100000000000000000),
}),
)
}
......@@ -96,8 +97,8 @@ func TestBalancesPeers(t *testing.T) {
func TestBalancesPeersError(t *testing.T) {
peer := "bff2c89e85e78c38bd89fca1acc996afb876c21bf5a8482ad798ce15f1c223fa"
wantErr := errors.New("Error")
compensatedBalanceFunc := func(swarm.Address) (int64, error) {
return 0, wantErr
compensatedBalanceFunc := func(swarm.Address) (*big.Int, error) {
return nil, wantErr
}
testServer := newTestServer(t, testServerOptions{
AccountingOpts: []mock.Option{mock.WithCompensatedBalanceFunc(compensatedBalanceFunc)},
......@@ -113,8 +114,8 @@ func TestBalancesPeersError(t *testing.T) {
func TestBalancesPeersNoBalance(t *testing.T) {
peer := "bff2c89e85e78c38bd89fca1acc996afb876c21bf5a8482ad798ce15f1c223fa"
compensatedBalanceFunc := func(swarm.Address) (int64, error) {
return 0, accounting.ErrPeerNoBalance
compensatedBalanceFunc := func(swarm.Address) (*big.Int, error) {
return nil, accounting.ErrPeerNoBalance
}
testServer := newTestServer(t, testServerOptions{
AccountingOpts: []mock.Option{mock.WithCompensatedBalanceFunc(compensatedBalanceFunc)},
......@@ -172,11 +173,11 @@ func equalBalances(a, b *debugapi.BalancesResponse) bool {
}
func TestConsumedBalances(t *testing.T) {
balancesFunc := func() (ret map[string]int64, err error) {
ret = make(map[string]int64)
ret["DEAD"] = 1000000000000000000
ret["BEEF"] = -100000000000000000
ret["PARTY"] = 0
balancesFunc := func() (ret map[string]*big.Int, err error) {
ret = make(map[string]*big.Int)
ret["DEAD"] = big.NewInt(1000000000000000000)
ret["BEEF"] = big.NewInt(-100000000000000000)
ret["PARTY"] = big.NewInt(0)
return ret, err
}
testServer := newTestServer(t, testServerOptions{
......@@ -187,15 +188,15 @@ func TestConsumedBalances(t *testing.T) {
[]debugapi.BalanceResponse{
{
Peer: "DEAD",
Balance: 1000000000000000000,
Balance: big.NewInt(1000000000000000000),
},
{
Peer: "BEEF",
Balance: -100000000000000000,
Balance: big.NewInt(-100000000000000000),
},
{
Peer: "PARTY",
Balance: 0,
Balance: big.NewInt(0),
},
},
}
......@@ -214,7 +215,7 @@ func TestConsumedBalances(t *testing.T) {
func TestConsumedError(t *testing.T) {
wantErr := errors.New("ASDF")
balancesFunc := func() (ret map[string]int64, err error) {
balancesFunc := func() (ret map[string]*big.Int, err error) {
return nil, wantErr
}
testServer := newTestServer(t, testServerOptions{
......@@ -231,8 +232,8 @@ func TestConsumedError(t *testing.T) {
func TestConsumedPeers(t *testing.T) {
peer := "bff2c89e85e78c38bd89fca1acc996afb876c21bf5a8482ad798ce15f1c223fa"
balanceFunc := func(swarm.Address) (int64, error) {
return 1000000000000000000, nil
balanceFunc := func(swarm.Address) (*big.Int, error) {
return big.NewInt(1000000000000000000), nil
}
testServer := newTestServer(t, testServerOptions{
AccountingOpts: []mock.Option{mock.WithBalanceFunc(balanceFunc)},
......@@ -241,7 +242,7 @@ func TestConsumedPeers(t *testing.T) {
jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/consumed/"+peer, http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.BalanceResponse{
Peer: peer,
Balance: 1000000000000000000,
Balance: big.NewInt(1000000000000000000),
}),
)
}
......@@ -249,8 +250,8 @@ func TestConsumedPeers(t *testing.T) {
func TestConsumedPeersError(t *testing.T) {
peer := "bff2c89e85e78c38bd89fca1acc996afb876c21bf5a8482ad798ce15f1c223fa"
wantErr := errors.New("Error")
balanceFunc := func(swarm.Address) (int64, error) {
return 0, wantErr
balanceFunc := func(swarm.Address) (*big.Int, error) {
return nil, wantErr
}
testServer := newTestServer(t, testServerOptions{
AccountingOpts: []mock.Option{mock.WithBalanceFunc(balanceFunc)},
......@@ -266,8 +267,8 @@ func TestConsumedPeersError(t *testing.T) {
func TestConsumedPeersNoBalance(t *testing.T) {
peer := "bff2c89e85e78c38bd89fca1acc996afb876c21bf5a8482ad798ce15f1c223fa"
balanceFunc := func(swarm.Address) (int64, error) {
return 0, accounting.ErrPeerNoBalance
balanceFunc := func(swarm.Address) (*big.Int, error) {
return nil, accounting.ErrPeerNoBalance
}
testServer := newTestServer(t, testServerOptions{
AccountingOpts: []mock.Option{mock.WithBalanceFunc(balanceFunc)},
......
......@@ -19,7 +19,6 @@ import (
p2pmock "github.com/ethersphere/bee/pkg/p2p/mock"
"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"
swapmock "github.com/ethersphere/bee/pkg/settlement/swap/mock"
"github.com/ethersphere/bee/pkg/storage"
......@@ -42,7 +41,7 @@ type testServerOptions struct {
TopologyOpts []topologymock.Option
Tags *tags.Tags
AccountingOpts []accountingmock.Option
SettlementOpts []settlementmock.Option
SettlementOpts []swapmock.Option
ChequebookOpts []chequebookmock.Option
SwapOpts []swapmock.Option
}
......@@ -55,7 +54,7 @@ type testServer struct {
func newTestServer(t *testing.T, o testServerOptions) *testServer {
topologyDriver := topologymock.NewTopologyDriver(o.TopologyOpts...)
acc := accountingmock.NewAccounting(o.AccountingOpts...)
settlement := settlementmock.NewSettlement(o.SettlementOpts...)
settlement := swapmock.New(o.SettlementOpts...)
chequebook := chequebookmock.NewChequebook(o.ChequebookOpts...)
swapserv := swapmock.NewApiInterface(o.SwapOpts...)
s := debugapi.New(o.Overlay, o.PublicKey, o.PSSPublicKey, o.EthereumAddress, o.P2P, o.Pingpong, topologyDriver, o.Storer, logging.New(ioutil.Discard, 0), nil, o.Tags, acc, settlement, true, swapserv, chequebook)
......
......@@ -22,8 +22,8 @@ var (
type settlementResponse struct {
Peer string `json:"peer"`
SettlementReceived uint64 `json:"received"`
SettlementSent uint64 `json:"sent"`
SettlementReceived *big.Int `json:"received"`
SettlementSent *big.Int `json:"sent"`
}
type settlementsResponse struct {
......@@ -58,9 +58,9 @@ func (s *server) settlementsHandler(w http.ResponseWriter, r *http.Request) {
settlementResponses[a] = settlementResponse{
Peer: a,
SettlementSent: b,
SettlementReceived: 0,
SettlementReceived: big.NewInt(0),
}
totalSent.Add(big.NewInt(int64(b)), totalSent)
totalSent.Add(b, totalSent)
}
for a, b := range settlementsReceived {
......@@ -71,11 +71,11 @@ func (s *server) settlementsHandler(w http.ResponseWriter, r *http.Request) {
} else {
settlementResponses[a] = settlementResponse{
Peer: a,
SettlementSent: 0,
SettlementSent: big.NewInt(0),
SettlementReceived: b,
}
}
totalReceived.Add(big.NewInt(int64(b)), totalReceived)
totalReceived.Add(b, totalReceived)
}
settlementResponsesArray := make([]settlementResponse, len(settlementResponses))
......
......@@ -14,23 +14,23 @@ import (
"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/pseudosettle/mock"
"github.com/ethersphere/bee/pkg/settlement/swap/mock"
"github.com/ethersphere/bee/pkg/swarm"
)
func TestSettlements(t *testing.T) {
settlementsSentFunc := func() (ret map[string]uint64, err error) {
ret = make(map[string]uint64)
ret["DEAD"] = 10000
ret["BEEF"] = 20000
ret["FFFF"] = 50000
settlementsSentFunc := func() (ret map[string]*big.Int, err error) {
ret = make(map[string]*big.Int)
ret["DEAD"] = big.NewInt(10000)
ret["BEEF"] = big.NewInt(20000)
ret["FFFF"] = big.NewInt(50000)
return ret, err
}
settlementsRecvFunc := func() (ret map[string]uint64, err error) {
ret = make(map[string]uint64)
ret["BEEF"] = 10000
ret["EEEE"] = 5000
settlementsRecvFunc := func() (ret map[string]*big.Int, err error) {
ret = make(map[string]*big.Int)
ret["BEEF"] = big.NewInt(10000)
ret["EEEE"] = big.NewInt(5000)
return ret, err
}
......@@ -44,23 +44,23 @@ func TestSettlements(t *testing.T) {
Settlements: []debugapi.SettlementResponse{
{
Peer: "DEAD",
SettlementReceived: 0,
SettlementSent: 10000,
SettlementReceived: big.NewInt(0),
SettlementSent: big.NewInt(10000),
},
{
Peer: "BEEF",
SettlementReceived: 10000,
SettlementSent: 20000,
SettlementReceived: big.NewInt(10000),
SettlementSent: big.NewInt(20000),
},
{
Peer: "FFFF",
SettlementReceived: 0,
SettlementSent: 50000,
SettlementReceived: big.NewInt(0),
SettlementSent: big.NewInt(50000),
},
{
Peer: "EEEE",
SettlementReceived: 5000,
SettlementSent: 0,
SettlementReceived: big.NewInt(5000),
SettlementSent: big.NewInt(0),
},
},
}
......@@ -79,7 +79,7 @@ func TestSettlements(t *testing.T) {
func TestSettlementsError(t *testing.T) {
wantErr := errors.New("New errors")
settlementsSentFunc := func() (map[string]uint64, error) {
settlementsSentFunc := func() (map[string]*big.Int, error) {
return nil, wantErr
}
testServer := newTestServer(t, testServerOptions{
......@@ -96,8 +96,8 @@ func TestSettlementsError(t *testing.T) {
func TestSettlementsPeers(t *testing.T) {
peer := "bff2c89e85e78c38bd89fca1acc996afb876c21bf5a8482ad798ce15f1c223fa"
settlementSentFunc := func(swarm.Address) (uint64, error) {
return 1000000000000000000, nil
settlementSentFunc := func(swarm.Address) (*big.Int, error) {
return big.NewInt(1000000000000000000), nil
}
testServer := newTestServer(t, testServerOptions{
SettlementOpts: []mock.Option{mock.WithSettlementSentFunc(settlementSentFunc)},
......@@ -106,8 +106,8 @@ func TestSettlementsPeers(t *testing.T) {
jsonhttptest.Request(t, testServer.Client, http.MethodGet, "/settlements/"+peer, http.StatusOK,
jsonhttptest.WithExpectedJSONResponse(debugapi.SettlementResponse{
Peer: peer,
SettlementSent: 1000000000000000000,
SettlementReceived: 0,
SettlementSent: big.NewInt(1000000000000000000),
SettlementReceived: big.NewInt(0),
}),
)
}
......@@ -115,8 +115,8 @@ func TestSettlementsPeers(t *testing.T) {
func TestSettlementsPeersError(t *testing.T) {
peer := "bff2c89e85e78c38bd89fca1acc996afb876c21bf5a8482ad798ce15f1c223fa"
wantErr := errors.New("Error")
settlementSentFunc := func(swarm.Address) (uint64, error) {
return 0, wantErr
settlementSentFunc := func(swarm.Address) (*big.Int, error) {
return nil, wantErr
}
testServer := newTestServer(t, testServerOptions{
SettlementOpts: []mock.Option{mock.WithSettlementSentFunc(settlementSentFunc)},
......
......@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"log"
"math/big"
"net"
"net/http"
"path/filepath"
......@@ -97,14 +98,14 @@ type Options struct {
TracingEndpoint string
TracingServiceName string
GlobalPinningEnabled bool
PaymentThreshold uint64
PaymentTolerance uint64
PaymentEarly uint64
PaymentThreshold string
PaymentTolerance string
PaymentEarly string
ResolverConnectionCfgs []multiresolver.ConnectionConfig
GatewayMode bool
SwapEndpoint string
SwapFactoryAddress string
SwapInitialDeposit uint64
SwapInitialDeposit string
SwapEnable bool
}
......@@ -198,12 +199,16 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
}
}
swapInitialDeposit, ok := new(big.Int).SetString(o.SwapInitialDeposit, 10)
if !ok {
return nil, fmt.Errorf("invalid initial deposit: %s", swapInitialDeposit)
}
// initialize chequebook logic
chequebookService, err = chequebook.Init(p2pCtx,
chequebookFactory,
stateStore,
logger,
o.SwapInitialDeposit,
swapInitialDeposit,
transactionService,
swapBackend,
chainID.Int64(),
......@@ -300,12 +305,32 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey,
settlement = pseudosettleService
}
pricing := pricing.New(p2ps, logger, o.PaymentThreshold)
paymentThreshold, ok := new(big.Int).SetString(o.PaymentThreshold, 10)
if !ok {
return nil, fmt.Errorf("invalid payment threshold: %s", paymentThreshold)
}
pricing := pricing.New(p2ps, logger, paymentThreshold)
if err = p2ps.AddProtocol(pricing.Protocol()); err != nil {
return nil, fmt.Errorf("pricing service: %w", err)
}
acc, err := accounting.NewAccounting(o.PaymentThreshold, o.PaymentTolerance, o.PaymentEarly, logger, stateStore, settlement, pricing)
paymentTolerance, ok := new(big.Int).SetString(o.PaymentTolerance, 10)
if !ok {
return nil, fmt.Errorf("invalid payment tolerance: %s", paymentTolerance)
}
paymentEarly, ok := new(big.Int).SetString(o.PaymentEarly, 10)
if !ok {
return nil, fmt.Errorf("invalid payment early: %s", paymentEarly)
}
acc, err := accounting.NewAccounting(
paymentThreshold,
paymentTolerance,
paymentEarly,
logger,
stateStore,
settlement,
pricing,
)
if err != nil {
return nil, fmt.Errorf("accounting: %w", err)
}
......
......@@ -23,7 +23,7 @@ var _ = math.Inf
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type AnnouncePaymentThreshold struct {
PaymentThreshold uint64 `protobuf:"varint,1,opt,name=PaymentThreshold,proto3" json:"PaymentThreshold,omitempty"`
PaymentThreshold []byte `protobuf:"bytes,1,opt,name=PaymentThreshold,proto3" json:"PaymentThreshold,omitempty"`
}
func (m *AnnouncePaymentThreshold) Reset() { *m = AnnouncePaymentThreshold{} }
......@@ -59,11 +59,11 @@ func (m *AnnouncePaymentThreshold) XXX_DiscardUnknown() {
var xxx_messageInfo_AnnouncePaymentThreshold proto.InternalMessageInfo
func (m *AnnouncePaymentThreshold) GetPaymentThreshold() uint64 {
func (m *AnnouncePaymentThreshold) GetPaymentThreshold() []byte {
if m != nil {
return m.PaymentThreshold
}
return 0
return nil
}
func init() {
......@@ -78,10 +78,10 @@ var fileDescriptor_ec4cc93d045d43d0 = []byte{
0xce, 0xcc, 0x4b, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x87, 0x72, 0x95, 0xdc, 0xb8,
0x24, 0x1c, 0xf3, 0xf2, 0xf2, 0x4b, 0xf3, 0x92, 0x53, 0x03, 0x12, 0x2b, 0x73, 0x53, 0xf3, 0x4a,
0x42, 0x32, 0x8a, 0x52, 0x8b, 0x33, 0xf2, 0x73, 0x52, 0x84, 0xb4, 0xb8, 0x04, 0xd0, 0xc5, 0x24,
0x18, 0x15, 0x18, 0x35, 0x58, 0x82, 0x30, 0xc4, 0x9d, 0x64, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0,
0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0x30, 0xc4, 0x9d, 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, 0xab, 0x31, 0x20, 0x00, 0x00,
0xff, 0xff, 0x70, 0x59, 0x58, 0xcf, 0x86, 0x00, 0x00, 0x00,
0xff, 0xff, 0x50, 0xca, 0x0e, 0x0a, 0x86, 0x00, 0x00, 0x00,
}
func (m *AnnouncePaymentThreshold) Marshal() (dAtA []byte, err error) {
......@@ -104,10 +104,12 @@ func (m *AnnouncePaymentThreshold) MarshalToSizedBuffer(dAtA []byte) (int, error
_ = i
var l int
_ = l
if m.PaymentThreshold != 0 {
i = encodeVarintPricing(dAtA, i, uint64(m.PaymentThreshold))
if len(m.PaymentThreshold) > 0 {
i -= len(m.PaymentThreshold)
copy(dAtA[i:], m.PaymentThreshold)
i = encodeVarintPricing(dAtA, i, uint64(len(m.PaymentThreshold)))
i--
dAtA[i] = 0x8
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
......@@ -129,8 +131,9 @@ func (m *AnnouncePaymentThreshold) Size() (n int) {
}
var l int
_ = l
if m.PaymentThreshold != 0 {
n += 1 + sovPricing(uint64(m.PaymentThreshold))
l = len(m.PaymentThreshold)
if l > 0 {
n += 1 + l + sovPricing(uint64(l))
}
return n
}
......@@ -171,10 +174,10 @@ func (m *AnnouncePaymentThreshold) Unmarshal(dAtA []byte) error {
}
switch fieldNum {
case 1:
if wireType != 0 {
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field PaymentThreshold", wireType)
}
m.PaymentThreshold = 0
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowPricing
......@@ -184,11 +187,26 @@ func (m *AnnouncePaymentThreshold) Unmarshal(dAtA []byte) error {
}
b := dAtA[iNdEx]
iNdEx++
m.PaymentThreshold |= uint64(b&0x7F) << shift
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthPricing
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return ErrInvalidLengthPricing
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.PaymentThreshold = append(m.PaymentThreshold[:0], dAtA[iNdEx:postIndex]...)
if m.PaymentThreshold == nil {
m.PaymentThreshold = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipPricing(dAtA[iNdEx:])
......
......@@ -9,5 +9,5 @@ package pricing;
option go_package = "pb";
message AnnouncePaymentThreshold {
uint64 PaymentThreshold = 1;
bytes PaymentThreshold = 1;
}
......@@ -7,6 +7,7 @@ package pricing
import (
"context"
"fmt"
"math/big"
"time"
"github.com/ethersphere/bee/pkg/logging"
......@@ -26,22 +27,22 @@ var _ Interface = (*Service)(nil)
// Interface is the main interface of the pricing protocol
type Interface interface {
AnnouncePaymentThreshold(ctx context.Context, peer swarm.Address, paymentThreshold uint64) error
AnnouncePaymentThreshold(ctx context.Context, peer swarm.Address, paymentThreshold *big.Int) error
}
// PaymentThresholdObserver is used for being notified of payment threshold updates
type PaymentThresholdObserver interface {
NotifyPaymentThreshold(peer swarm.Address, paymentThreshold uint64) error
NotifyPaymentThreshold(peer swarm.Address, paymentThreshold *big.Int) error
}
type Service struct {
streamer p2p.Streamer
logger logging.Logger
paymentThreshold uint64
paymentThreshold *big.Int
paymentThresholdObserver PaymentThresholdObserver
}
func New(streamer p2p.Streamer, logger logging.Logger, paymentThreshold uint64) *Service {
func New(streamer p2p.Streamer, logger logging.Logger, paymentThreshold *big.Int) *Service {
return &Service{
streamer: streamer,
logger: logger,
......@@ -81,7 +82,7 @@ func (s *Service) handler(ctx context.Context, p p2p.Peer, stream p2p.Stream) (e
}
s.logger.Tracef("received payment threshold announcement from peer %v of %d", p.Address, req.PaymentThreshold)
return s.paymentThresholdObserver.NotifyPaymentThreshold(p.Address, req.PaymentThreshold)
return s.paymentThresholdObserver.NotifyPaymentThreshold(p.Address, big.NewInt(0).SetBytes(req.PaymentThreshold))
}
func (s *Service) init(ctx context.Context, p p2p.Peer) error {
......@@ -93,7 +94,7 @@ func (s *Service) init(ctx context.Context, p p2p.Peer) error {
}
// AnnouncePaymentThreshold announces the payment threshold to per
func (s *Service) AnnouncePaymentThreshold(ctx context.Context, peer swarm.Address, paymentThreshold uint64) error {
func (s *Service) AnnouncePaymentThreshold(ctx context.Context, peer swarm.Address, paymentThreshold *big.Int) error {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
......@@ -112,7 +113,7 @@ func (s *Service) AnnouncePaymentThreshold(ctx context.Context, peer swarm.Addre
s.logger.Tracef("sending payment threshold announcement to peer %v of %d", peer, paymentThreshold)
w := protobuf.NewWriter(stream)
err = w.WriteMsgWithContext(ctx, &pb.AnnouncePaymentThreshold{
PaymentThreshold: paymentThreshold,
PaymentThreshold: paymentThreshold.Bytes(),
})
return err
......
......@@ -8,6 +8,7 @@ import (
"bytes"
"context"
"io/ioutil"
"math/big"
"testing"
"github.com/ethersphere/bee/pkg/logging"
......@@ -21,10 +22,10 @@ import (
type testObserver struct {
called bool
peer swarm.Address
paymentThreshold uint64
paymentThreshold *big.Int
}
func (t *testObserver) NotifyPaymentThreshold(peer swarm.Address, paymentThreshold uint64) error {
func (t *testObserver) NotifyPaymentThreshold(peer swarm.Address, paymentThreshold *big.Int) error {
t.called = true
t.peer = peer
t.paymentThreshold = paymentThreshold
......@@ -33,7 +34,7 @@ func (t *testObserver) NotifyPaymentThreshold(peer swarm.Address, paymentThresho
func TestAnnouncePaymentThreshold(t *testing.T) {
logger := logging.New(ioutil.Discard, 0)
testThreshold := uint64(100000)
testThreshold := big.NewInt(100000)
observer := &testObserver{}
recipient := pricing.New(nil, logger, testThreshold)
......@@ -46,7 +47,7 @@ func TestAnnouncePaymentThreshold(t *testing.T) {
payer := pricing.New(recorder, logger, testThreshold)
peerID := swarm.MustParseHexAddress("9ee7add7")
paymentThreshold := uint64(10000)
paymentThreshold := big.NewInt(10000)
err := payer.AnnouncePaymentThreshold(context.Background(), peerID, paymentThreshold)
if err != nil {
......@@ -76,8 +77,8 @@ func TestAnnouncePaymentThreshold(t *testing.T) {
t.Fatalf("got %v messages, want %v", len(messages), 1)
}
sentPaymentThreshold := messages[0].(*pb.AnnouncePaymentThreshold).PaymentThreshold
if sentPaymentThreshold != paymentThreshold {
sentPaymentThreshold := big.NewInt(0).SetBytes(messages[0].(*pb.AnnouncePaymentThreshold).PaymentThreshold)
if sentPaymentThreshold.Cmp(paymentThreshold) != 0 {
t.Fatalf("got message with amount %v, want %v", sentPaymentThreshold, paymentThreshold)
}
......@@ -85,7 +86,7 @@ func TestAnnouncePaymentThreshold(t *testing.T) {
t.Fatal("expected observer to be called")
}
if observer.paymentThreshold != paymentThreshold {
if observer.paymentThreshold.Cmp(paymentThreshold) != 0 {
t.Fatalf("observer called with wrong paymentThreshold. got %d, want %d", observer.paymentThreshold, paymentThreshold)
}
......
......@@ -76,7 +76,7 @@ func TestSendChunkAndReceiveReceipt(t *testing.T) {
t.Fatal(err)
}
if balance != -int64(fixedPrice) {
if balance.Int64() != -int64(fixedPrice) {
t.Fatalf("unexpected balance on pivot. want %d got %d", -int64(fixedPrice), balance)
}
......@@ -85,7 +85,7 @@ func TestSendChunkAndReceiveReceipt(t *testing.T) {
t.Fatal(err)
}
if balance != int64(fixedPrice) {
if balance.Int64() != int64(fixedPrice) {
t.Fatalf("unexpected balance on peer. want %d got %d", int64(fixedPrice), balance)
}
}
......@@ -155,7 +155,7 @@ func TestPushChunkToClosest(t *testing.T) {
t.Fatal(err)
}
if balance != -int64(fixedPrice) {
if balance.Int64() != -int64(fixedPrice) {
t.Fatalf("unexpected balance on pivot. want %d got %d", -int64(fixedPrice), balance)
}
......@@ -164,7 +164,7 @@ func TestPushChunkToClosest(t *testing.T) {
t.Fatal(err)
}
if balance != int64(fixedPrice) {
if balance.Int64() != int64(fixedPrice) {
t.Fatalf("unexpected balance on peer. want %d got %d", int64(fixedPrice), balance)
}
......@@ -273,7 +273,7 @@ func TestPushChunkToNextClosest(t *testing.T) {
t.Fatal(err)
}
if balance != -int64(fixedPrice) {
if balance.Int64() != -int64(fixedPrice) {
t.Fatalf("unexpected balance on pivot. want %d got %d", -int64(fixedPrice), balance)
}
......@@ -282,7 +282,7 @@ func TestPushChunkToNextClosest(t *testing.T) {
t.Fatal(err)
}
if balance2 != int64(fixedPrice) {
if balance2.Int64() != int64(fixedPrice) {
t.Fatalf("unexpected balance on peer2. want %d got %d", int64(fixedPrice), balance2)
}
......@@ -291,7 +291,7 @@ func TestPushChunkToNextClosest(t *testing.T) {
t.Fatal(err)
}
if balance1 != 0 {
if balance1.Int64() != 0 {
t.Fatalf("unexpected balance on peer1. want %d got %d", 0, balance1)
}
}
......@@ -354,7 +354,7 @@ func TestHandler(t *testing.T) {
t.Fatal(err)
}
if balance != -int64(fixedPrice) {
if balance.Int64() != -int64(fixedPrice) {
t.Fatalf("unexpected balance on trigger. want %d got %d", -int64(fixedPrice), balance)
}
......@@ -364,7 +364,7 @@ func TestHandler(t *testing.T) {
t.Fatal(err)
}
if balance != int64(fixedPrice) {
if balance.Int64() != int64(fixedPrice) {
t.Fatalf("unexpected balance on pivot. want %d got %d", int64(fixedPrice), balance)
}
......@@ -373,7 +373,7 @@ func TestHandler(t *testing.T) {
t.Fatal(err)
}
if balance != -int64(fixedPrice) {
if balance.Int64() != -int64(fixedPrice) {
t.Fatalf("unexpected balance on pivot. want %d got %d", -int64(fixedPrice), balance)
}
......@@ -382,7 +382,7 @@ func TestHandler(t *testing.T) {
t.Fatal(err)
}
if balance != int64(fixedPrice) {
if balance.Int64() != int64(fixedPrice) {
t.Fatalf("unexpected balance on closest. want %d got %d", int64(fixedPrice), balance)
}
}
......
......@@ -120,12 +120,12 @@ func TestDelivery(t *testing.T) {
}
clientBalance, _ := clientMockAccounting.Balance(peerID)
if clientBalance != -int64(price) {
if clientBalance.Int64() != -int64(price) {
t.Fatalf("unexpected balance on client. want %d got %d", -price, clientBalance)
}
serverBalance, _ := serverMockAccounting.Balance(peerID)
if serverBalance != int64(price) {
if serverBalance.Int64() != int64(price) {
t.Fatalf("unexpected balance on server. want %d got %d", price, serverBalance)
}
}
......@@ -418,12 +418,12 @@ func TestRetrievePreemptiveRetry(t *testing.T) {
}
clientServer1Balance, _ := clientMockAccounting.Balance(serverAddress1)
if clientServer1Balance != 0 {
if clientServer1Balance.Int64() != 0 {
t.Fatalf("unexpected balance on client. want %d got %d", -price, clientServer1Balance)
}
clientServer2Balance, _ := clientMockAccounting.Balance(serverAddress2)
if clientServer2Balance != -int64(price) {
if clientServer2Balance.Int64() != -int64(price) {
t.Fatalf("unexpected balance on client. want %d got %d", -price, clientServer2Balance)
}
......@@ -432,12 +432,12 @@ func TestRetrievePreemptiveRetry(t *testing.T) {
time.Sleep(2 * time.Second)
clientServer1Balance, _ = clientMockAccounting.Balance(serverAddress1)
if clientServer1Balance != -int64(price) {
if clientServer1Balance.Int64() != -int64(price) {
t.Fatalf("unexpected balance on client. want %d got %d", -price, clientServer1Balance)
}
clientServer2Balance, _ = clientMockAccounting.Balance(serverAddress2)
if clientServer2Balance != -int64(price) {
if clientServer2Balance.Int64() != -int64(price) {
t.Fatalf("unexpected balance on client. want %d got %d", -price, clientServer2Balance)
}
})
......
......@@ -7,6 +7,7 @@ package settlement
import (
"context"
"errors"
"math/big"
"github.com/ethersphere/bee/pkg/swarm"
)
......@@ -19,18 +20,18 @@ var (
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 uint64) error
Pay(ctx context.Context, peer swarm.Address, amount *big.Int) error
// TotalSent returns the total amount sent to a peer
TotalSent(peer swarm.Address) (totalSent uint64, err error)
TotalSent(peer swarm.Address) (totalSent *big.Int, err error)
// TotalReceived returns the total amount received from a peer
TotalReceived(peer swarm.Address) (totalSent uint64, err error)
TotalReceived(peer swarm.Address) (totalSent *big.Int, err error)
// SettlementsSent returns sent settlements for each individual known peer
SettlementsSent() (map[string]uint64, error)
SettlementsSent() (map[string]*big.Int, error)
// SettlementsReceived returns received settlements for each individual known peer
SettlementsReceived() (map[string]uint64, error)
SettlementsReceived() (map[string]*big.Int, error)
// SetNotifyPaymentFunc sets the NotifyPaymentFunc to notify
SetNotifyPaymentFunc(notifyPaymentFunc NotifyPaymentFunc)
}
// NotifyPaymentFunc is called when a payment from peer was successfully received
type NotifyPaymentFunc func(peer swarm.Address, amount uint64) error
type NotifyPaymentFunc func(peer swarm.Address, amount *big.Int) 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"
"sync"
"github.com/ethersphere/bee/pkg/settlement"
"github.com/ethersphere/bee/pkg/swarm"
)
// Service is the mock settlement service.
type Service struct {
lock sync.Mutex
settlementsSent map[string]uint64
settlementsRecv map[string]uint64
settlementSentFunc func(swarm.Address) (uint64, error)
settlementRecvFunc func(swarm.Address) (uint64, error)
settlementsSentFunc func() (map[string]uint64, error)
settlementsRecvFunc func() (map[string]uint64, error)
payFunc func(context.Context, swarm.Address, uint64) error
}
// WithsettlementFunc sets the mock settlement function
func WithSettlementSentFunc(f func(swarm.Address) (uint64, error)) Option {
return optionFunc(func(s *Service) {
s.settlementSentFunc = f
})
}
func WithSettlementRecvFunc(f func(swarm.Address) (uint64, error)) Option {
return optionFunc(func(s *Service) {
s.settlementRecvFunc = f
})
}
// WithsettlementsFunc sets the mock settlements function
func WithSettlementsSentFunc(f func() (map[string]uint64, error)) Option {
return optionFunc(func(s *Service) {
s.settlementsSentFunc = f
})
}
func WithSettlementsRecvFunc(f func() (map[string]uint64, error)) Option {
return optionFunc(func(s *Service) {
s.settlementsRecvFunc = f
})
}
func WithPayFunc(f func(context.Context, swarm.Address, uint64) error) Option {
return optionFunc(func(s *Service) {
s.payFunc = f
})
}
// Newsettlement creates the mock settlement implementation
func NewSettlement(opts ...Option) settlement.Interface {
mock := new(Service)
mock.settlementsSent = make(map[string]uint64)
mock.settlementsRecv = make(map[string]uint64)
for _, o := range opts {
o.apply(mock)
}
return mock
}
func (s *Service) Pay(c context.Context, peer swarm.Address, amount uint64) error {
if s.payFunc != nil {
return s.payFunc(c, peer, amount)
}
s.settlementsSent[peer.String()] += amount
return nil
}
func (s *Service) TotalSent(peer swarm.Address) (totalSent uint64, err error) {
if s.settlementSentFunc != nil {
return s.settlementSentFunc(peer)
}
s.lock.Lock()
defer s.lock.Unlock()
return s.settlementsSent[peer.String()], nil
}
func (s *Service) TotalReceived(peer swarm.Address) (totalSent uint64, err error) {
if s.settlementRecvFunc != nil {
return s.settlementRecvFunc(peer)
}
s.lock.Lock()
defer s.lock.Unlock()
return s.settlementsRecv[peer.String()], nil
}
// settlements is the mock function wrapper that calls the set implementation
func (s *Service) SettlementsSent() (map[string]uint64, error) {
if s.settlementsSentFunc != nil {
return s.settlementsSentFunc()
}
s.lock.Lock()
defer s.lock.Unlock()
return s.settlementsSent, nil
}
func (s *Service) SettlementsReceived() (map[string]uint64, error) {
if s.settlementsRecvFunc != nil {
return s.settlementsRecvFunc()
}
s.lock.Lock()
defer s.lock.Unlock()
return s.settlementsRecv, nil
}
func (s *Service) SetNotifyPaymentFunc(settlement.NotifyPaymentFunc) {
}
// Option is the option passed to the mock settlement service
type Option interface {
apply(*Service)
}
type optionFunc func(*Service)
func (f optionFunc) apply(r *Service) { f(r) }
......@@ -8,6 +8,7 @@ import (
"context"
"errors"
"fmt"
"math/big"
"strings"
"time"
......@@ -97,19 +98,19 @@ func (s *Service) handler(ctx context.Context, p p2p.Peer, stream p2p.Stream) (e
if !errors.Is(err, settlement.ErrPeerNoSettlements) {
return err
}
totalReceived = 0
totalReceived = big.NewInt(0)
}
err = s.store.Put(totalKey(p.Address, SettlementReceivedPrefix), totalReceived+req.Amount)
err = s.store.Put(totalKey(p.Address, SettlementReceivedPrefix), totalReceived.Add(totalReceived, new(big.Int).SetUint64(req.Amount)))
if err != nil {
return err
}
return s.notifyPaymentFunc(p.Address, req.Amount)
return s.notifyPaymentFunc(p.Address, new(big.Int).SetUint64(req.Amount))
}
// Pay initiates a payment to the given peer
func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount uint64) error {
func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount *big.Int) error {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
......@@ -128,7 +129,7 @@ func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount uint64) er
s.logger.Tracef("sending payment message to peer %v of %d", peer, amount)
w := protobuf.NewWriter(stream)
err = w.WriteMsgWithContext(ctx, &pb.Payment{
Amount: amount,
Amount: amount.Uint64(),
})
if err != nil {
return err
......@@ -138,13 +139,15 @@ func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount uint64) er
if !errors.Is(err, settlement.ErrPeerNoSettlements) {
return err
}
totalSent = 0
totalSent = big.NewInt(0)
}
err = s.store.Put(totalKey(peer, SettlementSentPrefix), totalSent+amount)
err = s.store.Put(totalKey(peer, SettlementSentPrefix), totalSent.Add(totalSent, amount))
if err != nil {
return err
}
s.metrics.TotalSentPseudoSettlements.Add(float64(amount))
amountFloat, _ := new(big.Float).SetInt(amount).Float64()
s.metrics.TotalSentPseudoSettlements.Add(amountFloat)
return nil
}
......@@ -154,41 +157,41 @@ func (s *Service) SetNotifyPaymentFunc(notifyPaymentFunc settlement.NotifyPaymen
}
// TotalSent returns the total amount sent to a peer
func (s *Service) TotalSent(peer swarm.Address) (totalSent uint64, err error) {
func (s *Service) TotalSent(peer swarm.Address) (totalSent *big.Int, err error) {
key := totalKey(peer, SettlementSentPrefix)
err = s.store.Get(key, &totalSent)
if err != nil {
if errors.Is(err, storage.ErrNotFound) {
return 0, settlement.ErrPeerNoSettlements
return nil, settlement.ErrPeerNoSettlements
}
return 0, err
return nil, err
}
return totalSent, nil
}
// TotalReceived returns the total amount received from a peer
func (s *Service) TotalReceived(peer swarm.Address) (totalReceived uint64, err error) {
func (s *Service) TotalReceived(peer swarm.Address) (totalReceived *big.Int, err error) {
key := totalKey(peer, SettlementReceivedPrefix)
err = s.store.Get(key, &totalReceived)
if err != nil {
if errors.Is(err, storage.ErrNotFound) {
return 0, settlement.ErrPeerNoSettlements
return nil, settlement.ErrPeerNoSettlements
}
return 0, err
return nil, err
}
return totalReceived, nil
}
// AllSettlements returns all stored settlement values for a given type of prefix (sent or received)
func (s *Service) SettlementsSent() (map[string]uint64, error) {
sent := make(map[string]uint64)
// SettlementsSent returns all stored sent settlement values for a given type of prefix
func (s *Service) SettlementsSent() (map[string]*big.Int, error) {
sent := make(map[string]*big.Int)
err := s.store.Iterate(SettlementSentPrefix, func(key, val []byte) (stop bool, err error) {
addr, err := totalKeyPeer(key, SettlementSentPrefix)
if err != nil {
return false, fmt.Errorf("parse address from key: %s: %w", string(key), err)
}
if _, ok := sent[addr.String()]; !ok {
var storevalue uint64
var storevalue *big.Int
err = s.store.Get(totalKey(addr, SettlementSentPrefix), &storevalue)
if err != nil {
return false, fmt.Errorf("get peer %s settlement balance: %w", addr.String(), err)
......@@ -204,15 +207,16 @@ func (s *Service) SettlementsSent() (map[string]uint64, error) {
return sent, nil
}
func (s *Service) SettlementsReceived() (map[string]uint64, error) {
received := make(map[string]uint64)
// SettlementsReceived returns all stored received settlement values for a given type of prefix
func (s *Service) SettlementsReceived() (map[string]*big.Int, error) {
received := make(map[string]*big.Int)
err := s.store.Iterate(SettlementReceivedPrefix, func(key, val []byte) (stop bool, err error) {
addr, err := totalKeyPeer(key, SettlementReceivedPrefix)
if err != nil {
return false, fmt.Errorf("parse address from key: %s: %w", string(key), err)
}
if _, ok := received[addr.String()]; !ok {
var storevalue uint64
var storevalue *big.Int
err = s.store.Get(totalKey(addr, SettlementReceivedPrefix), &storevalue)
if err != nil {
return false, fmt.Errorf("get peer %s settlement balance: %w", addr.String(), err)
......
......@@ -8,6 +8,7 @@ import (
"bytes"
"context"
"io/ioutil"
"math/big"
"testing"
"time"
......@@ -23,7 +24,7 @@ import (
type testObserver struct {
called chan struct{}
peer swarm.Address
amount uint64
amount *big.Int
}
func newTestObserver() *testObserver {
......@@ -32,7 +33,7 @@ func newTestObserver() *testObserver {
}
}
func (t *testObserver) NotifyPayment(peer swarm.Address, amount uint64) error {
func (t *testObserver) NotifyPayment(peer swarm.Address, amount *big.Int) error {
close(t.called)
t.peer = peer
t.amount = amount
......@@ -59,7 +60,7 @@ func TestPayment(t *testing.T) {
payer := pseudosettle.New(recorder, logger, storePayer)
peerID := swarm.MustParseHexAddress("9ee7add7")
amount := uint64(10000)
amount := big.NewInt(10000)
err := payer.Pay(context.Background(), peerID, amount)
if err != nil {
......@@ -94,7 +95,7 @@ func TestPayment(t *testing.T) {
}
sentAmount := messages[0].(*pb.Payment).Amount
if sentAmount != amount {
if sentAmount != amount.Uint64() {
t.Fatalf("got message with amount %v, want %v", sentAmount, amount)
}
......@@ -104,7 +105,7 @@ func TestPayment(t *testing.T) {
t.Fatal("expected observer to be called")
}
if observer.amount != amount {
if observer.amount.Cmp(amount) != 0 {
t.Fatalf("observer called with wrong amount. got %d, want %d", observer.amount, amount)
}
......@@ -117,7 +118,7 @@ func TestPayment(t *testing.T) {
t.Fatal(err)
}
if totalSent != sentAmount {
if totalSent.Cmp(new(big.Int).SetUint64(sentAmount)) != 0 {
t.Fatalf("stored wrong totalSent. got %d, want %d", totalSent, sentAmount)
}
......@@ -126,7 +127,7 @@ func TestPayment(t *testing.T) {
t.Fatal(err)
}
if totalReceived != sentAmount {
if totalReceived.Cmp(new(big.Int).SetUint64(sentAmount)) != 0 {
t.Fatalf("stored wrong totalReceived. got %d, want %d", totalReceived, sentAmount)
}
}
......@@ -22,7 +22,7 @@ const chequebookKey = "chequebook"
func checkBalance(
ctx context.Context,
logger logging.Logger,
swapInitialDeposit uint64,
swapInitialDeposit *big.Int,
swapBackend transaction.Backend,
chainId int64,
overlayEthAddress common.Address,
......@@ -47,7 +47,7 @@ func checkBalance(
return err
}
if balance.Cmp(big.NewInt(int64(swapInitialDeposit))) < 0 {
if balance.Cmp(swapInitialDeposit) < 0 {
logger.Warningf("cannot continue until there is sufficient ETH and BZZ available on %x", overlayEthAddress)
if chainId == 5 {
logger.Warningf("on the test network you can get both Goerli ETH and Goerli BZZ from https://faucet.ethswarm.org?address=%x", overlayEthAddress)
......@@ -70,7 +70,7 @@ func Init(
chequebookFactory Factory,
stateStore storage.StateStorer,
logger logging.Logger,
swapInitialDeposit uint64,
swapInitialDeposit *big.Int,
transactionService transaction.Service,
swapBackend transaction.Backend,
chainId int64,
......@@ -97,7 +97,7 @@ func Init(
}
logger.Info("no chequebook found, deploying new one.")
if swapInitialDeposit != 0 {
if swapInitialDeposit.Cmp(big.NewInt(0)) != 0 {
err = checkBalance(ctx, logger, swapInitialDeposit, swapBackend, chainId, overlayEthAddress, erc20BindingFunc, erc20Address, 20*time.Second, 10)
if err != nil {
return nil, err
......@@ -130,9 +130,9 @@ func Init(
return nil, err
}
if swapInitialDeposit != 0 {
if swapInitialDeposit.Cmp(big.NewInt(0)) != 0 {
logger.Infof("depositing %d token into new chequebook", swapInitialDeposit)
depositHash, err := chequebookService.Deposit(ctx, big.NewInt(int64(swapInitialDeposit)))
depositHash, err := chequebookService.Deposit(ctx, swapInitialDeposit)
if err != nil {
return nil, err
}
......
......@@ -6,6 +6,7 @@ package mock
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
......@@ -16,14 +17,17 @@ import (
)
type Service struct {
settlementSentFunc func(swarm.Address) (uint64, error)
settlementRecvFunc func(swarm.Address) (uint64, error)
settlementsSent map[string]*big.Int
settlementsRecv map[string]*big.Int
settlementsSentFunc func() (map[string]uint64, error)
settlementsRecvFunc func() (map[string]uint64, error)
settlementSentFunc func(swarm.Address) (*big.Int, error)
settlementRecvFunc func(swarm.Address) (*big.Int, error)
settlementsSentFunc func() (map[string]*big.Int, error)
settlementsRecvFunc func() (map[string]*big.Int, error)
receiveChequeFunc func(context.Context, swarm.Address, *chequebook.SignedCheque) error
payFunc func(context.Context, swarm.Address, uint64) error
payFunc func(context.Context, swarm.Address, *big.Int) error
setNotifyPaymentFunc settlement.NotifyPaymentFunc
handshakeFunc func(swarm.Address, common.Address) error
lastSentChequeFunc func(swarm.Address) (*chequebook.SignedCheque, error)
......@@ -37,26 +41,26 @@ type Service struct {
}
// WithsettlementFunc sets the mock settlement function
func WithSettlementSentFunc(f func(swarm.Address) (uint64, error)) Option {
func WithSettlementSentFunc(f func(swarm.Address) (*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.settlementSentFunc = f
})
}
func WithSettlementRecvFunc(f func(swarm.Address) (uint64, error)) Option {
func WithSettlementRecvFunc(f func(swarm.Address) (*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.settlementRecvFunc = f
})
}
// WithsettlementsFunc sets the mock settlements function
func WithSettlementsSentFunc(f func() (map[string]uint64, error)) Option {
func WithSettlementsSentFunc(f func() (map[string]*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.settlementsSentFunc = f
})
}
func WithSettlementsRecvFunc(f func() (map[string]uint64, error)) Option {
func WithSettlementsRecvFunc(f func() (map[string]*big.Int, error)) Option {
return optionFunc(func(s *Service) {
s.settlementsRecvFunc = f
})
......@@ -68,7 +72,7 @@ func WithReceiveChequeFunc(f func(context.Context, swarm.Address, *chequebook.Si
})
}
func WithPayFunc(f func(context.Context, swarm.Address, uint64) error) Option {
func WithPayFunc(f func(context.Context, swarm.Address, *big.Int) error) Option {
return optionFunc(func(s *Service) {
s.payFunc = f
})
......@@ -126,6 +130,8 @@ func WithCashoutStatusFunc(f func(ctx context.Context, peer swarm.Address) (*che
// New creates the mock swap implementation
func New(opts ...Option) settlement.Interface {
mock := new(Service)
mock.settlementsSent = make(map[string]*big.Int)
mock.settlementsRecv = make(map[string]*big.Int)
for _, o := range opts {
o.apply(mock)
}
......@@ -149,10 +155,15 @@ func (s *Service) ReceiveCheque(ctx context.Context, peer swarm.Address, cheque
}
// Pay is the mock Pay function of swap.
func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount uint64) error {
func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount *big.Int) error {
if s.payFunc != nil {
return s.payFunc(ctx, peer, amount)
}
if settlement, ok := s.settlementsSent[peer.String()]; ok {
s.settlementsSent[peer.String()] = big.NewInt(0).Add(settlement, amount)
} else {
s.settlementsSent[peer.String()] = amount
}
return nil
}
......@@ -163,37 +174,41 @@ func (s *Service) SetNotifyPaymentFunc(f settlement.NotifyPaymentFunc) {
}
// TotalSent is the mock TotalSent function of swap.
func (s *Service) TotalSent(peer swarm.Address) (totalSent uint64, err error) {
func (s *Service) TotalSent(peer swarm.Address) (totalSent *big.Int, err error) {
if s.settlementSentFunc != nil {
return s.settlementSentFunc(peer)
}
return 0, nil
if v, ok := s.settlementsSent[peer.String()]; ok {
return v, nil
}
return big.NewInt(0), nil
}
// TotalReceived is the mock TotalReceived function of swap.
func (s *Service) TotalReceived(peer swarm.Address) (totalReceived uint64, err error) {
func (s *Service) TotalReceived(peer swarm.Address) (totalReceived *big.Int, err error) {
if s.settlementRecvFunc != nil {
return s.settlementRecvFunc(peer)
}
return 0, nil
if v, ok := s.settlementsRecv[peer.String()]; ok {
return v, nil
}
return big.NewInt(0), nil
}
// SettlementsSent is the mock SettlementsSent function of swap.
func (s *Service) SettlementsSent() (map[string]uint64, error) {
func (s *Service) SettlementsSent() (map[string]*big.Int, error) {
if s.settlementsSentFunc != nil {
return s.settlementsSentFunc()
}
result := make(map[string]uint64)
return result, nil
return s.settlementsSent, nil
}
// SettlementsReceived is the mock SettlementsReceived function of swap.
func (s *Service) SettlementsReceived() (map[string]uint64, error) {
func (s *Service) SettlementsReceived() (map[string]*big.Int, error) {
if s.settlementsRecvFunc != nil {
return s.settlementsRecvFunc()
}
result := make(map[string]uint64)
return result, nil
return s.settlementsRecv, nil
}
// Handshake is called by the swap protocol when a handshake is received.
......
......@@ -102,11 +102,11 @@ func (s *Service) ReceiveCheque(ctx context.Context, peer swarm.Address, cheque
s.metrics.TotalReceived.Add(float64(amount.Uint64()))
return s.notifyPaymentFunc(peer, amount.Uint64())
return s.notifyPaymentFunc(peer, amount)
}
// Pay initiates a payment to the given peer
func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount uint64) error {
func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount *big.Int) error {
beneficiary, known, err := s.addressbook.Beneficiary(peer)
if err != nil {
return err
......@@ -119,7 +119,7 @@ func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount uint64) er
}
return ErrUnknownBeneficary
}
balance, err := s.chequebook.Issue(ctx, beneficiary, big.NewInt(int64(amount)), func(signedCheque *chequebook.SignedCheque) error {
balance, err := s.chequebook.Issue(ctx, beneficiary, amount, func(signedCheque *chequebook.SignedCheque) error {
return s.proto.EmitCheque(ctx, peer, signedCheque)
})
if err != nil {
......@@ -127,7 +127,8 @@ func (s *Service) Pay(ctx context.Context, peer swarm.Address, amount uint64) er
}
bal, _ := big.NewFloat(0).SetInt(balance).Float64()
s.metrics.AvailableBalance.Set(bal)
s.metrics.TotalSent.Add(float64(amount))
amountFloat, _ := big.NewFloat(0).SetInt(amount).Float64()
s.metrics.TotalSent.Add(amountFloat)
return nil
}
......@@ -137,47 +138,47 @@ func (s *Service) SetNotifyPaymentFunc(notifyPaymentFunc settlement.NotifyPaymen
}
// TotalSent returns the total amount sent to a peer
func (s *Service) TotalSent(peer swarm.Address) (totalSent uint64, err error) {
func (s *Service) TotalSent(peer swarm.Address) (totalSent *big.Int, err error) {
beneficiary, known, err := s.addressbook.Beneficiary(peer)
if err != nil {
return 0, err
return nil, err
}
if !known {
return 0, settlement.ErrPeerNoSettlements
return nil, settlement.ErrPeerNoSettlements
}
cheque, err := s.chequebook.LastCheque(beneficiary)
if err != nil {
if err == chequebook.ErrNoCheque {
return 0, settlement.ErrPeerNoSettlements
return nil, settlement.ErrPeerNoSettlements
}
return 0, err
return nil, err
}
return cheque.CumulativePayout.Uint64(), nil
return cheque.CumulativePayout, nil
}
// TotalReceived returns the total amount received from a peer
func (s *Service) TotalReceived(peer swarm.Address) (totalReceived uint64, err error) {
func (s *Service) TotalReceived(peer swarm.Address) (totalReceived *big.Int, err error) {
chequebookAddress, known, err := s.addressbook.Chequebook(peer)
if err != nil {
return 0, err
return nil, err
}
if !known {
return 0, settlement.ErrPeerNoSettlements
return nil, settlement.ErrPeerNoSettlements
}
cheque, err := s.chequeStore.LastCheque(chequebookAddress)
if err != nil {
if err == chequebook.ErrNoCheque {
return 0, settlement.ErrPeerNoSettlements
return nil, settlement.ErrPeerNoSettlements
}
return 0, err
return nil, err
}
return cheque.CumulativePayout.Uint64(), nil
return cheque.CumulativePayout, nil
}
// SettlementsSent returns sent settlements for each individual known peer
func (s *Service) SettlementsSent() (map[string]uint64, error) {
result := make(map[string]uint64)
func (s *Service) SettlementsSent() (map[string]*big.Int, error) {
result := make(map[string]*big.Int)
cheques, err := s.chequebook.LastCheques()
if err != nil {
return nil, err
......@@ -191,15 +192,15 @@ func (s *Service) SettlementsSent() (map[string]uint64, error) {
if !known {
continue
}
result[peer.String()] = cheque.CumulativePayout.Uint64()
result[peer.String()] = cheque.CumulativePayout
}
return result, nil
}
// SettlementsReceived returns received settlements for each individual known peer.
func (s *Service) SettlementsReceived() (map[string]uint64, error) {
result := make(map[string]uint64)
func (s *Service) SettlementsReceived() (map[string]*big.Int, error) {
result := make(map[string]*big.Int)
cheques, err := s.chequeStore.LastCheques()
if err != nil {
return nil, err
......@@ -213,7 +214,7 @@ func (s *Service) SettlementsReceived() (map[string]uint64, error) {
if !known {
continue
}
result[peer.String()] = cheque.CumulativePayout.Uint64()
result[peer.String()] = cheque.CumulativePayout
}
return result, err
}
......
......@@ -37,10 +37,10 @@ func (m *swapProtocolMock) EmitCheque(ctx context.Context, peer swarm.Address, c
type testObserver struct {
called bool
peer swarm.Address
amount uint64
amount *big.Int
}
func (t *testObserver) NotifyPayment(peer swarm.Address, amount uint64) error {
func (t *testObserver) NotifyPayment(peer swarm.Address, amount *big.Int) error {
t.called = true
t.peer = peer
t.amount = amount
......@@ -155,7 +155,7 @@ func TestReceiveCheque(t *testing.T) {
t.Fatal("expected observer to be called")
}
if observer.amount != amount.Uint64() {
if observer.amount.Cmp(amount) != 0 {
t.Fatalf("observer called with wrong amount. got %d, want %d", observer.amount, amount)
}
......@@ -278,7 +278,7 @@ func TestPay(t *testing.T) {
logger := logging.New(ioutil.Discard, 0)
store := mockstore.NewStateStore()
amount := uint64(50)
amount := big.NewInt(50)
beneficiary := common.HexToAddress("0xcd")
var cheque chequebook.SignedCheque
......@@ -289,7 +289,7 @@ func TestPay(t *testing.T) {
if b != beneficiary {
t.Fatalf("issuing cheque for wrong beneficiary. wanted %v, got %v", beneficiary, b)
}
if a.Uint64() != amount {
if a.Cmp(amount) != 0 {
t.Fatalf("issuing cheque with wrong amount. wanted %d, got %d", amount, a)
}
chequebookCalled = true
......@@ -349,7 +349,7 @@ func TestPayIssueError(t *testing.T) {
logger := logging.New(ioutil.Discard, 0)
store := mockstore.NewStateStore()
amount := uint64(50)
amount := big.NewInt(50)
beneficiary := common.HexToAddress("0xcd")
peer := swarm.MustParseHexAddress("abcd")
......@@ -392,7 +392,7 @@ func TestPayUnknownBeneficiary(t *testing.T) {
logger := logging.New(ioutil.Discard, 0)
store := mockstore.NewStateStore()
amount := uint64(50)
amount := big.NewInt(50)
peer := swarm.MustParseHexAddress("abcd")
networkID := uint64(1)
addressbook := &addressbookMock{
......
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