Replace pricing exchange by account exchange
Rationale: price is no longer set per peer, but per chunk. Only the Ethereum accounts of the peers needs to be exchanged.
This commit is contained in:
parent
d4dd15734e
commit
6bd4260911
|
@ -157,8 +157,8 @@ proc new*(
|
|||
blocks: seq[bt.Block]) {.gcsafe.} =
|
||||
engine.blocksHandler(peer, blocks)
|
||||
|
||||
proc pricingHandler(peer: PeerId, pricing: Pricing) =
|
||||
engine.pricingHandler(peer, pricing)
|
||||
proc accountHandler(peer: PeerId, account: Account) =
|
||||
engine.accountHandler(peer, account)
|
||||
|
||||
proc paymentHandler(peer: PeerId, payment: SignedState) =
|
||||
engine.paymentHandler(peer, payment)
|
||||
|
@ -167,7 +167,7 @@ proc new*(
|
|||
onWantList: blockWantListHandler,
|
||||
onBlocks: blocksHandler,
|
||||
onPresence: blockPresenceHandler,
|
||||
onPricing: pricingHandler,
|
||||
onAccount: accountHandler,
|
||||
onPayment: paymentHandler
|
||||
)
|
||||
|
||||
|
|
|
@ -50,6 +50,10 @@ type
|
|||
wallet*: WalletRef # nitro wallet for micropayments
|
||||
pricing*: ?Pricing # optional bandwidth pricing
|
||||
|
||||
Pricing* = object
|
||||
address*: EthAddress
|
||||
price*: UInt256
|
||||
|
||||
proc contains*(a: AsyncHeapQueue[Entry], b: Cid): bool =
|
||||
## Convenience method to check for entry prepense
|
||||
##
|
||||
|
@ -246,21 +250,20 @@ proc wantListHandler*(
|
|||
if not b.scheduleTask(peerCtx):
|
||||
trace "Unable to schedule task for peer", peer
|
||||
|
||||
proc pricingHandler*(engine: BitswapEngine, peer: PeerID, pricing: Pricing) =
|
||||
proc accountHandler*(engine: BitswapEngine, peer: PeerID, account: Account) =
|
||||
let context = engine.getPeerCtx(peer)
|
||||
if context.isNil:
|
||||
return
|
||||
|
||||
context.pricing = pricing.some
|
||||
context.account = account.some
|
||||
|
||||
proc paymentHandler*(engine: BitswapEngine, peer: PeerId, payment: SignedState) =
|
||||
without context =? engine.getPeerCtx(peer).option and
|
||||
contextPricing =? context.pricing and
|
||||
enginePricing =? engine.pricing:
|
||||
account =? context.account:
|
||||
return
|
||||
|
||||
if channel =? context.paymentChannel:
|
||||
let sender = contextPricing.address
|
||||
let sender = account.address
|
||||
discard engine.wallet.acceptPayment(channel, Asset, sender, payment)
|
||||
else:
|
||||
context.paymentChannel = engine.wallet.acceptChannel(payment).option
|
||||
|
@ -280,8 +283,8 @@ proc setupPeer*(b: BitswapEngine, peer: PeerID) =
|
|||
if b.wantList.len > 0:
|
||||
b.request.sendWantList(peer, b.wantList, full = true)
|
||||
|
||||
if pricing =? b.pricing:
|
||||
b.request.sendPricing(peer, pricing)
|
||||
if address =? b.pricing.?address:
|
||||
b.request.sendAccount(peer, Account(address: address))
|
||||
|
||||
proc dropPeer*(b: BitswapEngine, peer: PeerID) =
|
||||
## Cleanup disconnected peer
|
||||
|
|
|
@ -21,20 +21,20 @@ func openLedgerChannel*(wallet: WalletRef,
|
|||
func getOrOpenChannel(wallet: WalletRef, peer: BitswapPeerCtx): ?!ChannelId =
|
||||
if channel =? peer.paymentChannel:
|
||||
success channel
|
||||
elif pricing =? peer.pricing:
|
||||
let channel = ?wallet.openLedgerChannel(pricing.address, Asset)
|
||||
elif account =? peer.account:
|
||||
let channel = ?wallet.openLedgerChannel(account.address, Asset)
|
||||
peer.paymentChannel = channel.some
|
||||
success channel
|
||||
else:
|
||||
failure "no pricing set for peer"
|
||||
failure "no account set for peer"
|
||||
|
||||
func pay*(wallet: WalletRef,
|
||||
peer: BitswapPeerCtx,
|
||||
amount: UInt256): ?!SignedState =
|
||||
if pricing =? peer.pricing:
|
||||
if account =? peer.account:
|
||||
let asset = Asset
|
||||
let receiver = pricing.address
|
||||
let receiver = account.address
|
||||
let channel = ?wallet.getOrOpenChannel(peer)
|
||||
wallet.pay(channel, asset, receiver, amount)
|
||||
else:
|
||||
failure "no pricing set for peer"
|
||||
failure "no account set for peer"
|
||||
|
|
|
@ -31,14 +31,14 @@ type
|
|||
WantListHandler* = proc(peer: PeerID, wantList: WantList) {.gcsafe.}
|
||||
BlocksHandler* = proc(peer: PeerID, blocks: seq[bt.Block]) {.gcsafe.}
|
||||
BlockPresenceHandler* = proc(peer: PeerID, precense: seq[BlockPresence]) {.gcsafe.}
|
||||
PricingHandler* = proc(peer: PeerID, pricing: Pricing) {.gcsafe.}
|
||||
AccountHandler* = proc(peer: PeerID, account: Account) {.gcsafe.}
|
||||
PaymentHandler* = proc(peer: PeerID, payment: SignedState) {.gcsafe.}
|
||||
|
||||
BitswapHandlers* = object
|
||||
onWantList*: WantListHandler
|
||||
onBlocks*: BlocksHandler
|
||||
onPresence*: BlockPresenceHandler
|
||||
onPricing*: PricingHandler
|
||||
onAccount*: AccountHandler
|
||||
onPayment*: PaymentHandler
|
||||
|
||||
WantListBroadcaster* = proc(
|
||||
|
@ -52,14 +52,14 @@ type
|
|||
|
||||
BlocksBroadcaster* = proc(peer: PeerID, presence: seq[bt.Block]) {.gcsafe.}
|
||||
PresenceBroadcaster* = proc(peer: PeerID, presence: seq[BlockPresence]) {.gcsafe.}
|
||||
PricingBroadcaster* = proc(peer: PeerID, pricing: Pricing) {.gcsafe.}
|
||||
AccountBroadcaster* = proc(peer: PeerID, account: Account) {.gcsafe.}
|
||||
PaymentBroadcaster* = proc(peer: PeerID, payment: SignedState) {.gcsafe.}
|
||||
|
||||
BitswapRequest* = object
|
||||
sendWantList*: WantListBroadcaster
|
||||
sendBlocks*: BlocksBroadcaster
|
||||
sendPresence*: PresenceBroadcaster
|
||||
sendPricing*: PricingBroadcaster
|
||||
sendAccount*: AccountBroadcaster
|
||||
sendPayment*: PaymentBroadcaster
|
||||
|
||||
BitswapNetwork* = ref object of LPProtocol
|
||||
|
@ -202,20 +202,20 @@ proc broadcastBlockPresence*(
|
|||
trace "Sending presence to peer", peer = id
|
||||
asyncSpawn b.peers[id].send(Message(blockPresences: presence))
|
||||
|
||||
proc handlePricing(network: BitswapNetwork,
|
||||
proc handleAccount(network: BitswapNetwork,
|
||||
peer: NetworkPeer,
|
||||
pricing: Pricing) =
|
||||
if network.handlers.onPricing.isNil:
|
||||
account: Account) =
|
||||
if network.handlers.onAccount.isNil:
|
||||
return
|
||||
network.handlers.onPricing(peer.id, pricing)
|
||||
network.handlers.onAccount(peer.id, account)
|
||||
|
||||
proc broadcastPricing*(network: BitswapNetwork,
|
||||
id: PeerId,
|
||||
pricing: Pricing) =
|
||||
proc broadcastAccount*(network: BitswapNetwork,
|
||||
id: PeerId,
|
||||
account: Account) =
|
||||
if id notin network.peers:
|
||||
return
|
||||
|
||||
let message = Message(pricing: PricingMessage.init(pricing))
|
||||
let message = Message(account: AccountMessage.init(account))
|
||||
asyncSpawn network.peers[id].send(message)
|
||||
|
||||
proc broadcastPayment*(network: BitswapNetwork,
|
||||
|
@ -248,8 +248,8 @@ proc rpcHandler(b: BitswapNetwork, peer: NetworkPeer, msg: Message) {.async.} =
|
|||
if msg.blockPresences.len > 0:
|
||||
b.handleBlockPresence(peer, msg.blockPresences)
|
||||
|
||||
if pricing =? Pricing.init(msg.pricing):
|
||||
b.handlePricing(peer, pricing)
|
||||
if account =? Account.init(msg.account):
|
||||
b.handleAccount(peer, account)
|
||||
|
||||
if payment =? SignedState.init(msg.payment):
|
||||
b.handlePayment(peer, payment)
|
||||
|
@ -347,8 +347,8 @@ proc new*(
|
|||
proc sendPresence(id: PeerID, presence: seq[BlockPresence]) {.gcsafe.} =
|
||||
b.broadcastBlockPresence(id, presence)
|
||||
|
||||
proc sendPricing(id: PeerID, pricing: Pricing) =
|
||||
b.broadcastPricing(id, pricing)
|
||||
proc sendAccount(id: PeerID, account: Account) =
|
||||
b.broadcastAccount(id, account)
|
||||
|
||||
proc sendPayment(id: PeerID, payment: SignedState) =
|
||||
b.broadcastPayment(id, payment)
|
||||
|
@ -357,7 +357,7 @@ proc new*(
|
|||
sendWantList: sendWantList,
|
||||
sendBlocks: sendBlocks,
|
||||
sendPresence: sendPresence,
|
||||
sendPricing: sendPricing,
|
||||
sendAccount: sendAccount,
|
||||
sendPayment: sendPayment
|
||||
)
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ type
|
|||
peerWants*: seq[Entry] # remote peers want lists
|
||||
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
|
||||
account*: ?Account # ethereum account of this peer
|
||||
paymentChannel*: ?ChannelId # payment channel id
|
||||
|
||||
proc peerHave*(context: BitswapPeerCtx): seq[Cid] =
|
||||
|
|
|
@ -17,7 +17,7 @@ import_proto3 "message.proto"
|
|||
export Message
|
||||
export Wantlist, WantType, Entry
|
||||
export Block, BlockPresenceType, BlockPresence
|
||||
export PricingMessage, StateChannelUpdate
|
||||
export AccountMessage, StateChannelUpdate
|
||||
|
||||
proc hash*(e: Entry): Hash =
|
||||
hash(e.`block`)
|
||||
|
|
|
@ -35,12 +35,11 @@ message Message {
|
|||
message BlockPresence {
|
||||
bytes cid = 1;
|
||||
BlockPresenceType type = 2;
|
||||
bytes price = 3; // Amount of assets to pay per byte (UInt256)
|
||||
bytes price = 3; // Amount of assets to pay for the block (UInt256)
|
||||
}
|
||||
|
||||
message PricingMessage {
|
||||
bytes address = 1; // Ethereum address to which payments should be made
|
||||
bytes price = 3; // Amount of assets to pay per byte (UInt256)
|
||||
message AccountMessage {
|
||||
bytes address = 1; // Ethereum address to which payments should be made
|
||||
}
|
||||
|
||||
message StateChannelUpdate {
|
||||
|
@ -52,6 +51,6 @@ message Message {
|
|||
repeated Block payload = 3; // used to send Blocks in bitswap 1.1.0
|
||||
repeated BlockPresence blockPresences = 4;
|
||||
int32 pendingBytes = 5;
|
||||
PricingMessage pricing = 6;
|
||||
AccountMessage account = 6;
|
||||
StateChannelUpdate payment = 7;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import pkg/questionable
|
|||
import pkg/upraises
|
||||
import ./bitswap
|
||||
|
||||
export PricingMessage
|
||||
export AccountMessage
|
||||
export StateChannelUpdate
|
||||
|
||||
export stint
|
||||
|
@ -15,15 +15,11 @@ export nitro
|
|||
push: {.upraises: [].}
|
||||
|
||||
type
|
||||
Pricing* = object
|
||||
Account* = object
|
||||
address*: EthAddress
|
||||
price*: UInt256
|
||||
|
||||
func init*(_: type PricingMessage, pricing: Pricing): PricingMessage =
|
||||
PricingMessage(
|
||||
address: @(pricing.address.toArray),
|
||||
price: @(pricing.price.toBytesBE)
|
||||
)
|
||||
func init*(_: type AccountMessage, account: Account): AccountMessage =
|
||||
AccountMessage(address: @(account.address.toArray))
|
||||
|
||||
func parse(_: type EthAddress, bytes: seq[byte]): ?EthAddress =
|
||||
var address: array[20, byte]
|
||||
|
@ -33,16 +29,10 @@ func parse(_: type EthAddress, bytes: seq[byte]): ?EthAddress =
|
|||
address[i] = bytes[i]
|
||||
EthAddress(address).some
|
||||
|
||||
func parse(_: type UInt256, bytes: seq[byte]): ?UInt256 =
|
||||
if bytes.len > 32:
|
||||
return UInt256.none
|
||||
UInt256.fromBytesBE(bytes).some
|
||||
|
||||
func init*(_: type Pricing, message: PricingMessage): ?Pricing =
|
||||
without address =? EthAddress.parse(message.address) and
|
||||
price =? UInt256.parse(message.price):
|
||||
return Pricing.none
|
||||
Pricing(address: address, price: price).some
|
||||
func init*(_: type Account, message: AccountMessage): ?Account =
|
||||
without address =? EthAddress.parse(message.address):
|
||||
return none Account
|
||||
some Account(address: address)
|
||||
|
||||
func init*(_: type StateChannelUpdate, state: SignedState): StateChannelUpdate =
|
||||
StateChannelUpdate(update: state.toJson.toBytes)
|
||||
|
|
|
@ -4,6 +4,7 @@ import ../../examples
|
|||
|
||||
suite "engine payments":
|
||||
|
||||
let address = EthAddress.example
|
||||
let amount = 42.u256
|
||||
|
||||
var wallet: WalletRef
|
||||
|
@ -12,17 +13,16 @@ suite "engine payments":
|
|||
setup:
|
||||
wallet = WalletRef.example
|
||||
peer = BitswapPeerCtx.example
|
||||
peer.pricing = Pricing.example.some
|
||||
peer.account = Account(address: address).some
|
||||
|
||||
test "pays for received blocks":
|
||||
let payment = !wallet.pay(peer, amount)
|
||||
let pricing = !peer.pricing
|
||||
let balances = payment.state.outcome.balances(Asset)
|
||||
let destination = pricing.address.toDestination
|
||||
let destination = address.toDestination
|
||||
check !balances[destination] == amount
|
||||
|
||||
test "no payment when no price is set":
|
||||
peer.pricing = Pricing.none
|
||||
test "no payment when no account is set":
|
||||
peer.account = Account.none
|
||||
check wallet.pay(peer, amount).isFailure
|
||||
|
||||
test "uses same channel for consecutive payments":
|
||||
|
|
|
@ -4,34 +4,21 @@ import pkg/stew/byteutils
|
|||
import ../../examples
|
||||
import ../../../../dagger/bitswap/protobuf/payments
|
||||
|
||||
suite "pricing protobuf messages":
|
||||
suite "account protobuf messages":
|
||||
|
||||
let address = EthAddress.example
|
||||
let price = UInt256.example
|
||||
let pricing = Pricing(address: address, price: price)
|
||||
let message = PricingMessage.init(pricing)
|
||||
let account = Account(address: EthAddress.example)
|
||||
let message = AccountMessage.init(account)
|
||||
|
||||
test "encodes recipient of payments":
|
||||
check message.address == @(address.toArray)
|
||||
|
||||
test "encodes price per byte":
|
||||
check message.price == @(price.toBytesBE)
|
||||
check message.address == @(account.address.toArray)
|
||||
|
||||
test "decodes recipient of payments":
|
||||
check Pricing.init(message).?address == address.some
|
||||
|
||||
test "decodes price":
|
||||
check Pricing.init(message).?price == price.some
|
||||
check Account.init(message).?address == account.address.some
|
||||
|
||||
test "fails to decode when address has incorrect number of bytes":
|
||||
var incorrect = message
|
||||
incorrect.address.del(0)
|
||||
check Pricing.init(incorrect).isNone
|
||||
|
||||
test "fails to decode when price has too many bytes":
|
||||
var incorrect = message
|
||||
incorrect.price = newSeq[byte](33)
|
||||
check Pricing.init(incorrect).isNone
|
||||
check Account.init(incorrect).isNone
|
||||
|
||||
suite "channel update messages":
|
||||
|
||||
|
|
|
@ -103,9 +103,9 @@ suite "Bitswap engine - 2 nodes":
|
|||
peerCtx2.peerHave.mapIt( $it ).sorted(cmp[string]) ==
|
||||
bitswap1.engine.wantList.mapIt( $it ).sorted(cmp[string])
|
||||
|
||||
test "exchanges pricing on connect":
|
||||
check peerCtx1.pricing == pricing1.some
|
||||
check peerCtx2.pricing == pricing2.some
|
||||
test "exchanges accounts on connect":
|
||||
check peerCtx1.account.?address == pricing1.address.some
|
||||
check peerCtx2.account.?address == pricing2.address.some
|
||||
|
||||
test "should send want-have for block":
|
||||
let blk = bt.Block.new("Block 1".toBytes)
|
||||
|
@ -152,7 +152,6 @@ suite "Bitswap engine - 2 nodes":
|
|||
|
||||
test "receives payments for blocks that were sent":
|
||||
let blocks = await bitswap1.getBlocks(blocks2.mapIt(it.cid))
|
||||
let pricing = !bitswap2.engine.pricing
|
||||
await sleepAsync(100.millis)
|
||||
let channel = !peerCtx1.paymentChannel
|
||||
check wallet2.balance(channel, Asset) > 0
|
||||
|
|
|
@ -57,14 +57,14 @@ suite "Bitswap engine basic":
|
|||
|
||||
await done
|
||||
|
||||
test "sends pricing to new peers":
|
||||
test "sends account to new peers":
|
||||
let pricing = Pricing.example
|
||||
|
||||
proc sendPricing(peer: PeerID, toBeSent: Pricing) =
|
||||
check toBeSent == pricing
|
||||
proc sendAccount(peer: PeerID, account: Account) =
|
||||
check account.address == pricing.address
|
||||
done.complete()
|
||||
|
||||
let request = BitswapRequest(sendPricing: sendPricing)
|
||||
let request = BitswapRequest(sendAccount: sendAccount)
|
||||
let engine = BitswapEngine.new(MemoryStore.new, wallet, request)
|
||||
engine.pricing = pricing.some
|
||||
|
||||
|
@ -153,16 +153,16 @@ suite "Bitswap engine handlers":
|
|||
check engine.localStore.hasBlock(b.cid)
|
||||
|
||||
test "sends payments for received blocks":
|
||||
let pricing = Pricing.example
|
||||
let account = Account(address: EthAddress.example)
|
||||
let peerContext = engine.getPeerCtx(peerId)
|
||||
peerContext.pricing = pricing.some
|
||||
peerContext.account = account.some
|
||||
peerContext.peerPrices = blocks.mapIt((it.cid, rand(uint16).u256)).toTable
|
||||
|
||||
engine.request.sendPayment = proc(receiver: PeerID, payment: SignedState) =
|
||||
let amount = blocks.mapIt(peerContext.peerPrices[it.cid]).foldl(a+b)
|
||||
let balances = !payment.state.outcome.balances(Asset)
|
||||
check receiver == peerId
|
||||
check balances[pricing.address.toDestination] == amount
|
||||
check balances[account.address.toDestination] == amount
|
||||
done.complete()
|
||||
|
||||
engine.blocksHandler(peerId, blocks)
|
||||
|
|
|
@ -103,16 +103,16 @@ suite "Bitswap network":
|
|||
|
||||
await done.wait(500.millis)
|
||||
|
||||
test "handles pricing messages":
|
||||
let pricing = Pricing.example
|
||||
test "handles account messages":
|
||||
let account = Account(address: EthAddress.example)
|
||||
|
||||
proc handlePricing(peer: PeerID, received: Pricing) =
|
||||
check received == pricing
|
||||
proc handleAccount(peer: PeerID, received: Account) =
|
||||
check received == account
|
||||
done.complete()
|
||||
|
||||
network.handlers.onPricing = handlePricing
|
||||
network.handlers.onAccount = handleAccount
|
||||
|
||||
let message = Message(pricing: PricingMessage.init(pricing))
|
||||
let message = Message(account: AccountMessage.init(account))
|
||||
await buffer.pushData(lenPrefix(Protobuf.encode(message)))
|
||||
|
||||
await done.wait(100.millis)
|
||||
|
@ -224,16 +224,16 @@ suite "Bitswap Network - e2e":
|
|||
|
||||
await done.wait(500.millis)
|
||||
|
||||
test "broadcasts pricing":
|
||||
let pricing = Pricing.example
|
||||
test "broadcasts account":
|
||||
let account = Account(address: EthAddress.example)
|
||||
|
||||
proc handlePricing(peer: PeerID, received: Pricing) =
|
||||
check received == pricing
|
||||
proc handleAccount(peer: PeerID, received: Account) =
|
||||
check received == account
|
||||
done.complete()
|
||||
|
||||
network2.handlers.onPricing = handlePricing
|
||||
network2.handlers.onAccount = handleAccount
|
||||
|
||||
network1.broadcastPricing(switch2.peerInfo.peerId, pricing)
|
||||
network1.broadcastAccount(switch2.peerInfo.peerId, account)
|
||||
|
||||
await done.wait(100.millis)
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import pkg/nitro
|
|||
import pkg/dagger/p2p/rng
|
||||
import pkg/dagger/bitswap/protobuf/payments
|
||||
import pkg/dagger/bitswap/peercontext
|
||||
import pkg/dagger/bitswap/engine
|
||||
import pkg/dagger/blocktype
|
||||
|
||||
proc example*(_: type EthAddress): EthAddress =
|
||||
|
|
Loading…
Reference in New Issue