// 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 . 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() }