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 }