99 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			99 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2018 The go-ethereum Authors
 | |
| // This file is part of the go-ethereum library.
 | |
| //
 | |
| // The go-ethereum library is free software: you can redistribute it and/or modify
 | |
| // it under the terms of the GNU Lesser General Public License as published by
 | |
| // the Free Software Foundation, either version 3 of the License, or
 | |
| // (at your option) any later version.
 | |
| //
 | |
| // The go-ethereum library is distributed in the hope that it will be useful,
 | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | |
| // GNU Lesser General Public License for more details.
 | |
| //
 | |
| // You should have received a copy of the GNU Lesser General Public License
 | |
| // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| package swap
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"strconv"
 | |
| 	"sync"
 | |
| 
 | |
| 	"github.com/ethereum/go-ethereum/p2p/enode"
 | |
| 	"github.com/ethereum/go-ethereum/p2p/protocols"
 | |
| 	"github.com/ethereum/go-ethereum/swarm/log"
 | |
| 	"github.com/ethereum/go-ethereum/swarm/state"
 | |
| )
 | |
| 
 | |
| // SwAP Swarm Accounting Protocol
 | |
| // a peer to peer micropayment system
 | |
| // A node maintains an individual balance with every peer
 | |
| // Only messages which have a price will be accounted for
 | |
| type Swap struct {
 | |
| 	stateStore state.Store        //stateStore is needed in order to keep balances across sessions
 | |
| 	lock       sync.RWMutex       //lock the balances
 | |
| 	balances   map[enode.ID]int64 //map of balances for each peer
 | |
| }
 | |
| 
 | |
| // New - swap constructor
 | |
| func New(stateStore state.Store) (swap *Swap) {
 | |
| 	swap = &Swap{
 | |
| 		stateStore: stateStore,
 | |
| 		balances:   make(map[enode.ID]int64),
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| //Swap implements the protocols.Balance interface
 | |
| //Add is the (sole) accounting function
 | |
| func (s *Swap) Add(amount int64, peer *protocols.Peer) (err error) {
 | |
| 	s.lock.Lock()
 | |
| 	defer s.lock.Unlock()
 | |
| 
 | |
| 	//load existing balances from the state store
 | |
| 	err = s.loadState(peer)
 | |
| 	if err != nil && err != state.ErrNotFound {
 | |
| 		return
 | |
| 	}
 | |
| 	//adjust the balance
 | |
| 	//if amount is negative, it will decrease, otherwise increase
 | |
| 	s.balances[peer.ID()] += amount
 | |
| 	//save the new balance to the state store
 | |
| 	peerBalance := s.balances[peer.ID()]
 | |
| 	err = s.stateStore.Put(peer.ID().String(), &peerBalance)
 | |
| 
 | |
| 	log.Debug(fmt.Sprintf("balance for peer %s: %s", peer.ID().String(), strconv.FormatInt(peerBalance, 10)))
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| //GetPeerBalance returns the balance for a given peer
 | |
| func (swap *Swap) GetPeerBalance(peer enode.ID) (int64, error) {
 | |
| 	swap.lock.RLock()
 | |
| 	defer swap.lock.RUnlock()
 | |
| 	if p, ok := swap.balances[peer]; ok {
 | |
| 		return p, nil
 | |
| 	}
 | |
| 	return 0, errors.New("Peer not found")
 | |
| }
 | |
| 
 | |
| //load balances from the state store (persisted)
 | |
| func (s *Swap) loadState(peer *protocols.Peer) (err error) {
 | |
| 	var peerBalance int64
 | |
| 	peerID := peer.ID()
 | |
| 	//only load if the current instance doesn't already have this peer's
 | |
| 	//balance in memory
 | |
| 	if _, ok := s.balances[peerID]; !ok {
 | |
| 		err = s.stateStore.Get(peerID.String(), &peerBalance)
 | |
| 		s.balances[peerID] = peerBalance
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| //Clean up Swap
 | |
| func (swap *Swap) Close() {
 | |
| 	swap.stateStore.Close()
 | |
| }
 |