From a1bb2c4954e8570b44f23c2883ee28b27982d1cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Thor=C3=A9n?= Date: Fri, 13 Nov 2020 14:02:17 +0800 Subject: [PATCH] Accounting SWAP protocol basic data types and test (#262) * Start of SWAP * SWAP basic data types (untested) * SWAP Add handshake test and fix imports * SWAP Add cheque encode/decode test and fix bug --- tests/all_tests_v2.nim | 3 +- tests/v2/test_waku_swap.nim | 33 +++++++++++++++ waku/node/v2/waku_types.nim | 23 +++++++++-- waku/protocol/v2/waku_swap.nim | 73 ++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 tests/v2/test_waku_swap.nim create mode 100644 waku/protocol/v2/waku_swap.nim diff --git a/tests/all_tests_v2.nim b/tests/all_tests_v2.nim index 1d5b39d9f..5106b93eb 100644 --- a/tests/all_tests_v2.nim +++ b/tests/all_tests_v2.nim @@ -7,4 +7,5 @@ import ./v2/test_waku_filter, ./v2/test_waku_pagination, ./v2/test_waku_payload, - ./v2/test_rpc_waku + ./v2/test_rpc_waku, + ./v2/test_waku_swap diff --git a/tests/v2/test_waku_swap.nim b/tests/v2/test_waku_swap.nim new file mode 100644 index 000000000..f0f5d17eb --- /dev/null +++ b/tests/v2/test_waku_swap.nim @@ -0,0 +1,33 @@ +import + std/[unittest, options, tables, sets], + chronos, chronicles, + ../../waku/protocol/v2/waku_swap, + ../../waku/node/v2/waku_types, + ../test_helpers, ./utils + +procSuite "Waku SWAP Accounting": + test "Handshake Encode/Decode": + let + beneficiary = @[byte 0, 1, 2] + handshake = Handshake(beneficiary: beneficiary) + pb = handshake.encode() + + let decodedHandshake = Handshake.init(pb.buffer) + + check: + decodedHandshake.isErr == false + decodedHandshake.get().beneficiary == beneficiary + + test "Cheque Encode/Decode": + let + amount = 1'u32 + date = 9000'u32 + beneficiary = @[byte 0, 1, 2] + cheque = Cheque(beneficiary: beneficiary, amount: amount, date: date) + pb = cheque.encode() + + let decodedCheque = Cheque.init(pb.buffer) + + check: + decodedCheque.isErr == false + decodedCheque.get() == cheque diff --git a/waku/node/v2/waku_types.nim b/waku/node/v2/waku_types.nim index ac1870997..d1604d805 100644 --- a/waku/node/v2/waku_types.nim +++ b/waku/node/v2/waku_types.nim @@ -12,8 +12,10 @@ import libp2p/stream/connection, libp2p/protocols/pubsub/[pubsub, gossipsub], nimcrypto/sha2 -# constants required for pagination ------------------------------------------- -const MaxPageSize* = 100 # Maximum number of waku messages in each page + +# Constants required for pagination ------------------------------------------- +const MaxPageSize* = 100 # Maximum number of waku messages in each page + # Common data types ----------------------------------------------------------- type ContentTopic* = uint32 @@ -147,8 +149,21 @@ type #multiaddrStrings*: seq[string] WakuResult*[T] = Result[T, cstring] -# Encoding and decoding ------------------------------------------------------- + Beneficiary* = seq[byte] + + # TODO Consider adding payment threshhold and terms field + Handshake* = object + beneficiary*: Beneficiary + + Cheque* = object + beneficiary*: Beneficiary + date*: uint32 + amount*: uint32 + +# Encoding and decoding ------------------------------------------------------- +# TODO Move out to to waku_message module +# Possibly same with util functions proc init*(T: type WakuMessage, buffer: seq[byte]): ProtoResult[T] = var msg = WakuMessage() let pb = initProtoBuffer(buffer) @@ -199,4 +214,4 @@ proc computeIndex*(msg: WakuMessage): Index = ctx.clear() result.digest = digest - result.receivedTime = epochTime() # gets the unix timestamp \ No newline at end of file + result.receivedTime = epochTime() # gets the unix timestamp diff --git a/waku/protocol/v2/waku_swap.nim b/waku/protocol/v2/waku_swap.nim new file mode 100644 index 000000000..cc6f2b15f --- /dev/null +++ b/waku/protocol/v2/waku_swap.nim @@ -0,0 +1,73 @@ +## SWAP implements Accounting for Waku. See +## https://github.com/vacp2p/specs/issues/24 for more. +## +## This is based on the SWAP based approach researched by the Swarm team, and +## can be thought of as an economic extension to Bittorrent's tit-for-tat +## economics. +## +## It is quite suitable for accounting for imbalances between peers, and +## specifically for something like the Store protocol. +## +## It is structured as follows: +## +## 1) First a handshake is made, where terms are agreed upon +## +## 2) Then operation occurs as normal with HistoryRequest, HistoryResponse etc +## through store protocol (or otherwise) +## +## 3) When payment threshhold is met, a cheque is sent. This acts as promise to +## pay. Right now it is best thought of as karma points. +## +## Things like settlement is for future work. +## + +import + std/[tables, sequtils, future, algorithm, options], + bearssl, + chronos, chronicles, metrics, stew/[results,byteutils], + libp2p/switch, + libp2p/crypto/crypto, + libp2p/protocols/protocol, + libp2p/protobuf/minprotobuf, + libp2p/stream/connection, + ./message_notifier, + ./../../node/v2/waku_types + +export waku_types + +logScope: + topics = "wakuswap" + +const WakuSwapCodec* = "/vac/waku/swap/2.0.0-alpha1" + +proc encode*(handshake: Handshake): ProtoBuffer = + result = initProtoBuffer() + result.write(1, handshake.beneficiary) + +proc encode*(cheque: Cheque): ProtoBuffer = + result = initProtoBuffer() + result.write(1, cheque.beneficiary) + result.write(2, cheque.date) + result.write(3, cheque.amount) + +proc init*(T: type Handshake, buffer: seq[byte]): ProtoResult[T] = + var beneficiary: seq[byte] + var handshake = Handshake() + let pb = initProtoBuffer(buffer) + + discard ? pb.getField(1, handshake.beneficiary) + + ok(handshake) + +proc init*(T: type Cheque, buffer: seq[byte]): ProtoResult[T] = + var beneficiary: seq[byte] + var date: uint32 + var amount: uint32 + var cheque = Cheque() + let pb = initProtoBuffer(buffer) + + discard ? pb.getField(1, cheque.beneficiary) + discard ? pb.getField(2, cheque.date) + discard ? pb.getField(3, cheque.amount) + + ok(cheque)