github.com/susy-go/susy-graviton@v0.0.0-20190614130430-36cddae42305/swarm/swap/swap.go (about)

     1  // Copyleft 2018 The susy-graviton Authors
     2  // This file is part of the susy-graviton library.
     3  //
     4  // The susy-graviton library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The susy-graviton library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MSRCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the susy-graviton library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package swap
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"strconv"
    23  	"sync"
    24  
    25  	"github.com/susy-go/susy-graviton/p2p/enode"
    26  	"github.com/susy-go/susy-graviton/p2p/protocols"
    27  	"github.com/susy-go/susy-graviton/swarm/log"
    28  	"github.com/susy-go/susy-graviton/swarm/state"
    29  )
    30  
    31  // SwAP Swarm Accounting Protocol
    32  // a peer to peer micropayment system
    33  // A node maintains an individual balance with every peer
    34  // Only messages which have a price will be accounted for
    35  type Swap struct {
    36  	stateStore state.Store        //stateStore is needed in order to keep balances across sessions
    37  	lock       sync.RWMutex       //lock the balances
    38  	balances   map[enode.ID]int64 //map of balances for each peer
    39  }
    40  
    41  // New - swap constructor
    42  func New(stateStore state.Store) (swap *Swap) {
    43  	swap = &Swap{
    44  		stateStore: stateStore,
    45  		balances:   make(map[enode.ID]int64),
    46  	}
    47  	return
    48  }
    49  
    50  //Swap implements the protocols.Balance interface
    51  //Add is the (sole) accounting function
    52  func (s *Swap) Add(amount int64, peer *protocols.Peer) (err error) {
    53  	s.lock.Lock()
    54  	defer s.lock.Unlock()
    55  
    56  	//load existing balances from the state store
    57  	err = s.loadState(peer)
    58  	if err != nil && err != state.ErrNotFound {
    59  		return
    60  	}
    61  	//adjust the balance
    62  	//if amount is negative, it will decrease, otherwise increase
    63  	s.balances[peer.ID()] += amount
    64  	//save the new balance to the state store
    65  	peerBalance := s.balances[peer.ID()]
    66  	err = s.stateStore.Put(peer.ID().String(), &peerBalance)
    67  
    68  	log.Debug(fmt.Sprintf("balance for peer %s: %s", peer.ID().String(), strconv.FormatInt(peerBalance, 10)))
    69  	return err
    70  }
    71  
    72  //GetPeerBalance returns the balance for a given peer
    73  func (swap *Swap) GetPeerBalance(peer enode.ID) (int64, error) {
    74  	swap.lock.RLock()
    75  	defer swap.lock.RUnlock()
    76  	if p, ok := swap.balances[peer]; ok {
    77  		return p, nil
    78  	}
    79  	return 0, errors.New("Peer not found")
    80  }
    81  
    82  //load balances from the state store (persisted)
    83  func (s *Swap) loadState(peer *protocols.Peer) (err error) {
    84  	var peerBalance int64
    85  	peerID := peer.ID()
    86  	//only load if the current instance doesn't already have this peer's
    87  	//balance in memory
    88  	if _, ok := s.balances[peerID]; !ok {
    89  		err = s.stateStore.Get(peerID.String(), &peerBalance)
    90  		s.balances[peerID] = peerBalance
    91  	}
    92  	return
    93  }
    94  
    95  //Clean up Swap
    96  func (swap *Swap) Close() {
    97  	swap.stateStore.Close()
    98  }