diff --git a/api/config.go b/api/config.go index 354b12e076..8c1c31fe1d 100644 --- a/api/config.go +++ b/api/config.go @@ -32,6 +32,7 @@ import ( "github.com/ethersphere/swarm/pss" "github.com/ethersphere/swarm/storage" "github.com/ethersphere/swarm/swap" + "github.com/ethersphere/swarm/swap/int256" ) const ( @@ -52,16 +53,16 @@ type Config struct { BaseKey []byte // Swap configs - SwapBackendURL string // Ethereum API endpoint - SwapEnabled bool // whether SWAP incentives are enabled - SwapPaymentThreshold uint64 // honey amount at which a payment is triggered - SwapDisconnectThreshold uint64 // honey amount at which a peer disconnects - SwapSkipDeposit bool // do not ask the user to deposit during boot sequence - SwapDepositAmount uint64 // deposit amount to the chequebook - SwapLogPath string // dir to swap related audit logs - SwapLogLevel int // log level of swap related audit logs - Contract common.Address // address of the chequebook contract - SwapChequebookFactory common.Address // address of the chequebook factory contract + SwapBackendURL string // Ethereum API endpoint + SwapEnabled bool // whether SWAP incentives are enabled + SwapPaymentThreshold *int256.Uint256 // honey amount at which a payment is triggered + SwapDisconnectThreshold *int256.Uint256 // honey amount at which a peer disconnects + SwapSkipDeposit bool // do not ask the user to deposit during boot sequence + SwapDepositAmount uint64 // deposit amount to the chequebook + SwapLogPath string // dir to swap related audit logs + SwapLogLevel int // log level of swap related audit logs + Contract common.Address // address of the chequebook contract + SwapChequebookFactory common.Address // address of the chequebook factory contract // end of Swap configs *network.HiveParams diff --git a/cmd/swarm/config.go b/cmd/swarm/config.go index 92d990c4f2..e80c57633b 100644 --- a/cmd/swarm/config.go +++ b/cmd/swarm/config.go @@ -36,6 +36,7 @@ import ( bzzapi "github.com/ethersphere/swarm/api" "github.com/ethersphere/swarm/network" + "github.com/ethersphere/swarm/swap/int256" ) var ( @@ -223,10 +224,10 @@ func flagsOverride(currentConfig *bzzapi.Config, ctx *cli.Context) *bzzapi.Confi currentConfig.SwapDepositAmount = deposit } if paymentThreshold := ctx.GlobalUint64(SwarmSwapPaymentThresholdFlag.Name); paymentThreshold != 0 { - currentConfig.SwapPaymentThreshold = paymentThreshold + currentConfig.SwapPaymentThreshold = int256.Uint256From(paymentThreshold) } if disconnectThreshold := ctx.GlobalUint64(SwarmSwapDisconnectThresholdFlag.Name); disconnectThreshold != 0 { - currentConfig.SwapDisconnectThreshold = disconnectThreshold + currentConfig.SwapDisconnectThreshold = int256.Uint256From(disconnectThreshold) } if ctx.GlobalIsSet(SwarmNoSyncFlag.Name) { val := !ctx.GlobalBool(SwarmNoSyncFlag.Name) diff --git a/cmd/swarm/config_test.go b/cmd/swarm/config_test.go index 28dd14177b..fe0b19c08a 100644 --- a/cmd/swarm/config_test.go +++ b/cmd/swarm/config_test.go @@ -24,7 +24,6 @@ import ( "net" "os" "os/exec" - "strconv" "testing" "time" @@ -36,6 +35,7 @@ import ( "github.com/ethersphere/swarm" "github.com/ethersphere/swarm/api" "github.com/ethersphere/swarm/swap" + "github.com/ethersphere/swarm/swap/int256" "github.com/ethersphere/swarm/testutil" ) @@ -227,6 +227,20 @@ func TestConfigCmdLineOverrides(t *testing.T) { t.Fatal(err) } + // add 1 to payment threshold + paymentThresholdOverride, err := new(int256.Uint256).Add(swap.DefaultPaymentThreshold, int256.Uint256From(1)) + if err != nil { + t.Fatal(err) + } + paymentThreshold := paymentThresholdOverride.Value() + + // add 1 to disconnect threshold + disconnectThresholdOverride, err := new(int256.Uint256).Add(swap.DefaultDisconnectThreshold, int256.Uint256From(1)) + if err != nil { + t.Fatal(err) + } + disconnectThreshold := disconnectThresholdOverride.Value() + flags := []string{ fmt.Sprintf("--%s", SwarmNetworkIdFlag.Name), "42", fmt.Sprintf("--%s", SwarmPortFlag.Name), httpPort, @@ -238,8 +252,8 @@ func TestConfigCmdLineOverrides(t *testing.T) { fmt.Sprintf("--%s", utils.DataDirFlag.Name), dir, fmt.Sprintf("--%s", utils.IPCPathFlag.Name), conf.IPCPath, "--verbosity", fmt.Sprintf("%d", *testutil.Loglevel), - fmt.Sprintf("--%s", SwarmSwapPaymentThresholdFlag.Name), strconv.FormatUint(swap.DefaultPaymentThreshold+1, 10), - fmt.Sprintf("--%s", SwarmSwapDisconnectThresholdFlag.Name), strconv.FormatUint(swap.DefaultDisconnectThreshold+1, 10), + fmt.Sprintf("--%s", SwarmSwapPaymentThresholdFlag.Name), paymentThreshold.String(), + fmt.Sprintf("--%s", SwarmSwapDisconnectThresholdFlag.Name), disconnectThreshold.String(), fmt.Sprintf("--%s", SwarmEnablePinningFlag.Name), } @@ -287,12 +301,12 @@ func TestConfigCmdLineOverrides(t *testing.T) { t.Fatalf("Expected Cors flag to be set to %s, got %s", "*", info.Cors) } - if info.SwapPaymentThreshold != (swap.DefaultPaymentThreshold + 1) { - t.Fatalf("Expected SwapPaymentThreshold to be %d, but got %d", swap.DefaultPaymentThreshold+1, info.SwapPaymentThreshold) + if !info.SwapPaymentThreshold.Equals(paymentThresholdOverride) { + t.Fatalf("Expected SwapPaymentThreshold to be %v, but got %v", paymentThresholdOverride, info.SwapPaymentThreshold) } - if info.SwapDisconnectThreshold != (swap.DefaultDisconnectThreshold + 1) { - t.Fatalf("Expected SwapDisconnectThreshold to be %d, but got %d", swap.DefaultDisconnectThreshold+1, info.SwapDisconnectThreshold) + if !info.SwapDisconnectThreshold.Equals(disconnectThresholdOverride) { + t.Fatalf("Expected SwapDisconnectThreshold to be %v, but got %v", disconnectThresholdOverride, info.SwapDisconnectThreshold) } if info.EnablePinning != true { diff --git a/swap/api.go b/swap/api.go index bb864cfd74..2a11fc0b09 100644 --- a/swap/api.go +++ b/swap/api.go @@ -26,8 +26,8 @@ func (s *Swap) APIs() []rpc.API { type swapAPI interface { AvailableBalance() (*int256.Uint256, error) - PeerBalance(peer enode.ID) (int64, error) - Balances() (map[enode.ID]int64, error) + PeerBalance(peer enode.ID) (*int256.Int256, error) + Balances() (map[enode.ID]*int256.Int256, error) PeerCheques(peer enode.ID) (PeerCheques, error) Cheques() (map[enode.ID]*PeerCheques, error) } @@ -95,7 +95,7 @@ func (s *Swap) AvailableBalance() (*int256.Uint256, error) { } // PeerBalance returns the balance for a given peer -func (s *Swap) PeerBalance(peer enode.ID) (balance int64, err error) { +func (s *Swap) PeerBalance(peer enode.ID) (balance *int256.Int256, err error) { if swapPeer := s.getPeer(peer); swapPeer != nil { swapPeer.lock.Lock() defer swapPeer.lock.Unlock() @@ -106,8 +106,8 @@ func (s *Swap) PeerBalance(peer enode.ID) (balance int64, err error) { } // Balances returns the balances for all known SWAP peers -func (s *Swap) Balances() (map[enode.ID]int64, error) { - balances := make(map[enode.ID]int64) +func (s *Swap) Balances() (map[enode.ID]*int256.Int256, error) { + balances := make(map[enode.ID]*int256.Int256) s.peersLock.Lock() for peer, swapPeer := range s.peers { @@ -121,7 +121,7 @@ func (s *Swap) Balances() (map[enode.ID]int64, error) { balanceIterFunction := func(key []byte, value []byte) (stop bool, err error) { peer := keyToID(string(key), balancePrefix) if _, peerHasBalance := balances[peer]; !peerHasBalance { - var peerBalance int64 + var peerBalance *int256.Int256 err = json.Unmarshal(value, &peerBalance) if err == nil { balances[peer] = peerBalance diff --git a/swap/api_test.go b/swap/api_test.go index 0bd51ced71..28708fceec 100644 --- a/swap/api_test.go +++ b/swap/api_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/simulations/adapters" "github.com/ethersphere/swarm/p2p/protocols" "github.com/ethersphere/swarm/state" + "github.com/ethersphere/swarm/swap/int256" ) type peerChequesTestCase struct { @@ -40,19 +41,19 @@ func TestPeerBalance(t *testing.T) { defer clean() // test balance - setBalance(t, testPeer, 888) - testPeerBalance(t, swap, testPeerID, 888) + setBalance(t, testPeer, int256.Int256From(888)) + testPeerBalance(t, swap, testPeerID, int256.Int256From(888)) // test balance after change - setBalance(t, testPeer, 17000) - testPeerBalance(t, swap, testPeerID, 17000) + setBalance(t, testPeer, int256.Int256From(17000)) + testPeerBalance(t, swap, testPeerID, int256.Int256From(17000)) // test balance for second peer testPeer2 := addPeer(t, swap) testPeer2ID := testPeer2.ID() - setBalance(t, testPeer2, 4) - testPeerBalance(t, swap, testPeer2ID, 4) + setBalance(t, testPeer2, int256.Int256From(4)) + testPeerBalance(t, swap, testPeer2ID, int256.Int256From(4)) // test balance for inexistent node invalidPeerID := adapters.RandomNodeConfig().ID @@ -67,23 +68,23 @@ func TestPeerBalance(t *testing.T) { // test balance for disconnected node testPeer3 := newDummyPeer().Peer testPeer3ID := testPeer3.ID() - err = swap.saveBalance(testPeer3ID, 777) - testPeerBalance(t, swap, testPeer3ID, 777) + err = swap.saveBalance(testPeer3ID, int256.Int256From(777)) + testPeerBalance(t, swap, testPeer3ID, int256.Int256From(777)) // test previous results are still correct - testPeerBalance(t, swap, testPeerID, 17000) - testPeerBalance(t, swap, testPeer2ID, 4) + testPeerBalance(t, swap, testPeerID, int256.Int256From(17000)) + testPeerBalance(t, swap, testPeer2ID, int256.Int256From(4)) } // tests that expected balance for peer matches the result of the Balance function -func testPeerBalance(t *testing.T, s *Swap, id enode.ID, expectedBalance int64) { +func testPeerBalance(t *testing.T, s *Swap, id enode.ID, expectedBalance *int256.Int256) { t.Helper() b, err := s.PeerBalance(id) if err != nil { t.Fatal(err) } - if b != expectedBalance { - t.Fatalf("Expected peer's balance to be %d, but is %d", expectedBalance, b) + if !b.Equals(expectedBalance) { + t.Fatalf("Expected peer's balance to be %v, but is %v", expectedBalance, b) } } @@ -97,7 +98,7 @@ func addPeer(t *testing.T, s *Swap) *Peer { } // sets the given balance for the given peer, fails if there are errors -func setBalance(t *testing.T, p *Peer, balance int64) { +func setBalance(t *testing.T, p *Peer, balance *int256.Int256) { t.Helper() err := p.setBalance(balance) if err != nil { @@ -112,38 +113,42 @@ func TestBalances(t *testing.T) { defer clean() // test balances are empty - testBalances(t, swap, map[enode.ID]int64{}) + testBalances(t, swap, map[enode.ID]*int256.Int256{}) // add peer testPeer := addPeer(t, swap) testPeerID := testPeer.ID() // test balances with one peer - setBalance(t, testPeer, 808) - testBalances(t, swap, map[enode.ID]int64{testPeerID: 808}) + balancePeer := int256.Int256From(808) + setBalance(t, testPeer, int256.Int256From(808)) + testBalances(t, swap, map[enode.ID]*int256.Int256{testPeerID: balancePeer}) // add second peer testPeer2 := addPeer(t, swap) testPeer2ID := testPeer2.ID() // test balances with second peer - setBalance(t, testPeer2, 123) - testBalances(t, swap, map[enode.ID]int64{testPeerID: 808, testPeer2ID: 123}) + balancePeer2 := int256.Int256From(123) + setBalance(t, testPeer2, int256.Int256From(123)) + testBalances(t, swap, map[enode.ID]*int256.Int256{testPeerID: balancePeer, testPeer2ID: balancePeer2}) // test balances after balance change for peer - setBalance(t, testPeer, 303) - testBalances(t, swap, map[enode.ID]int64{testPeerID: 303, testPeer2ID: 123}) + balancePeer = int256.Int256From(303) + balancePeer2 = int256.Int256From(123) + setBalance(t, testPeer, int256.Int256From(303)) + testBalances(t, swap, map[enode.ID]*int256.Int256{testPeerID: balancePeer, testPeer2ID: balancePeer2}) } // tests that a map of peerID:balance matches the result of the Balances function -func testBalances(t *testing.T, s *Swap, expectedBalances map[enode.ID]int64) { +func testBalances(t *testing.T, s *Swap, expectedBalances map[enode.ID]*int256.Int256) { t.Helper() actualBalances, err := s.Balances() if err != nil { t.Fatal(err) } if !reflect.DeepEqual(actualBalances, expectedBalances) { - t.Fatalf("Expected node's balances to be %d, but are %d", expectedBalances, actualBalances) + t.Fatalf("Expected node's balances to be %v, but are %v", expectedBalances, actualBalances) } } diff --git a/swap/common_test.go b/swap/common_test.go index ef3a36f3bc..20e655007c 100644 --- a/swap/common_test.go +++ b/swap/common_test.go @@ -83,8 +83,8 @@ func newDefaultParams(t *testing.T) *Params { BaseAddrs: network.NewBzzAddr(baseKey, nil), LogPath: emptyLogPath, LogLevel: DefaultSwapLogLevel, //Info level - PaymentThreshold: int64(DefaultPaymentThreshold), - DisconnectThreshold: int64(DefaultDisconnectThreshold), + PaymentThreshold: DefaultPaymentThreshold, + DisconnectThreshold: DefaultDisconnectThreshold, } } diff --git a/swap/config.go b/swap/config.go index ee66e8ad25..a32b126f5e 100644 --- a/swap/config.go +++ b/swap/config.go @@ -18,6 +18,8 @@ package swap import ( "time" + + "github.com/ethersphere/swarm/swap/int256" ) // These are currently arbitrary values which have not been verified nor tested @@ -25,11 +27,11 @@ import ( const ( // Thresholds which trigger payment or disconnection. The unit is in honey (internal accounting unit) // DefaultPaymentThreshold is set to be equivalent to requesting and serving 10mb of data (2441 chunks (4096 bytes) = 10 mb, 10^7 bytes = 10 mb) - DefaultPaymentThreshold = 2441*RetrieveRequestPrice + (10^7)*ChunkDeliveryPrice // 4096 * 2441 = 10 mb, - DefaultDisconnectThreshold = 20 * DefaultPaymentThreshold + defaultPaymentThreshold = 2441*RetrieveRequestPrice + (10^7)*ChunkDeliveryPrice // 4096 * 2441 = 10 mb, + defaultDisconnectThreshold = 20 * defaultPaymentThreshold // ChequeDebtTolerance is the lowest resulting balance a node is willing to accept when receiving a cheque // the value is meant to be used below 0, as positive resulting balances should always be accepted when receiving cheques - ChequeDebtTolerance = DefaultPaymentThreshold * 20 / 100 // roughly 20% of the payment threshold + ChequeDebtTolerance = defaultPaymentThreshold * 20 / 100 // roughly 20% of the payment threshold // DefaultDepositAmount is the default amount to send to the contract when initially deploying // NOTE: deliberate value for now; needs experimentation DefaultDepositAmount = 0 @@ -40,3 +42,6 @@ const ( AllowedNetworkID = 5 DefaultTransactionTimeout = 10 * time.Minute ) + +var DefaultPaymentThreshold = int256.Uint256From(defaultPaymentThreshold) +var DefaultDisconnectThreshold = int256.Uint256From(defaultDisconnectThreshold) diff --git a/swap/int256/int256.go b/swap/int256/int256.go index 1f3acff987..1199676723 100644 --- a/swap/int256/int256.go +++ b/swap/int256/int256.go @@ -30,6 +30,11 @@ type Int256 struct { value *big.Int } +// BigIntWrapper represents a struct with an underlying big.Int value +type BigIntWrapper interface { + Value() *big.Int +} + var minInt256 = new(big.Int).Mul(big.NewInt(-1), new(big.Int).Exp(big.NewInt(2), big.NewInt(255), nil)) // -(2^255) var maxInt256 = new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(255), nil), big.NewInt(1)) // 2^255 - 1 @@ -57,6 +62,10 @@ func (u *Int256) Copy() *Int256 { // Value returns the underlying private value for a Int256 struct func (u *Int256) Value() *big.Int { + if u.value == nil { + return nil + } + // clone the value to avoid external modification return new(big.Int).Set(u.value) } @@ -110,13 +119,13 @@ func (u *Int256) Mul(multiplicand, multiplier *Int256) (*Int256, error) { } // cmp calls the underlying Cmp method for the big.Int stored in a Int256 struct as its value field -func (u *Int256) cmp(v *Int256) int { - return u.value.Cmp(v.value) +func (u *Int256) Cmp(v BigIntWrapper) int { + return u.value.Cmp(v.Value()) } // Equals returns true if the two Int256 structs have the same underlying values, false otherwise -func (u *Int256) Equals(v *Int256) bool { - return u.cmp(v) == 0 +func (u *Int256) Equals(v BigIntWrapper) bool { + return u.Cmp(v) == 0 } // String returns the string representation for Int256 structs diff --git a/swap/int256/uint256.go b/swap/int256/uint256.go index d341c6b6dd..ed79cefa12 100644 --- a/swap/int256/uint256.go +++ b/swap/int256/uint256.go @@ -57,6 +57,10 @@ func (u *Uint256) Copy() *Uint256 { // Value returns the underlying private value for a Uint256 struct func (u *Uint256) Value() *big.Int { + if u.value == nil { + return nil + } + // clone the value to avoid external modification return new(big.Int).Set(u.value) } @@ -110,12 +114,12 @@ func (u *Uint256) Mul(multiplicand, multiplier *Uint256) (*Uint256, error) { } // Cmp calls the underlying Cmp method for the big.Int stored in a Uint256 struct as its value field -func (u *Uint256) Cmp(v *Uint256) int { - return u.value.Cmp(v.value) +func (u *Uint256) Cmp(v BigIntWrapper) int { + return u.value.Cmp(v.Value()) } // Equals returns true if the two Uint256 structs have the same underlying values, false otherwise -func (u *Uint256) Equals(v *Uint256) bool { +func (u *Uint256) Equals(v BigIntWrapper) bool { return u.Cmp(v) == 0 } diff --git a/swap/peer.go b/swap/peer.go index 5614a36da8..f09766caa6 100644 --- a/swap/peer.go +++ b/swap/peer.go @@ -20,7 +20,7 @@ import ( "context" "errors" "fmt" - "strconv" + "math/big" "sync" "github.com/ethereum/go-ethereum/common" @@ -42,7 +42,7 @@ type Peer struct { lastReceivedCheque *Cheque // last cheque we received from the peer lastSentCheque *Cheque // last cheque that was sent to peer that was confirmed pendingCheque *Cheque // last cheque that was sent to peer but is not yet confirmed - balance int64 // current balance of the peer + balance *int256.Int256 // current balance of the peer logger Logger // logger for swap related messages and audit trail with peer identifier } @@ -125,26 +125,29 @@ func (p *Peer) getLastSentCumulativePayout() *int256.Uint256 { } // the caller is expected to hold p.lock -func (p *Peer) setBalance(balance int64) error { +func (p *Peer) setBalance(balance *int256.Int256) error { p.balance = balance return p.swap.saveBalance(p.ID(), balance) } // getBalance returns the current balance for this peer // the caller is expected to hold p.lock -func (p *Peer) getBalance() int64 { +func (p *Peer) getBalance() *int256.Int256 { return p.balance } // the caller is expected to hold p.lock -func (p *Peer) updateBalance(amount int64) error { +func (p *Peer) updateBalance(amount *int256.Int256) error { //adjust the balance //if amount is negative, it will decrease, otherwise increase - newBalance := p.getBalance() + amount + newBalance, err := new(int256.Int256).Add(p.getBalance(), amount) + if err != nil { + return err + } if err := p.setBalance(newBalance); err != nil { return err } - p.logger.Debug(UpdateBalanceAction, "balance", strconv.FormatInt(newBalance, 10)) + p.logger.Debug(UpdateBalanceAction, "balance", newBalance) return nil } @@ -156,11 +159,13 @@ func (p *Peer) createCheque() (*Cheque, error) { var cheque *Cheque var err error - if p.getBalance() >= 0 { - return nil, fmt.Errorf("expected negative balance, found: %d", p.getBalance()) + if p.getBalance().Cmp(int256.Int256From(0)) >= 0 { + return nil, fmt.Errorf("expected negative balance, found: %v", p.getBalance()) } // the balance should be negative here, we take the absolute value: - honey := uint64(-p.getBalance()) + b := p.getBalance().Value() + balance := new(big.Int).Mul(b, big.NewInt(-1)) + honey := balance.Uint64() oraclePrice, err := p.swap.honeyPriceOracle.GetPrice(honey) if err != nil { @@ -208,14 +213,14 @@ func (p *Peer) sendCheque() error { return fmt.Errorf("error while saving pending cheque: %v", err) } - honeyAmount := int64(cheque.Honey) + honeyAmount := int256.Int256From(int64(cheque.Honey)) err = p.updateBalance(honeyAmount) if err != nil { return fmt.Errorf("error while updating balance: %v", err) } metrics.GetOrRegisterCounter("swap/cheques/emitted/num", nil).Inc(1) - metrics.GetOrRegisterCounter("swap/cheques/emitted/honey", nil).Inc(honeyAmount) + metrics.GetOrRegisterCounter("swap/cheques/emitted/honey", nil).Inc(int64(cheque.Honey)) p.logger.Info(SendChequeAction, "sending cheque to peer", "cheque", cheque) return p.Send(context.Background(), &EmitChequeMsg{ Cheque: cheque, diff --git a/swap/protocol_test.go b/swap/protocol_test.go index fa101d61ae..b191e9a83c 100644 --- a/swap/protocol_test.go +++ b/swap/protocol_test.go @@ -259,7 +259,7 @@ func TestEmitCheque(t *testing.T) { debitor := creditorSwap.getPeer(protocolTester.Nodes[0].ID()) // set balance artificially - if err = debitor.setBalance(balanceValue.Int64()); err != nil { + if err = debitor.setBalance(int256.Int256From(100001)); err != nil { t.Fatal(err) } @@ -306,8 +306,8 @@ func TestEmitCheque(t *testing.T) { } // check that the balance has been reset - if debitor.getBalance() != 0 { - t.Fatalf("Expected debitor balance to have been reset to %d, but it is %d", 0, debitor.getBalance()) + if !debitor.getBalance().Equals(int256.Int256From(0)) { + t.Fatalf("Expected debitor balance to have been reset to %d, but it is %v", 0, debitor.getBalance()) } recvCheque := debitor.getLastReceivedCheque() log.Debug("expected cheque", "cheque", recvCheque) @@ -331,7 +331,12 @@ func TestEmitCheque(t *testing.T) { func TestTriggerPaymentThreshold(t *testing.T) { testBackend := newTestBackend(t) log.Debug("create test swap") - protocolTester, clean, err := newSwapTester(t, testBackend, int256.Uint256From(DefaultPaymentThreshold*2)) + depositAmount, err := new(int256.Uint256).Mul(DefaultPaymentThreshold, int256.Uint256From(2)) + if err != nil { + t.Fatal(err) + } + + protocolTester, clean, err := newSwapTester(t, testBackend, depositAmount) defer clean() if err != nil { t.Fatal(err) @@ -354,9 +359,23 @@ func TestTriggerPaymentThreshold(t *testing.T) { creditor := debitorSwap.getPeer(protocolTester.Nodes[0].ID()) // set the balance to manually be at PaymentThreshold - overDraft := 42 - expectedAmount := uint64(overDraft) + DefaultPaymentThreshold - if err = creditor.setBalance(-int64(DefaultPaymentThreshold)); err != nil { + overDraft := int256.Uint256From(42) + expectedAmount, err := new(int256.Uint256).Add(overDraft, DefaultPaymentThreshold) + if err != nil { + t.Fatal(err) + } + + // transform Uint256 to Int256 + newBalance, err := int256.NewInt256(DefaultPaymentThreshold.Value()) + if err != nil { + t.Fatal(err) + } + _, err = newBalance.Mul(newBalance, int256.Int256From(-1)) + if err != nil { + t.Fatal(err) + } + + if err = creditor.setBalance(newBalance); err != nil { t.Fatal(err) } @@ -365,14 +384,14 @@ func TestTriggerPaymentThreshold(t *testing.T) { t.Fatalf("Expected no cheques yet, but there is %v:", creditor.getLastSentCheque()) } // do some accounting, no error expected, just a WARN - err = debitorSwap.Add(int64(-overDraft), creditor.Peer) + err = debitorSwap.Add(-42, creditor.Peer) if err != nil { t.Fatal(err) } // balance should be reset now - if creditor.getBalance() != 0 { - t.Fatalf("Expected debitorSwap balance to be 0, but is %d", creditor.getBalance()) + if !creditor.getBalance().Equals(int256.Int256From(0)) { + t.Fatalf("Expected debitorSwap balance to be 0, but is %v", creditor.getBalance()) } // pending cheque should now be set @@ -381,12 +400,13 @@ func TestTriggerPaymentThreshold(t *testing.T) { t.Fatal("Expected pending cheque") } - if !pending.CumulativePayout.Equals(int256.Uint256From(expectedAmount)) { - t.Fatalf("Expected cheque cumulative payout to be %d, but is %v", expectedAmount, pending.CumulativePayout) + if !pending.CumulativePayout.Equals(expectedAmount) { + t.Fatalf("Expected cheque cumulative payout to be %v, but is %v", expectedAmount, pending.CumulativePayout) } - if pending.Honey != expectedAmount { - t.Fatalf("Expected cheque honey to be %d, but is %d", expectedAmount, pending.Honey) + ea := expectedAmount.Value() + if pending.Honey != ea.Uint64() { + t.Fatalf("Expected cheque honey to be %v, but is %v", expectedAmount, pending.Honey) } if pending.Beneficiary != creditor.beneficiary { @@ -447,12 +467,13 @@ loop: } // because no other accounting took place in the meantime the balance should be exactly 0 - if creditor.getBalance() != 0 { - t.Fatalf("Expected debitorSwap balance to be 0, but is %d", creditor.getBalance()) + if !creditor.getBalance().Equals(int256.Int256From(0)) { + t.Fatalf("Expected debitorSwap balance to be 0, but is %v", creditor.getBalance()) } // do some accounting again to trigger a second cheque - if err = debitorSwap.Add(-int64(DefaultPaymentThreshold), creditor.Peer); err != nil { + amount := DefaultPaymentThreshold.Value() + if err = debitorSwap.Add(-(amount.Int64()), creditor.Peer); err != nil { t.Fatal(err) } @@ -472,8 +493,8 @@ loop: t.Fatal(err) } - if creditor.getBalance() != 0 { - t.Fatalf("Expected debitorSwap balance to be 0, but is %d", creditor.getBalance()) + if !creditor.getBalance().Equals(int256.Int256From(0)) { + t.Fatalf("Expected debitorSwap balance to be 0, but is %v", creditor.getBalance()) } } @@ -494,7 +515,11 @@ func TestTriggerDisconnectThreshold(t *testing.T) { // set the balance to manually be at DisconnectThreshold overDraft := 42 - expectedBalance := int64(DefaultDisconnectThreshold) + // transform Uint256 to Int256 + expectedBalance, err := int256.NewInt256((DefaultDisconnectThreshold).Value()) + if err != nil { + t.Fatal(err) + } // we don't expect any change after the test if err = debitor.setBalance(expectedBalance); err != nil { t.Fatal(err) @@ -511,7 +536,7 @@ func TestTriggerDisconnectThreshold(t *testing.T) { } // no balance change expected if debitor.getBalance() != expectedBalance { - t.Fatalf("Expected balance to be %d, but is %d", expectedBalance, debitor.getBalance()) + t.Fatalf("Expected balance to be %v, but is %v", expectedBalance, debitor.getBalance()) } // still no cheques expected if debitor.getPendingCheque() != nil { @@ -525,7 +550,7 @@ func TestTriggerDisconnectThreshold(t *testing.T) { } if debitor.getBalance() != expectedBalance { - t.Fatalf("Expected balance to be %d, but is %d", expectedBalance, debitor.getBalance()) + t.Fatalf("Expected balance to be %v, but is %v", expectedBalance, debitor.getBalance()) } if debitor.getPendingCheque() != nil { @@ -577,21 +602,21 @@ func TestSwapRPC(t *testing.T) { id2 := dummyPeer2.ID() // set some fake balances - fakeBalance1 := int64(234) - fakeBalance2 := int64(-100) + fakeBalance1 := int256.Int256From(234) + fakeBalance2 := int256.Int256From(-100) // query a first time, should give error - var balance int64 - err = rpcclient.Call(&balance, "swap_peerBalance", id1) + balance := new(int256.Int256) + err = rpcclient.Call(balance, "swap_peerBalance", id1) // at this point no balance should be there: no peer registered with Swap if err == nil { t.Fatal("Expected error but no error received") } log.Debug("servicenode balance", "balance", balance) - // ...thus balance should be zero - if balance != 0 { - t.Fatalf("Expected balance to be 0 but it is %d", balance) + // ...thus balance should be empty + if balance.Value() != nil { + t.Fatalf("Expected balance to be empty but it is %v", balance) } peer1, err := swap.addPeer(dummyPeer1.Peer, common.Address{}, common.Address{}) @@ -613,40 +638,43 @@ func TestSwapRPC(t *testing.T) { } // query them, values should coincide - err = rpcclient.Call(&balance, "swap_peerBalance", id1) + err = rpcclient.Call(balance, "swap_peerBalance", id1) if err != nil { t.Fatal(err) } log.Debug("balance1", "balance1", balance) - if balance != fakeBalance1 { - t.Fatalf("Expected balance %d to be equal to fake balance %d, but it is not", balance, fakeBalance1) + if !balance.Equals(fakeBalance1) { + t.Fatalf("Expected balance %v to be equal to fake balance %v, but it is not", balance, fakeBalance1) } - err = rpcclient.Call(&balance, "swap_peerBalance", id2) + err = rpcclient.Call(balance, "swap_peerBalance", id2) if err != nil { t.Fatal(err) } log.Debug("balance2", "balance2", balance) - if balance != fakeBalance2 { - t.Fatalf("Expected balance %d to be equal to fake balance %d, but it is not", balance, fakeBalance2) + if !balance.Equals(fakeBalance2) { + t.Fatalf("Expected balance %v to be equal to fake balance %v, but it is not", balance, fakeBalance2) } // now call all balances - allBalances := make(map[enode.ID]int64) + allBalances := make(map[enode.ID]*int256.Int256) err = rpcclient.Call(&allBalances, "swap_balances") if err != nil { t.Fatal(err) } log.Debug("received balances", "allBalances", allBalances) - var sum int64 + sum := int256.Int256From(0) for _, v := range allBalances { - sum += v + sum.Add(sum, v) } - fakeSum := fakeBalance1 + fakeBalance2 - if sum != fakeSum { - t.Fatalf("Expected total balance to be %d, but it %d", fakeSum, sum) + fakeSum, err := new(int256.Int256).Add(fakeBalance1, fakeBalance2) + if err != nil { + t.Fatal(err) + } + if !sum.Equals(fakeSum) { + t.Fatalf("Expected total balance to be %v, but it %v", fakeSum, sum) } balances, err := swap.Balances() diff --git a/swap/simulations_test.go b/swap/simulations_test.go index 9787771290..ca0f9de173 100644 --- a/swap/simulations_test.go +++ b/swap/simulations_test.go @@ -107,9 +107,12 @@ func (m *testMsgByReceiver) Price() *protocols.Price { } } +var paymentThreshold = DefaultPaymentThreshold.Value() +var paymentThresholdPrice = paymentThreshold.Uint64() + func (m *testMsgSmallPrice) Price() *protocols.Price { return &protocols.Price{ - Value: DefaultPaymentThreshold / 100, // ensures that the message won't put nodes into debt + Value: paymentThresholdPrice / 100, // ensures that the message won't put nodes into debt PerByte: false, Payer: protocols.Sender, } @@ -339,9 +342,10 @@ func TestMultiChequeSimulation(t *testing.T) { } paymentThreshold := debitorSvc.swap.params.PaymentThreshold + pt := paymentThreshold.Value() chequesAmount := 4 - msgsPerCheque := (uint64(paymentThreshold) / msgPrice) + 1 // +1 to round up without casting to float + msgsPerCheque := (pt.Uint64() / msgPrice) + 1 // +1 to round up without casting to float msgAmount := int(msgsPerCheque) * chequesAmount log.Debug("sending %d messages", msgAmount) @@ -381,14 +385,31 @@ func TestMultiChequeSimulation(t *testing.T) { t.Fatal(err) } + mp := new(big.Int).SetUint64(msgPrice) + price, err := int256.NewInt256(mp) + if err != nil { + t.Fatal(err) + } + // check if cheque should have been sent - balanceAfterMessage := debitorBalance - int64(msgPrice) - if balanceAfterMessage <= -paymentThreshold { + balanceAfterMessage, err := new(int256.Int256).Sub(debitorBalance, price) + if err != nil { + t.Fatal(err) + } + + threshold, err := int256.NewInt256(paymentThreshold.Value()) + if err != nil { + t.Fatal(err) + } + + pt, err := new(int256.Int256).Mul(threshold, int256.Int256From(-1)) + if balanceAfterMessage.Cmp(pt) <= 0 { // we need to wait a bit in order to give time for the cheque to be processed if err := waitForChequeProcessed(t, params.backend, counter, lastCount, debitorSvc.swap.peers[creditor], expectedPayout); err != nil { t.Fatal(err) } - expectedPayout += uint64(-balanceAfterMessage) + b := balanceAfterMessage.Value() + expectedPayout += b.Uint64() } lastCount++ @@ -411,8 +432,13 @@ func TestMultiChequeSimulation(t *testing.T) { t.Fatal(err) } - if b1 != -b2 { - t.Fatalf("Expected symmetric balances, but they are not: %d vs %d", b1, b2) + b2, err = new(int256.Int256).Mul(b2, int256.Int256From(-1)) + if err != nil { + t.Fatal(err) + } + + if !b1.Equals(b2) { + t.Fatalf("Expected symmetric balances, but they are not: %v vs %v", b1, b2) } // check cheques var cheque1, cheque2 *Cheque @@ -603,8 +629,12 @@ func TestBasicSwapSimulation(t *testing.T) { if err != nil { return fmt.Errorf("expected counter balance for node %v to be found, but not found", node) } - if nodeBalanceWithP != -pBalanceWithNode { - return fmt.Errorf("Expected symmetric balances, but they are not: %d vs %d", nodeBalanceWithP, pBalanceWithNode) + pBalanceWithNode, err = new(int256.Int256).Mul(pBalanceWithNode, int256.Int256From(-1)) + if err != nil { + return err + } + if !nodeBalanceWithP.Equals(pBalanceWithNode) { + return fmt.Errorf("Expected symmetric balances, but they are not: %v vs %v", nodeBalanceWithP, pBalanceWithNode) } } } diff --git a/swap/swap.go b/swap/swap.go index 913a432252..9550851240 100644 --- a/swap/swap.go +++ b/swap/swap.go @@ -79,8 +79,8 @@ type Params struct { BaseAddrs *network.BzzAddr // this node's base address LogPath string // optional audit log path LogLevel int // optional indicates audit filter level of swap log messages - PaymentThreshold int64 // honey amount at which a payment is triggered - DisconnectThreshold int64 // honey amount at which a peer disconnects + PaymentThreshold *int256.Uint256 // honey amount at which a payment is triggered + DisconnectThreshold *int256.Uint256 // honey amount at which a peer disconnects } // newSwapInstance is a swap constructor function without integrity checks @@ -122,8 +122,8 @@ func New(dbPath string, prvkey *ecdsa.PrivateKey, backendURL string, params *Par if stateStore, err = state.NewDBStore(filepath.Join(dbPath, "swap.db")); err != nil { return nil, fmt.Errorf("initializing statestore: %w", err) } - if params.DisconnectThreshold <= params.PaymentThreshold { - return nil, fmt.Errorf("disconnect threshold lower or at payment threshold. DisconnectThreshold: %d, PaymentThreshold: %d", params.DisconnectThreshold, params.PaymentThreshold) + if params.DisconnectThreshold.Cmp(params.PaymentThreshold) < 1 { + return nil, fmt.Errorf("disconnect threshold lower or at payment threshold. DisconnectThreshold: %v, PaymentThreshold: %v", params.DisconnectThreshold, params.PaymentThreshold) } // connect to the backend backend, err := ethclient.Dial(backendURL) @@ -270,11 +270,11 @@ func createOwner(prvkey *ecdsa.PrivateKey) *Owner { } // modifyBalanceOk checks that the amount would not result in crossing the disconnection threshold -func (s *Swap) modifyBalanceOk(amount int64, swapPeer *Peer) (err error) { +func (s *Swap) modifyBalanceOk(amount *int256.Int256, swapPeer *Peer) (err error) { // check if balance with peer is over the disconnect threshold and if the message would increase the existing debt balance := swapPeer.getBalance() - if balance >= s.params.DisconnectThreshold && amount > 0 { - return fmt.Errorf("balance for peer %s is over the disconnect threshold %d and cannot incur more debt, disconnecting", swapPeer.ID().String(), s.params.DisconnectThreshold) + if balance.Cmp(s.params.DisconnectThreshold) >= 0 && amount.Cmp(int256.Int256From(0)) > 0 { + return fmt.Errorf("balance for peer %s is over the disconnect threshold %v and cannot incur more debt, disconnecting", swapPeer.ID().String(), s.params.DisconnectThreshold) } return nil @@ -292,7 +292,7 @@ func (s *Swap) Check(amount int64, peer *protocols.Peer) (err error) { swapPeer.lock.Lock() defer swapPeer.lock.Unlock() // currently this is the only real check needed: - return s.modifyBalanceOk(amount, swapPeer) + return s.modifyBalanceOk(int256.Int256From(amount), swapPeer) } // Add is the (sole) accounting function @@ -306,11 +306,11 @@ func (s *Swap) Add(amount int64, peer *protocols.Peer) (err error) { swapPeer.lock.Lock() defer swapPeer.lock.Unlock() // we should probably check here again: - if err = s.modifyBalanceOk(amount, swapPeer); err != nil { + if err = s.modifyBalanceOk(int256.Int256From(amount), swapPeer); err != nil { return err } - if err = swapPeer.updateBalance(amount); err != nil { + if err = swapPeer.updateBalance(int256.Int256From(amount)); err != nil { return err } @@ -322,7 +322,20 @@ func (s *Swap) Add(amount int64, peer *protocols.Peer) (err error) { // that the balance is *below* the threshold // the caller is expected to hold swapPeer.lock func (s *Swap) checkPaymentThresholdAndSendCheque(swapPeer *Peer) error { - if swapPeer.getBalance() <= -s.params.PaymentThreshold { + balance := swapPeer.getBalance() + thresholdValue := s.params.PaymentThreshold.Value() + // transform Uint256 to Int256 + threshold, err := int256.NewInt256(thresholdValue) + if err != nil { + return err + } + + negativeThreshold, err := new(int256.Int256).Mul(int256.Int256From(-1), threshold) + if err != nil { + return err + } + + if balance.Cmp(negativeThreshold) < 1 { swapPeer.logger.Info(SendChequeAction, "balance for peer went over the payment threshold, sending cheque", "payment threshold", s.params.PaymentThreshold) return swapPeer.sendCheque() } @@ -370,14 +383,19 @@ func (s *Swap) handleEmitChequeMsg(ctx context.Context, p *Peer, msg *EmitCheque // reset balance by amount // as this is done by the creditor, receiving the cheque, the amount should be negative, // so that updateBalance will calculate balance + amount which result in reducing the peer's balance - honeyAmount := int64(cheque.Honey) - err = p.updateBalance(-honeyAmount) + honeyAmount := int256.Int256From(int64(cheque.Honey)) + honey, err := new(int256.Int256).Mul(int256.Int256From(-1), honeyAmount) + if err != nil { + return protocols.Break(err) + } + + err = p.updateBalance(honey) if err != nil { return protocols.Break(fmt.Errorf("updating balance: %w", err)) } metrics.GetOrRegisterCounter("swap/cheques/received/num", nil).Inc(1) - metrics.GetOrRegisterCounter("swap/cheques/received/honey", nil).Inc(honeyAmount) + metrics.GetOrRegisterCounter("swap/cheques/received/honey", nil).Inc(int64(cheque.Honey)) err = p.Send(ctx, &ConfirmChequeMsg{ Cheque: cheque, @@ -476,11 +494,27 @@ func (s *Swap) processAndVerifyCheque(cheque *Cheque, p *Peer) (*int256.Uint256, return nil, err } + chequeHoney := new(big.Int).SetUint64(cheque.Honey) + honey, err := int256.NewInt256(chequeHoney) + if err != nil { + return nil, err + } + // calculate tentative new balance after cheque is processed - newBalance := p.getBalance() - int64(cheque.Honey) + newBalance, err := new(int256.Int256).Sub(p.getBalance(), honey) + if err != nil { + return nil, err + } + + debtTolerance := big.NewInt(-int64(ChequeDebtTolerance)) + tolerance, err := int256.NewInt256(debtTolerance) + if err != nil { + return nil, err + } + // check if this new balance would put creditor into debt - if newBalance < -int64(ChequeDebtTolerance) { - return nil, fmt.Errorf("received cheque would result in balance %d which exceeds tolerance %d and would cause debt", newBalance, ChequeDebtTolerance) + if newBalance.Cmp(tolerance) == -1 { + return nil, fmt.Errorf("received cheque would result in balance %v which exceeds tolerance %d and would cause debt", newBalance, ChequeDebtTolerance) } if err := p.setLastReceivedCheque(cheque); err != nil { @@ -532,13 +566,13 @@ func (s *Swap) loadPendingCheque(p enode.ID) (cheque *Cheque, err error) { // loadBalance loads the current balance for the peer from the store // and returns 0 if there was no prior balance saved -func (s *Swap) loadBalance(p enode.ID) (balance int64, err error) { +func (s *Swap) loadBalance(p enode.ID) (balance *int256.Int256, err error) { err = s.store.Get(balanceKey(p), &balance) if err == state.ErrNotFound { - return 0, nil + return int256.Int256From(0), nil } if err != nil { - return 0, err + return int256.Int256From(0), err } return balance, nil } @@ -559,7 +593,7 @@ func (s *Swap) savePendingCheque(p enode.ID, cheque *Cheque) error { } // saveBalance saves balance as the current balance for peer -func (s *Swap) saveBalance(p enode.ID, balance int64) error { +func (s *Swap) saveBalance(p enode.ID, balance *int256.Int256) error { return s.store.Put(balanceKey(p), balance) } diff --git a/swap/swap_test.go b/swap/swap_test.go index b562a0c35f..552369e851 100644 --- a/swap/swap_test.go +++ b/swap/swap_test.go @@ -65,7 +65,7 @@ var ( // if `amount` is positive, it means the node which adds this booking will be credited in respect to `peer` // otherwise it will be debited type booking struct { - amount int64 + amount *int256.Int256 peer *protocols.Peer } @@ -156,7 +156,7 @@ func TestStoreBalances(t *testing.T) { t.Fatal(err) } testPeerID := testPeer.ID() - peerBalance := int64(29) + peerBalance := int256.Int256From(29) if err := testPeer.setBalance(peerBalance); err != nil { t.Fatal(err) } @@ -169,7 +169,7 @@ func TestStoreBalances(t *testing.T) { t.Fatal(err) } testPeer2ID := testPeer2.ID() - peer2Balance := int64(-76) + peer2Balance := int256.Int256From(-76) if err := testPeer2.setBalance(peer2Balance); err != nil { t.Fatal(err) @@ -179,15 +179,15 @@ func TestStoreBalances(t *testing.T) { comparePeerBalance(t, s, testPeer2ID, peer2Balance) } -func comparePeerBalance(t *testing.T, s *Swap, peer enode.ID, expectedPeerBalance int64) { +func comparePeerBalance(t *testing.T, s *Swap, peer enode.ID, expectedPeerBalance *int256.Int256) { t.Helper() - var peerBalance int64 + var peerBalance *int256.Int256 err := s.store.Get(balanceKey(peer), &peerBalance) if err != nil && err != state.ErrNotFound { t.Error("Unexpected peer balance retrieval failure.") } - if peerBalance != expectedPeerBalance { - t.Errorf("Expected peer store balance to be %d, but is %d instead.", expectedPeerBalance, peerBalance) + if !peerBalance.Equals(expectedPeerBalance) { + t.Errorf("Expected peer store balance to be %v, but is %v instead.", expectedPeerBalance, peerBalance) } } @@ -219,9 +219,9 @@ func TestRepeatedBookings(t *testing.T) { // credits and debits to peer 2 mixedBookings := []booking{ - {int64(mrand.Intn(100)), testPeer2.Peer}, - {int64(0 - mrand.Intn(55)), testPeer2.Peer}, - {int64(0 - mrand.Intn(999)), testPeer2.Peer}, + {int256.Int256From(int64(mrand.Intn(100))), testPeer2.Peer}, + {int256.Int256From(int64(0 - mrand.Intn(55))), testPeer2.Peer}, + {int256.Int256From(int64(0 - mrand.Intn(999))), testPeer2.Peer}, } addBookings(swap, mixedBookings) verifyBookings(t, swap, append(bookings, mixedBookings...)) @@ -313,7 +313,10 @@ func TestNewSwapFailure(t *testing.T) { config.dbPath = dir config.prvkey = prvKey config.backendURL = ipcEndpoint - params.PaymentThreshold = params.DisconnectThreshold + 1 + params.PaymentThreshold, err = new(int256.Uint256).Add(params.DisconnectThreshold, int256.Uint256From(1)) + if err != nil { + t.Fatal(err) + } config.factoryAddress = testBackend.factoryAddress }, check: func(t *testing.T, config *testSwapConfig) { @@ -363,7 +366,7 @@ func TestNewSwapFailure(t *testing.T) { configure: func(config *testSwapConfig) { config.prvkey = prvKey config.backendURL = "invalid backendURL" - params.PaymentThreshold = int64(DefaultPaymentThreshold) + params.PaymentThreshold = DefaultPaymentThreshold config.skipDeposit = false config.factoryAddress = testBackend.factoryAddress }, @@ -555,8 +558,9 @@ func TestDisconnectThreshold(t *testing.T) { testPeer := newDummyPeer() swap.addPeer(testPeer.Peer, swap.owner.address, swap.GetParams().ContractAddress) + amount := DefaultDisconnectThreshold.Value() // leave balance exactly at disconnect threshold - swap.Add(int64(DefaultDisconnectThreshold), testPeer.Peer) + swap.Add(amount.Int64(), testPeer.Peer) // account for traffic which increases debt err := swap.Add(1, testPeer.Peer) if err == nil { @@ -576,16 +580,17 @@ func TestDisconnectThreshold(t *testing.T) { func TestPaymentThreshold(t *testing.T) { swap, clean := newTestSwap(t, ownerKey, nil) defer clean() - testDeploy(context.Background(), swap, int256.Uint256From(DefaultPaymentThreshold)) + testDeploy(context.Background(), swap, DefaultPaymentThreshold) testPeer := newDummyPeerWithSpec(Spec) swap.addPeer(testPeer.Peer, swap.owner.address, swap.GetParams().ContractAddress) - if err := swap.Add(-int64(DefaultPaymentThreshold), testPeer.Peer); err != nil { + amount := DefaultPaymentThreshold.Value() + if err := swap.Add(-amount.Int64(), testPeer.Peer); err != nil { t.Fatal() } var cheque *Cheque _ = swap.store.Get(pendingChequeKey(testPeer.Peer.ID()), &cheque) - if !cheque.CumulativePayout.Equals(int256.Uint256From(DefaultPaymentThreshold)) { + if !cheque.CumulativePayout.Equals(DefaultPaymentThreshold) { t.Fatal() } } @@ -606,14 +611,18 @@ func TestResetBalance(t *testing.T) { defer clean1() defer clean2() - testAmount := DefaultPaymentThreshold + 42 + testAmount, err := new(int256.Uint256).Add(DefaultPaymentThreshold, int256.Uint256From(42)) + + if err != nil { + t.Fatal(err) + } ctx := context.Background() - err := testDeploy(ctx, creditorSwap, int256.Uint256From(0)) + err = testDeploy(ctx, creditorSwap, int256.Uint256From(0)) if err != nil { t.Fatal(err) } - err = testDeploy(ctx, debitorSwap, int256.Uint256From(testAmount)) + err = testDeploy(ctx, debitorSwap, testAmount) if err != nil { t.Fatal(err) } @@ -632,11 +641,20 @@ func TestResetBalance(t *testing.T) { t.Fatal(err) } + amount := testAmount.Value() + debitorBalance, err := int256.NewInt256(amount) + if err != nil { + t.Fatal(err) + } + creditorBalance, err := int256.NewInt256(new(big.Int).Mul(big.NewInt(-1), amount)) + if err != nil { + t.Fatal(err) + } // set balances arbitrarily - if err = debitor.setBalance(int64(testAmount)); err != nil { + if err = debitor.setBalance(debitorBalance); err != nil { t.Fatal(err) } - if err = creditor.setBalance(int64(-testAmount)); err != nil { + if err = creditor.setBalance(creditorBalance); err != nil { t.Fatal(err) } @@ -653,8 +671,8 @@ func TestResetBalance(t *testing.T) { Cheque: creditor.getPendingCheque(), }) // the debitor should have already reset its balance - if creditor.getBalance() != 0 { - t.Fatalf("unexpected balance to be 0, but it is %d", creditor.getBalance()) + if !creditor.getBalance().Equals(int256.Int256From(0)) { + t.Fatalf("unexpected balance to be 0, but it is %v", creditor.getBalance()) } // now load the cheque that the debitor created... @@ -681,8 +699,8 @@ func TestResetBalance(t *testing.T) { t.Fatalf("Timeout waiting for cash transactions to complete") } // finally check that the creditor also successfully reset the balances - if debitor.getBalance() != 0 { - t.Fatalf("unexpected balance to be 0, but it is %d", debitor.getBalance()) + if !debitor.getBalance().Equals(int256.Int256From(0)) { + t.Fatalf("unexpected balance to be 0, but it is %v", debitor.getBalance()) } } @@ -702,7 +720,11 @@ func TestDebtCheques(t *testing.T) { t.Fatal(err) } - debitorChequebook, err := testDeployWithPrivateKey(ctx, testBackend, ownerKey, ownerAddress, int256.Uint256From((DefaultPaymentThreshold * 2))) + amount, err := new(int256.Uint256).Mul(DefaultPaymentThreshold, int256.Uint256From(2)) + if err != nil { + t.Fatal(err) + } + debitorChequebook, err := testDeployWithPrivateKey(ctx, testBackend, ownerKey, ownerAddress, amount) if err != nil { t.Fatal(err) } @@ -767,7 +789,7 @@ func testPeerBookings(t *testing.T, s *Swap, bookings *[]booking, bookingAmount // generate as many bookings as specified by `quantity`, each one with the indicated `amount` and `peer` func generateBookings(amount int64, quantity int, peer *protocols.Peer) (bookings []booking) { for i := 0; i < quantity; i++ { - bookings = append(bookings, booking{amount, peer}) + bookings = append(bookings, booking{int256.Int256From(amount), peer}) } return } @@ -776,14 +798,15 @@ func generateBookings(amount int64, quantity int, peer *protocols.Peer) (booking func addBookings(swap *Swap, bookings []booking) { for i := 0; i < len(bookings); i++ { booking := bookings[i] - swap.Add(booking.amount, booking.peer) + amount := booking.amount.Value() + swap.Add(amount.Int64(), booking.peer) } } // take a Swap struct and a list of bookings, and verify the resulting balances are as expected func verifyBookings(t *testing.T, s *Swap, bookings []booking) { t.Helper() - expectedBalances := calculateExpectedBalances(s, bookings) + expectedBalances := calculateExpectedBalances(t, s, bookings) realBalances, err := s.Balances() if err != nil { t.Fatal(err) @@ -794,7 +817,7 @@ func verifyBookings(t *testing.T, s *Swap, bookings []booking) { } // converts a balance map to a one-line string representation -func stringifyBalance(balance map[enode.ID]int64) string { +func stringifyBalance(balance map[enode.ID]*int256.Int256) string { marshaledBalance, err := json.Marshal(balance) if err != nil { return err.Error() @@ -805,15 +828,20 @@ func stringifyBalance(balance map[enode.ID]int64) string { // take a swap struct and a list of bookings, and calculate the expected balances. // the result is a map which stores the balance for all the peers present in the bookings, // from the perspective of the node that loaded the Swap struct. -func calculateExpectedBalances(swap *Swap, bookings []booking) map[enode.ID]int64 { - expectedBalances := make(map[enode.ID]int64) +func calculateExpectedBalances(t *testing.T, swap *Swap, bookings []booking) map[enode.ID]*int256.Int256 { + expectedBalances := make(map[enode.ID]*int256.Int256) for i := 0; i < len(bookings); i++ { booking := bookings[i] peerID := booking.peer.ID() - peerBalance := expectedBalances[peerID] + peerBalance, ok := expectedBalances[peerID] + if !ok { + peerBalance = int256.Int256From(0) + } // peer balance should only be affected if debt is being reduced or if balance is smaller than disconnect threshold - if peerBalance < swap.params.DisconnectThreshold || booking.amount < 0 { - peerBalance += booking.amount + if peerBalance.Cmp(swap.params.DisconnectThreshold) < 0 || booking.amount.Cmp(int256.Int256From(0)) < 0 { + if _, err := peerBalance.Add(peerBalance, booking.amount); err != nil { + t.Fatal(err) + } } expectedBalances[peerID] = peerBalance } @@ -838,7 +866,8 @@ func TestRestoreBalanceFromStateStore(t *testing.T) { if err != nil { t.Fatal(err) } - if err = testPeer.setBalance(-8888); err != nil { + + if err = testPeer.setBalance(int256.Int256From(-8888)); err != nil { t.Fatal(err) } @@ -857,12 +886,12 @@ func TestRestoreBalanceFromStateStore(t *testing.T) { t.Fatal(err) } - var newBalance int64 + var newBalance *int256.Int256 stateStore.Get(testPeer.Peer.ID().String(), &newBalance) // compare the balances - if tmpBalance != newBalance { - t.Fatalf("Unexpected balance value after sending cheap message test. Expected balance: %d, balance is: %d", tmpBalance, newBalance) + if !tmpBalance.Equals(newBalance) { + t.Fatalf("Unexpected balance value after sending cheap message test. Expected balance: %v, balance is: %v", tmpBalance, newBalance) } } @@ -1268,10 +1297,13 @@ func TestSwapLogToFile(t *testing.T) { } defer clean() - testAmount := DefaultPaymentThreshold + 42 + testAmount, err := new(int256.Uint256).Add(DefaultPaymentThreshold, int256.Uint256From(42)) + if err != nil { + t.Fatal(err) + } ctx := context.Background() - err = testDeploy(ctx, creditorSwap, int256.Uint256From(testAmount)) + err = testDeploy(ctx, creditorSwap, testAmount) if err != nil { t.Fatal(err) } @@ -1294,11 +1326,14 @@ func TestSwapLogToFile(t *testing.T) { t.Fatal(err) } + ta := testAmount.Value() + debitorAmount, err := int256.NewInt256(ta) + creditorAmount, err := int256.NewInt256(new(big.Int).Mul(big.NewInt(-1), ta)) // set balances arbitrarily - if err = debitor.setBalance(int64(testAmount)); err != nil { + if err = debitor.setBalance(debitorAmount); err != nil { t.Fatal(err) } - if err = creditor.setBalance(int64(-testAmount)); err != nil { + if err = creditor.setBalance(creditorAmount); err != nil { t.Fatal(err) } @@ -1487,9 +1522,10 @@ func TestAvailableBalance(t *testing.T) { // send a cheque worth 42 chequeAmount := uint64(42) // create a dummy peer. Note: the peer's contract address and the peers address are resp the swap contract and the swap owner - if err = peer.setBalance(int64(-chequeAmount)); err != nil { + if err = peer.setBalance(int256.Int256From(int64(-chequeAmount))); err != nil { t.Fatal(err) } + if err = peer.sendCheque(); err != nil { t.Fatal(err) } diff --git a/swarm.go b/swarm.go index ff109c6bcc..e0a792bfc4 100644 --- a/swarm.go +++ b/swarm.go @@ -135,8 +135,8 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e BaseAddrs: bzzconfig.Address, LogPath: self.config.SwapLogPath, LogLevel: self.config.SwapLogLevel, - DisconnectThreshold: int64(self.config.SwapDisconnectThreshold), - PaymentThreshold: int64(self.config.SwapPaymentThreshold), + DisconnectThreshold: self.config.SwapDisconnectThreshold, + PaymentThreshold: self.config.SwapPaymentThreshold, } // create the accounting objects