Skip to content
This repository has been archived by the owner on Aug 2, 2021. It is now read-only.

Commit

Permalink
swap: conversion to wei on cheque creation; cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
holisticode committed Jul 19, 2019
1 parent 88e8c67 commit fdadcbe
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 187 deletions.
5 changes: 3 additions & 2 deletions network/stream/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/ethersphere/swarm/p2p/protocols"
"github.com/ethersphere/swarm/state"
"github.com/ethersphere/swarm/storage"
"github.com/ethersphere/swarm/swap"
)

const (
Expand Down Expand Up @@ -658,13 +659,13 @@ func (sp *StreamerPrices) Price(msg interface{}) *protocols.Price {
// Instead of hardcoding the price, get it
// through a function - it could be quite complex in the future
func (sp *StreamerPrices) getRetrieveRequestMsgPrice() uint64 {
return RetrieveRequestMsgPrice
return swap.RetrieveRequestMsgPrice
}

// Instead of hardcoding the price, get it
// through a function - it could be quite complex in the future
func (sp *StreamerPrices) getChunkDeliveryMsgRetrievalPrice() uint64 {
return ChunkDeliveryMsgRetrievalPrice
return swap.ChunkDeliveryMsgRetrievalPrice
}

// createPriceOracle sets up a matrix which can be queried to get
Expand Down
19 changes: 18 additions & 1 deletion swap/defaults.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
// Copyright 2019 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

// Uknown for now, placeholder values
// These are currently arbitrary values which have not been verified nor tested
// Need experimentation to arrive to values which make sense
const (
DefaultPaymentThreshold = 1000000
DefaultDisconnectThreshold = 1500000
Expand Down
11 changes: 3 additions & 8 deletions swap/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,10 @@ func (sp *Peer) handleMsg(ctx context.Context, msg interface{}) error {
// a cheque from a creditor
// TODO: validate the contract address in the cheque to match the address given at handshake
// TODO: this should not be blocking
func (sp *Peer) handleEmitChequeMsg(ctx context.Context, msg interface{}) error {
func (sp *Peer) handleEmitChequeMsg(ctx context.Context, msg *EmitChequeMsg) error {
log.Info("received emit cheque message")

chequeMsg, ok := msg.(*EmitChequeMsg)
if !ok {
return fmt.Errorf("Invalid message type, %v", msg)
}

cheque := chequeMsg.Cheque
cheque := msg.Cheque
if cheque.Contract != sp.contractAddress {
return fmt.Errorf("wrong cheque parameters: expected contract: %s, was: %s", sp.contractAddress, cheque.Contract)
}
Expand All @@ -106,7 +101,7 @@ func (sp *Peer) handleEmitChequeMsg(ctx context.Context, msg interface{}) error
// reset balance by amount
// as this is done by the creditor, receiving the cheque, the amount should be negative,
// so that updateBalance will calculate balance + amount which result in reducing the peer's balance
sp.swap.resetBalance(sp.ID(), 0-int64(cheque.Amount))
sp.swap.resetBalance(sp.ID(), 0-int64(cheque.Honey))
// send confirmation
if err := sp.Send(ctx, &ConfirmMsg{}); err != nil {
log.Error("error while sending confirm msg", "peer", sp.ID().String(), "err", err.Error())
Expand Down
17 changes: 12 additions & 5 deletions swap/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,20 @@ import (
// ErrEmptyAddressInSignature is used when the empty address is used for the chequebook in the handshake
var ErrEmptyAddressInSignature = errors.New("empty address in handshake")

// Spec is the swap protocol specification
var Spec = &protocols.Spec{
Name: "swap",
Version: 1,
MaxMsgSize: 10 * 1024 * 1024,
Messages: []interface{}{
SwapHandshakeMsg{},
HandshakeMsg{},
EmitChequeMsg{},
ErrorMsg{},
ConfirmMsg{},
},
}

// Protocols is a node.Service interface method
func (s *Swap) Protocols() []p2p.Protocol {
return []p2p.Protocol{
{
Expand All @@ -52,6 +54,7 @@ func (s *Swap) Protocols() []p2p.Protocol {
}
}

// APIs is a node.Service interface method
func (s *Swap) APIs() []rpc.API {
return []rpc.API{
{
Expand All @@ -63,41 +66,44 @@ func (s *Swap) APIs() []rpc.API {
}
}

// Start is a node.Service interface method
func (s *Swap) Start(server *p2p.Server) error {
log.Info("Swap service started")
return nil
}

// Stop is a node.Service interface method
func (s *Swap) Stop() error {
return nil
}

// verifyHandshake verifies the chequebook address transmitted in the swap handshake
func (s *Swap) verifyHandshake(msg interface{}) error {
handshake, ok := msg.(*SwapHandshakeMsg)
handshake, ok := msg.(*HandshakeMsg)
if !ok || (handshake.ContractAddress == common.Address{}) {
return ErrEmptyAddressInSignature
}

return s.verifyContract(context.TODO(), handshake.ContractAddress)
}

// run is the actual swap protocol run method
func (s *Swap) run(p *p2p.Peer, rw p2p.MsgReadWriter) error {
protoPeer := protocols.NewPeer(p, rw, Spec)

answer, err := protoPeer.Handshake(context.TODO(), &SwapHandshakeMsg{
answer, err := protoPeer.Handshake(context.TODO(), &HandshakeMsg{
ContractAddress: s.owner.Contract,
}, s.verifyHandshake)
if err != nil {
return err
}

beneficiary, err := s.getContractOwner(context.TODO(), answer.(*SwapHandshakeMsg).ContractAddress)
beneficiary, err := s.getContractOwner(context.TODO(), answer.(*HandshakeMsg).ContractAddress)
if err != nil {
return err
}

swapPeer := NewPeer(protoPeer, s, s.backend, beneficiary, answer.(*SwapHandshakeMsg).ContractAddress)
swapPeer := NewPeer(protoPeer, s, s.backend, beneficiary, answer.(*HandshakeMsg).ContractAddress)

s.lock.Lock()
s.peers[p.ID()] = swapPeer
Expand All @@ -108,5 +114,6 @@ func (s *Swap) run(p *p2p.Peer, rw p2p.MsgReadWriter) error {
return swapPeer.Run(swapPeer.handleMsg)
}

// PublicAPI would be the public API accessor for protocol methods
type PublicAPI struct {
}
158 changes: 67 additions & 91 deletions swap/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,105 +16,81 @@

package swap

// TODO: Update this test.
// We are no longer sending the cheque request messages, we send the cheques directly now.
/*
TestRequestCheque tests that a peer will respond with a
`EmitChequeMsg` containing a cheque for an expected amount
if it sends a `RequestChequeMsg` is sent to it
*/
// func TestRequestCheque(t *testing.T) {
// var err error

// // setup test swap object
// swap, dir := createTestSwap(t)
// defer os.RemoveAll(dir)
import (
"os"
"testing"

// // dummy object so we can run the protocol
// ss := swap
"github.com/ethereum/go-ethereum/common"
p2ptest "github.com/ethereum/go-ethereum/p2p/testing"
)

// // setup the protocolTester, which will allow protocol testing by sending messages
// protocolTester := p2ptest.NewProtocolTester(swap.owner.privateKey, 2, ss.run)

// // shortcut to creditor node
// creditor := protocolTester.Nodes[0]
/*
TestEmitCheque tests an end-to-end exchange between a debitor peer
and its creditor. The debitor issues the cheque, the creditor receives it
and responds with a confirmation
*/
func TestEmitCheque(t *testing.T) {
var err error

// // set balance artifially
// swap.balances[creditor.ID()] = -42
// setup test swap object
swap, dir := newTestSwap(t)
defer os.RemoveAll(dir)

// // create the expected cheque to be received
// // NOTE: this may be improved, as it is essentially running the same
// // code as in production
// expectedCheque := swap.cheques[creditor.ID()]
// expectedCheque = &Cheque{
// ChequeParams: ChequeParams{
// Serial: uint64(1),
// Amount: uint64(42),
// Timeout: defaultCashInDelay,
// Beneficiary: crypto.PubkeyToAddress(*creditor.Pubkey()),
// },
// }
// setup the protocolTester, which will allow protocol testing by sending messages
protocolTester := p2ptest.NewProtocolTester(swap.owner.privateKey, 2, swap.run)

// // sign the cheque
// expectedCheque.Sig, err = swap.signContent(expectedCheque)
// if err != nil {
// t.Fatal(err)
// }
// shortcut to creditor node
debitor := protocolTester.Nodes[0]
creditor := protocolTester.Nodes[1]

// // run the exchange:
// // trigger a `ChequeRequestMsg`
// // expect a `EmitChequeMsg` with a valid cheque
// err = protocolTester.TestExchanges(p2ptest.Exchange{
// Label: "TestRequestCheque",
// Triggers: []p2ptest.Trigger{
// {
// Code: 0,
// Msg: &ChequeRequestMsg{
// crypto.PubkeyToAddress(*creditor.Pubkey()),
// },
// Peer: creditor.ID(),
// },
// },
// Expects: []p2ptest.Expect{
// {
// Code: 1,
// Msg: &EmitChequeMsg{
// Cheque: expectedCheque,
// },
// Peer: creditor.ID(),
// },
// },
// })
// set balance artifially
swap.balances[creditor.ID()] = -42

// // there should be no error at this point
// if err != nil {
// t.Fatal(err)
// }
// create the expected cheque to be received
cheque := newTestCheque()

// // now we request a new cheque;
// // the peer though should have already reset the balance,
// // so no new cheque should be issued
// err = protocolTester.TestExchanges(p2ptest.Exchange{
// Label: "TestRequestNoCheque",
// Triggers: []p2ptest.Trigger{
// {
// Code: 0,
// Msg: &ChequeRequestMsg{
// crypto.PubkeyToAddress(*creditor.Pubkey()),
// },
// Peer: creditor.ID(),
// },
// },
// })
// sign the cheque
cheque.Sig, err = swap.signContent(cheque)
if err != nil {
t.Fatal(err)
}

// //
// if err != nil {
// t.Fatal(err)
// }
// run the exchange:
// trigger a `ChequeRequestMsg`
// expect a `EmitChequeMsg` with a valid cheque
err = protocolTester.TestExchanges(p2ptest.Exchange{
Label: "TestRequestCheque",
Triggers: []p2ptest.Trigger{
{
Code: 1,
Msg: &EmitChequeMsg{
Cheque: cheque,
},
Peer: debitor.ID(),
},
},
Expects: []p2ptest.Expect{
{
Code: 0,
Msg: &HandshakeMsg{
ContractAddress: common.Address{},
},
Peer: creditor.ID(),
},
{
Code: 0,
Msg: &HandshakeMsg{
ContractAddress: common.Address{},
},
Peer: debitor.ID(),
},
},
})

// // no new cheques should have been emitted
// if len(swap.cheques) != 1 {
// t.Fatalf("Expected unchanged number of cheques, but it changed: %d", len(swap.cheques))
// }
// there should be no error at this point
if err != nil {
t.Fatal(err)
}

// }
// TODO: Test further exchanges
}
25 changes: 15 additions & 10 deletions swap/swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (s *Swap) DeploySuccess() string {

// Add is the (sole) accounting function
// Swap implements the protocols.Balance interface
func (s *Swap) Add(honey int64, peer *protocols.Peer) (err error) {
func (s *Swap) Add(amount int64, peer *protocols.Peer) (err error) {
s.lock.Lock()
defer s.lock.Unlock()

Expand All @@ -146,14 +146,6 @@ func (s *Swap) Add(honey int64, peer *protocols.Peer) (err error) {
return errors.New(disconnectMessage)
}

// convert honey to ETH
var amount int64
amount, err = s.oracle.GetPrice(honey)
if err != nil {
log.Error("error getting price from oracle", "err", err)
return
}

// calculate new balance
var newBalance int64
newBalance, err = s.updateBalance(peer.ID(), amount)
Expand Down Expand Up @@ -242,8 +234,19 @@ func (s *Swap) createCheque(peer enode.ID) (*Cheque, error) {
beneficiary := swapPeer.beneficiary

peerBalance := s.balances[peer]
amount := -peerBalance
honey := -peerBalance

// convert honey to ETH
var amount int64
amount, err = s.oracle.GetPrice(honey)
if err != nil {
log.Error("error getting price from oracle", "err", err)
return nil, err
}

// we need to ignore the error check when loading from the StateStore,
// as an error might indicate that there is no existing cheque, which
// could mean it's the first interaction, which is absolutely valid
_ = s.loadCheque(peer)
lastCheque := s.cheques[peer]

Expand All @@ -264,7 +267,9 @@ func (s *Swap) createCheque(peer enode.ID) (*Cheque, error) {
}
cheque.ChequeParams.Timeout = defaultCashInDelay
cheque.ChequeParams.Contract = s.owner.Contract
cheque.ChequeParams.Honey = uint64(honey)
cheque.Beneficiary = beneficiary

cheque.Sig, err = s.signContent(cheque)

return cheque, err
Expand Down
Loading

0 comments on commit fdadcbe

Please sign in to comment.