Add proc to engine that pays peers for bytes

This commit is contained in:
Mark Spanbroek 2021-04-14 16:07:49 +02:00 committed by markspanbroek
parent ad48f55aaa
commit 9512bbc50b
6 changed files with 106 additions and 9 deletions

View File

@ -0,0 +1,40 @@
import std/math
import pkg/nitro
import pkg/questionable/results
import ../peercontext
export nitro
export results
export peercontext
push: {.upraises: [].}
const ChainId = 0.u256 # invalid chain id for now
const AmountPerChannel = (10^18).u256 # 1 asset, ERC20 default is 18 decimals
func openLedgerChannel*(wallet: var Wallet,
hub: EthAddress,
asset: EthAddress): ?!ChannelId =
wallet.openLedgerChannel(hub, ChainId, asset, AmountPerChannel)
func getOrOpenChannel(wallet: var Wallet, peer: BitswapPeerCtx): ?!ChannelId =
if channel =? peer.paymentChannel:
channel.success
elif pricing =? peer.pricing:
let channel = ?wallet.openLedgerChannel(pricing.address, pricing.asset)
peer.paymentChannel = channel.some
channel.success
else:
ChannelId.failure "no pricing set for peer"
func pay*(wallet: var Wallet,
peer: BitswapPeerCtx,
amountOfBytes: int): ?!SignedState =
if pricing =? peer.pricing:
let amount = amountOfBytes.u256 * pricing.price
let asset = pricing.asset
let receiver = pricing.address
let channel = ?wallet.getOrOpenChannel(peer)
wallet.pay(channel, asset, receiver, amount)
else:
SignedState.failure "no pricing set for peer"

View File

@ -1,20 +1,25 @@
import std/sequtils
import pkg/libp2p
import pkg/chronos
import pkg/nitro
import pkg/questionable
import ./protobuf/bitswap
import ./protobuf/payments
export payments
export nitro
type
BitswapPeerCtx* = ref object of RootObj
id*: PeerID
peerHave*: seq[Cid] # remote peers have lists
peerWants*: seq[Entry] # remote peers want lists
bytesSent*: int # bytes sent to remote
bytesRecv*: int # bytes received from remote
exchanged*: int # times peer has exchanged with us
lastExchange*: Moment # last time peer has exchanged with us
pricing*: ?Pricing # optional bandwidth price for this peer
peerHave*: seq[Cid] # remote peers have lists
peerWants*: seq[Entry] # remote peers want lists
bytesSent*: int # bytes sent to remote
bytesRecv*: int # bytes received from remote
exchanged*: int # times peer has exchanged with us
lastExchange*: Moment # last time peer has exchanged with us
pricing*: ?Pricing # optional bandwidth price for this peer
paymentChannel*: ?ChannelId # payment channel id
proc contains*(a: openArray[BitswapPeerCtx], b: PeerID): bool =
## Convenience method to check for peer prepense

View File

@ -1,5 +1,6 @@
import pkg/protobuf_serialization
import pkg/stew/byteutils
import pkg/stint
import pkg/nitro
import pkg/questionable
import pkg/upraises
@ -8,6 +9,7 @@ import ./bitswap
export PricingMessage
export StateChannelUpdate
export stint
export nitro
push: {.upraises: [].}

View File

@ -0,0 +1,32 @@
import std/unittest
import pkg/dagger/bitswap/engine/payments
import ../../examples
suite "engine payments":
let amountOfBytes = 42
var wallet: Wallet
var peer: BitswapPeerCtx
setup:
wallet = Wallet.example
peer = BitswapPeerCtx.example
peer.pricing = Pricing.example.some
test "pays for received bytes":
let payment = wallet.pay(peer, amountOfBytes).get
let pricing = peer.pricing.get
let balances = payment.state.outcome.balances(pricing.asset)
let destination = pricing.address.toDestination
check balances[destination].get == amountOfBytes.u256 * pricing.price
test "no payment when no price is set":
peer.pricing = Pricing.none
check wallet.pay(peer, amountOfBytes).isErr
test "uses same channel for consecutive payments":
let payment1, payment2 = wallet.pay(peer, amountOfBytes)
let channel1 = payment1.?state.?channel.?getChannelId
let channel2 = payment2.?state.?channel.?getChannelId
check channel1 == channel2

View File

@ -1,6 +1,11 @@
import std/random
import std/sequtils
import pkg/libp2p
import pkg/nitro
import pkg/dagger/p2p/rng
import pkg/dagger/bitswap/protobuf/payments
import pkg/dagger/bitswap/peercontext
import pkg/dagger/blocktype
proc example*(_: type EthAddress): EthAddress =
EthPrivateKey.random().toPublicKey.toAddress
@ -30,5 +35,17 @@ proc example*(_: type Pricing): Pricing =
Pricing(
address: EthAddress.example,
asset: EthAddress.example,
price: UInt256.example()
price: uint32.example.u256
)
proc example*(_: type Block): Block =
let length = rand(4096)
let bytes = newSeqWith(length, rand(uint8))
Block.new(bytes)
proc example*(_: type PeerId): PeerID =
let key = PrivateKey.random(Rng.instance[]).get
PeerId.init(key.getKey().get).get
proc example*(_: type BitswapPeerCtx): BitswapPeerCtx =
BitswapPeerCtx(id: PeerID.example)

View File

@ -1,7 +1,8 @@
import ./dagger/bitswap/testbitswap
import ./dagger/bitswap/testengine
import ./dagger/bitswap/testnetwork
import ./dagger/bitswap/protobuf/testpayments
import ./dagger/bitswap/protobuf/testpayments as testprotobufpayments
import ./dagger/bitswap/engine/testpayments as testenginepayments
import ./dagger/testasyncheapqueue
import ./dagger/testblockstore
import ./dagger/testchunking