swarm/swap: new swap accounting with SwapEnabled flag

This commit is contained in:
Fabio Barone 2018-08-30 11:49:08 -05:00
parent 9c024e2517
commit 55f45d2523
3 changed files with 73 additions and 31 deletions

View file

@ -110,7 +110,8 @@ func (sp *SwapPeer) handle(ctx context.Context, msg interface{}) error {
var price *big.Int var price *big.Int
//the message is one which needs accounting... //the message is one which needs accounting...
if _, ok := msg.(PricedMsg); ok { //only account if swapAccount != nil (== swap is disabled)
if _, ok := msg.(PricedMsg); ok && sp.swapAccount != nil {
//..so first check if there are enough funds for the operation available //..so first check if there are enough funds for the operation available
//(for crediting, this means if we are not essentially "overdrafting", or crossing the threshold) //(for crediting, this means if we are not essentially "overdrafting", or crossing the threshold)
price, err = sp.checkAvailableFunds(ctx, msg, CreditEntry) price, err = sp.checkAvailableFunds(ctx, msg, CreditEntry)
@ -144,7 +145,8 @@ func (sp *SwapPeer) Send(ctx context.Context, msg interface{}) error {
var price *big.Int var price *big.Int
//the message is one which needs accounting... //the message is one which needs accounting...
if _, ok := msg.(PricedMsg); ok { //only account if swapAccount != nil (== swap is disabled)
if _, ok := msg.(PricedMsg); ok && sp.swapAccount != nil {
//..so first check if there are enough funds for the operation available //..so first check if there are enough funds for the operation available
price, err = sp.checkAvailableFunds(ctx, msg, DebitEntry) price, err = sp.checkAvailableFunds(ctx, msg, DebitEntry)
//if not (or some other error occured), return error //if not (or some other error occured), return error
@ -263,18 +265,21 @@ func (sp *SwapPeer) issueCheque(ctx context.Context) error {
//Create a new swap accounted peer //Create a new swap accounted peer
func NewSwapPeer(peer *protocols.Peer, swap *Swap) *SwapPeer { func NewSwapPeer(peer *protocols.Peer, swap *Swap) *SwapPeer {
balance := big.NewInt(0)
//check if there is one already in the stateStore and load it
swap.stateStore.Get(peer.String()[:24]+"-swap", &balance)
sp := &SwapPeer{ sp := &SwapPeer{
Peer: peer, Peer: peer,
swapAccount: swap, swapAccount: swap,
balance: balance,
storeID: peer.String()[:24] + "-swap", storeID: peer.String()[:24] + "-swap",
} }
//swap is not enabled
if swap != nil {
//check if there is one already in the stateStore and load it
balance := &big.Int{}
swap.stateStore.Get(peer.String()[:24]+"-swap", &balance)
sp.balance = balance
swap.lock.Lock() swap.lock.Lock()
defer swap.lock.Unlock() defer swap.lock.Unlock()
swap.peers[peer.ID()] = sp swap.peers[peer.ID()] = sp
}
return sp return sp
} }

View file

@ -22,9 +22,16 @@ import (
"github.com/ethereum/go-ethereum/swarm/storage" "github.com/ethereum/go-ethereum/swarm/storage"
) )
//In TestSwapNetworkSymmetricFileUpload we set up a network with arbitrary number of nodes
//(16), and each of the nodes uploads a file of same size
//Afterwards we check that every node's balance WITH ANOTHER PEER
//has the same value but opposite sign
func TestSwapNetworkSymmetricFileUpload(t *testing.T) { func TestSwapNetworkSymmetricFileUpload(t *testing.T) {
//default hardcoded network size
nodeCount := 16 nodeCount := 16
//setup the simulation
//use a complete node setup via `NewSwam`
sim := simulation.New(map[string]simulation.ServiceFunc{ sim := simulation.New(map[string]simulation.ServiceFunc{
"swarm": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) { "swarm": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) {
config := api.NewConfig() config := api.NewConfig()
@ -49,6 +56,9 @@ func TestSwapNetworkSymmetricFileUpload(t *testing.T) {
config.Init(privkey) config.Init(privkey)
//set Swap to be enabled for this test
config.SwapEnabled = true
swarm, err := NewSwarm(config, nil) swarm, err := NewSwarm(config, nil)
if err != nil { if err != nil {
return nil, cleanup, err return nil, cleanup, err
@ -67,16 +77,19 @@ func TestSwapNetworkSymmetricFileUpload(t *testing.T) {
var nodeStatusM sync.Map var nodeStatusM sync.Map
var totalFoundCount uint64 var totalFoundCount uint64
//connect all nodes in a chain
_, err := sim.AddNodesAndConnectChain(nodeCount) _, err := sim.AddNodesAndConnectChain(nodeCount)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
//run the simulation
result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error {
nodeIDs := sim.UpNodeIDs() nodeIDs := sim.UpNodeIDs()
shuffle(len(nodeIDs), func(i, j int) { shuffle(len(nodeIDs), func(i, j int) {
nodeIDs[i], nodeIDs[j] = nodeIDs[j], nodeIDs[i] nodeIDs[i], nodeIDs[j] = nodeIDs[j], nodeIDs[i]
}) })
//upload a file for every node
for _, id := range nodeIDs { for _, id := range nodeIDs {
key, data, err := uploadFile(sim.Service("swarm", id).(*Swarm)) key, data, err := uploadFile(sim.Service("swarm", id).(*Swarm))
if err != nil { if err != nil {
@ -90,6 +103,7 @@ func TestSwapNetworkSymmetricFileUpload(t *testing.T) {
}) })
} }
//wait for kademlia to be healthy
if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { if _, err := sim.WaitTillHealthy(ctx, 2); err != nil {
return err return err
} }
@ -103,8 +117,11 @@ func TestSwapNetworkSymmetricFileUpload(t *testing.T) {
} }
}) })
//every node has a map to all nodes it had interactions
//each entry in the map is a map of the other node with all the balances
balancesMap := make(map[discover.NodeID]map[discover.NodeID]*big.Int) balancesMap := make(map[discover.NodeID]map[discover.NodeID]*big.Int)
//iterate all nodes
for _, node := range sim.NodeIDs() { for _, node := range sim.NodeIDs() {
item, ok := sim.NodeItem(node, bucketKeySwarm) item, ok := sim.NodeItem(node, bucketKeySwarm)
if !ok { if !ok {
@ -113,12 +130,17 @@ func TestSwapNetworkSymmetricFileUpload(t *testing.T) {
} }
swarm := item.(*Swarm) swarm := item.(*Swarm)
//submap for each node is a map of all nodes with the balance for that node
subBalances := make(map[discover.NodeID]*big.Int) subBalances := make(map[discover.NodeID]*big.Int)
//iterate all nodes again...
//get all balances with other peers for every node
for _, n := range sim.NodeIDs() { for _, n := range sim.NodeIDs() {
if node == n { if node == n {
continue continue
} }
//get the peer's balance with this node
balance := swarm.swap.GetPeerBalance(n) balance := swarm.swap.GetPeerBalance(n)
if balance != nil { if balance != nil {
subBalances[n] = balance subBalances[n] = balance
@ -127,9 +149,11 @@ func TestSwapNetworkSymmetricFileUpload(t *testing.T) {
log.Debug(fmt.Sprintf("Node %s has no balance with node %s", node.TerminalString(), n.TerminalString())) log.Debug(fmt.Sprintf("Node %s has no balance with node %s", node.TerminalString(), n.TerminalString()))
} }
} }
//update the map for this node
balancesMap[node] = subBalances balancesMap[node] = subBalances
} }
//print all the balances if requested
if *printStats { if *printStats {
for k, v := range balancesMap { for k, v := range balancesMap {
fmt.Println(fmt.Sprintf("node %s balances:", k.TerminalString())) fmt.Println(fmt.Sprintf("node %s balances:", k.TerminalString()))
@ -139,12 +163,22 @@ func TestSwapNetworkSymmetricFileUpload(t *testing.T) {
} }
} }
//now iterate the whole map
//and check that every node k has the same
//balance with a peer as that peer with the node,
//but in inverted signs
//iterate the map
for k, mapForK := range balancesMap { for k, mapForK := range balancesMap {
//iterate the submap
for n, balanceKwithN := range mapForK { for n, balanceKwithN := range mapForK {
//iterate the main map again
for subK, mapForSubK := range balancesMap { for subK, mapForSubK := range balancesMap {
//if the node and the peer are the same...
if n == subK { if n == subK {
log.Trace(fmt.Sprintf("balance of %s with %s: %s", k.TerminalString(), n.TerminalString(), balanceKwithN)) log.Trace(fmt.Sprintf("balance of %s with %s: %s", k.TerminalString(), n.TerminalString(), balanceKwithN))
log.Trace(fmt.Sprintf("balance of %s with %s: %s", n.TerminalString(), k.TerminalString(), mapForSubK[k])) log.Trace(fmt.Sprintf("balance of %s with %s: %s", n.TerminalString(), k.TerminalString(), mapForSubK[k]))
//...check that they have the same balance in Abs terms and that it is not 0
if balanceKwithN.CmpAbs(mapForSubK[k]) != 0 && balanceKwithN.Cmp(big.NewInt(0)) != 0 { if balanceKwithN.CmpAbs(mapForSubK[k]) != 0 && balanceKwithN.Cmp(big.NewInt(0)) != 0 {
log.Error("Expected balances to be |abs| = 0 AND balance1 != 0, but they are not") log.Error("Expected balances to be |abs| = 0 AND balance1 != 0, but they are not")
} }
@ -159,6 +193,8 @@ func TestSwapNetworkSymmetricFileUpload(t *testing.T) {
log.Debug("test terminated") log.Debug("test terminated")
} }
//TestSwapNetworkAsymmetricFileUpload is a swap test too,
//but this time the number and size of files are random
func TestSwapNetworkAsymmetricFileUpload(t *testing.T) { func TestSwapNetworkAsymmetricFileUpload(t *testing.T) {
nodeCount := 16 nodeCount := 16
@ -185,6 +221,8 @@ func TestSwapNetworkAsymmetricFileUpload(t *testing.T) {
} }
config.Init(privkey) config.Init(privkey)
//enable swap
config.SwapEnabled = true
swarm, err := NewSwarm(config, nil) swarm, err := NewSwarm(config, nil)
if err != nil { if err != nil {
@ -209,6 +247,9 @@ func TestSwapNetworkAsymmetricFileUpload(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
//this is actually quite a big maxFileSize, which results
//in the test running for nearly 2 minutes
//maybe for the test, we could reduce it
const maxFileSize = 1024 * 1024 * 4 //1024 bytes * 1024 * 4 = 4MB const maxFileSize = 1024 * 1024 * 4 //1024 bytes * 1024 * 4 = 4MB
const minfileSize = 1024 const minfileSize = 1024
@ -289,8 +330,8 @@ func TestSwapNetworkAsymmetricFileUpload(t *testing.T) {
} }
/* /*
TODO: Should balances in this case also be symmetric? Assuming that in this case, balances should be symmetric too I
*/
for k, mapForK := range balancesMap { for k, mapForK := range balancesMap {
for n, balanceKwithN := range mapForK { for n, balanceKwithN := range mapForK {
for subK, mapForSubK := range balancesMap { for subK, mapForSubK := range balancesMap {
@ -304,7 +345,6 @@ func TestSwapNetworkAsymmetricFileUpload(t *testing.T) {
} }
} }
} }
*/
if result.Error != nil { if result.Error != nil {
t.Fatal(result.Error) t.Fatal(result.Error)

View file

@ -178,6 +178,12 @@ func NewSwarm(config *api.Config, mockStore *mock.NodeStore) (self *Swarm, err e
if err := nodeID.UnmarshalText([]byte(config.NodeID)); err != nil { if err := nodeID.UnmarshalText([]byte(config.NodeID)); err != nil {
return nil, err return nil, err
} }
if config.SwapEnabled {
self.swap, err = swap.New(stateStore)
if err != nil {
return nil, err
}
}
self.streamer = stream.NewRegistry(nodeID, delivery, self.netStore, stateStore, &stream.RegistryOptions{ self.streamer = stream.NewRegistry(nodeID, delivery, self.netStore, stateStore, &stream.RegistryOptions{
SkipCheck: config.DeliverySkipCheck, SkipCheck: config.DeliverySkipCheck,
DoSync: config.SyncEnabled, DoSync: config.SyncEnabled,
@ -344,7 +350,7 @@ func (self *Swarm) Start(srv *p2p.Server) error {
newaddr := self.bzz.UpdateLocalAddr([]byte(srv.Self().String())) newaddr := self.bzz.UpdateLocalAddr([]byte(srv.Self().String()))
log.Info("Updated bzz local addr", "oaddr", fmt.Sprintf("%x", newaddr.OAddr), "uaddr", fmt.Sprintf("%s", newaddr.UAddr)) log.Info("Updated bzz local addr", "oaddr", fmt.Sprintf("%x", newaddr.OAddr), "uaddr", fmt.Sprintf("%s", newaddr.UAddr))
// set chequebook // set chequebook
if self.config.SwapEnabled { if self.config.SwapEnabled && self.config.SwapAPI != "" {
ctx := context.Background() // The initial setup has no deadline. ctx := context.Background() // The initial setup has no deadline.
err := self.SetChequebook(ctx) err := self.SetChequebook(ctx)
if err != nil { if err != nil {
@ -364,15 +370,6 @@ func (self *Swarm) Start(srv *p2p.Server) error {
} }
log.Info("Swarm network started", "bzzaddr", fmt.Sprintf("%x", self.bzz.Hive.BaseAddr())) log.Info("Swarm network started", "bzzaddr", fmt.Sprintf("%x", self.bzz.Hive.BaseAddr()))
/*
err = self.swap.Start(srv)
if err != nil {
log.Error("swap failed", "err", err)
return err
}
log.Debug("Swap accounting initialized")
*/
if self.ps != nil { if self.ps != nil {
self.ps.Start(srv) self.ps.Start(srv)
} }