diff --git a/README.md b/README.md index d421e12d..b10b7b66 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Examples of usage of go-waku as a library can be found in the examples folder. T |[15/WAKU2-BRIDGE](https://rfc.vac.dev/spec/15)|⛔| |[16/WAKU2-RPC](https://rfc.vac.dev/spec/16)|🚧| |[17/WAKU2-RLNRELAY](https://rfc.vac.dev/spec/17)|| -|[18/WAKU2-SWAP](https://rfc.vac.dev/spec/18)|| +|[18/WAKU2-SWAP](https://rfc.vac.dev/spec/18)|🚧| |[21/WAKU2-FTSTORE](https://rfc.vac.dev/spec/21)|✔| |[22/TOY-CHAT](https://rfc.vac.dev/spec/22)|✔| |[23/TOPICS](https://rfc.vac.dev/spec/22)|✔| diff --git a/waku/v2/protocol/pb/generate.go b/waku/v2/protocol/pb/generate.go index a75336ee..4e422ed5 100644 --- a/waku/v2/protocol/pb/generate.go +++ b/waku/v2/protocol/pb/generate.go @@ -4,3 +4,4 @@ package pb //go:generate protoc -I. --gofast_out=. ./waku_lightpush.proto //go:generate protoc -I. --gofast_out=. ./waku_message.proto //go:generate protoc -I. --gofast_out=. ./waku_store.proto +//go:generate protoc -I. --gofast_out=. ./waku_swap.proto diff --git a/waku/v2/protocol/pb/waku_swap.pb.go b/waku/v2/protocol/pb/waku_swap.pb.go new file mode 100644 index 00000000..d48b31f1 --- /dev/null +++ b/waku/v2/protocol/pb/waku_swap.pb.go @@ -0,0 +1,687 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: waku_swap.proto + +package pb + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type Cheque struct { + IssuerAddress string `protobuf:"bytes,1,opt,name=issuerAddress,proto3" json:"issuerAddress,omitempty"` + Beneficiary []byte `protobuf:"bytes,2,opt,name=beneficiary,proto3" json:"beneficiary,omitempty"` + Date uint32 `protobuf:"varint,3,opt,name=date,proto3" json:"date,omitempty"` + Amount uint32 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"` + Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Cheque) Reset() { *m = Cheque{} } +func (m *Cheque) String() string { return proto.CompactTextString(m) } +func (*Cheque) ProtoMessage() {} +func (*Cheque) Descriptor() ([]byte, []int) { + return fileDescriptor_8ec987fcc28cf932, []int{0} +} +func (m *Cheque) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Cheque) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Cheque.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Cheque) XXX_Merge(src proto.Message) { + xxx_messageInfo_Cheque.Merge(m, src) +} +func (m *Cheque) XXX_Size() int { + return m.Size() +} +func (m *Cheque) XXX_DiscardUnknown() { + xxx_messageInfo_Cheque.DiscardUnknown(m) +} + +var xxx_messageInfo_Cheque proto.InternalMessageInfo + +func (m *Cheque) GetIssuerAddress() string { + if m != nil { + return m.IssuerAddress + } + return "" +} + +func (m *Cheque) GetBeneficiary() []byte { + if m != nil { + return m.Beneficiary + } + return nil +} + +func (m *Cheque) GetDate() uint32 { + if m != nil { + return m.Date + } + return 0 +} + +func (m *Cheque) GetAmount() uint32 { + if m != nil { + return m.Amount + } + return 0 +} + +func (m *Cheque) GetSignature() []byte { + if m != nil { + return m.Signature + } + return nil +} + +type Handshake struct { + Beneficiary []byte `protobuf:"bytes,1,opt,name=beneficiary,proto3" json:"beneficiary,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Handshake) Reset() { *m = Handshake{} } +func (m *Handshake) String() string { return proto.CompactTextString(m) } +func (*Handshake) ProtoMessage() {} +func (*Handshake) Descriptor() ([]byte, []int) { + return fileDescriptor_8ec987fcc28cf932, []int{1} +} +func (m *Handshake) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Handshake) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Handshake.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Handshake) XXX_Merge(src proto.Message) { + xxx_messageInfo_Handshake.Merge(m, src) +} +func (m *Handshake) XXX_Size() int { + return m.Size() +} +func (m *Handshake) XXX_DiscardUnknown() { + xxx_messageInfo_Handshake.DiscardUnknown(m) +} + +var xxx_messageInfo_Handshake proto.InternalMessageInfo + +func (m *Handshake) GetBeneficiary() []byte { + if m != nil { + return m.Beneficiary + } + return nil +} + +func init() { + proto.RegisterType((*Cheque)(nil), "pb.Cheque") + proto.RegisterType((*Handshake)(nil), "pb.Handshake") +} + +func init() { proto.RegisterFile("waku_swap.proto", fileDescriptor_8ec987fcc28cf932) } + +var fileDescriptor_8ec987fcc28cf932 = []byte{ + // 200 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2f, 0x4f, 0xcc, 0x2e, + 0x8d, 0x2f, 0x2e, 0x4f, 0x2c, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2a, 0x48, 0x52, + 0x9a, 0xc5, 0xc8, 0xc5, 0xe6, 0x9c, 0x91, 0x5a, 0x58, 0x9a, 0x2a, 0xa4, 0xc2, 0xc5, 0x9b, 0x59, + 0x5c, 0x5c, 0x9a, 0x5a, 0xe4, 0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x2c, 0xc1, 0xa8, 0xc0, 0xa8, + 0xc1, 0x19, 0x84, 0x2a, 0x28, 0xa4, 0xc0, 0xc5, 0x9d, 0x94, 0x9a, 0x97, 0x9a, 0x96, 0x99, 0x9c, + 0x99, 0x58, 0x54, 0x29, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1, 0x13, 0x84, 0x2c, 0x24, 0x24, 0xc4, 0xc5, + 0x92, 0x92, 0x58, 0x92, 0x2a, 0xc1, 0xac, 0xc0, 0xa8, 0xc1, 0x1b, 0x04, 0x66, 0x0b, 0x89, 0x71, + 0xb1, 0x25, 0xe6, 0xe6, 0x97, 0xe6, 0x95, 0x48, 0xb0, 0x80, 0x45, 0xa1, 0x3c, 0x21, 0x19, 0x2e, + 0xce, 0xe2, 0xcc, 0xf4, 0xbc, 0xc4, 0x92, 0xd2, 0xa2, 0x54, 0x09, 0x56, 0xb0, 0x59, 0x08, 0x01, + 0x25, 0x5d, 0x2e, 0x4e, 0x8f, 0xc4, 0xbc, 0x94, 0xe2, 0x8c, 0xc4, 0xec, 0x54, 0x74, 0x8b, 0x19, + 0x31, 0x2c, 0x76, 0x12, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, + 0x18, 0x67, 0x3c, 0x96, 0x63, 0x48, 0x62, 0x03, 0x7b, 0xd4, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, + 0xce, 0x34, 0x72, 0xd2, 0xfb, 0x00, 0x00, 0x00, +} + +func (m *Cheque) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Cheque) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Cheque) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Signature) > 0 { + i -= len(m.Signature) + copy(dAtA[i:], m.Signature) + i = encodeVarintWakuSwap(dAtA, i, uint64(len(m.Signature))) + i-- + dAtA[i] = 0x2a + } + if m.Amount != 0 { + i = encodeVarintWakuSwap(dAtA, i, uint64(m.Amount)) + i-- + dAtA[i] = 0x20 + } + if m.Date != 0 { + i = encodeVarintWakuSwap(dAtA, i, uint64(m.Date)) + i-- + dAtA[i] = 0x18 + } + if len(m.Beneficiary) > 0 { + i -= len(m.Beneficiary) + copy(dAtA[i:], m.Beneficiary) + i = encodeVarintWakuSwap(dAtA, i, uint64(len(m.Beneficiary))) + i-- + dAtA[i] = 0x12 + } + if len(m.IssuerAddress) > 0 { + i -= len(m.IssuerAddress) + copy(dAtA[i:], m.IssuerAddress) + i = encodeVarintWakuSwap(dAtA, i, uint64(len(m.IssuerAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Handshake) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Handshake) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Handshake) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Beneficiary) > 0 { + i -= len(m.Beneficiary) + copy(dAtA[i:], m.Beneficiary) + i = encodeVarintWakuSwap(dAtA, i, uint64(len(m.Beneficiary))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintWakuSwap(dAtA []byte, offset int, v uint64) int { + offset -= sovWakuSwap(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Cheque) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.IssuerAddress) + if l > 0 { + n += 1 + l + sovWakuSwap(uint64(l)) + } + l = len(m.Beneficiary) + if l > 0 { + n += 1 + l + sovWakuSwap(uint64(l)) + } + if m.Date != 0 { + n += 1 + sovWakuSwap(uint64(m.Date)) + } + if m.Amount != 0 { + n += 1 + sovWakuSwap(uint64(m.Amount)) + } + l = len(m.Signature) + if l > 0 { + n += 1 + l + sovWakuSwap(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *Handshake) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Beneficiary) + if l > 0 { + n += 1 + l + sovWakuSwap(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovWakuSwap(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozWakuSwap(x uint64) (n int) { + return sovWakuSwap(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Cheque) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Cheque: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Cheque: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IssuerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthWakuSwap + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthWakuSwap + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IssuerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Beneficiary", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthWakuSwap + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthWakuSwap + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Beneficiary = append(m.Beneficiary[:0], dAtA[iNdEx:postIndex]...) + if m.Beneficiary == nil { + m.Beneficiary = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Date", wireType) + } + m.Date = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Date |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + m.Amount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Amount |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signature", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthWakuSwap + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthWakuSwap + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signature = append(m.Signature[:0], dAtA[iNdEx:postIndex]...) + if m.Signature == nil { + m.Signature = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipWakuSwap(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthWakuSwap + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Handshake) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Handshake: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Handshake: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Beneficiary", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthWakuSwap + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthWakuSwap + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Beneficiary = append(m.Beneficiary[:0], dAtA[iNdEx:postIndex]...) + if m.Beneficiary == nil { + m.Beneficiary = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipWakuSwap(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthWakuSwap + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipWakuSwap(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowWakuSwap + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthWakuSwap + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupWakuSwap + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthWakuSwap + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthWakuSwap = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowWakuSwap = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupWakuSwap = fmt.Errorf("proto: unexpected end of group") +) diff --git a/waku/v2/protocol/pb/waku_swap.proto b/waku/v2/protocol/pb/waku_swap.proto new file mode 100644 index 00000000..37f3344a --- /dev/null +++ b/waku/v2/protocol/pb/waku_swap.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package pb; + +message Cheque { + string issuerAddress = 1; + bytes beneficiary = 2; + uint32 date = 3; + uint32 amount = 4; + bytes signature = 5; +} + +message Handshake { + bytes beneficiary = 1; +} \ No newline at end of file diff --git a/waku/v2/protocol/swap/waku_swap.go b/waku/v2/protocol/swap/waku_swap.go new file mode 100644 index 00000000..66ed00a9 --- /dev/null +++ b/waku/v2/protocol/swap/waku_swap.go @@ -0,0 +1,74 @@ +package swap + +import ( + "sync" + + logging "github.com/ipfs/go-log" + + "github.com/libp2p/go-libp2p-core/protocol" +) + +const ( + SoftMode int = 0 + MockMode int = 1 + HardMode int = 2 +) + +const WakuSwapID_v200 = protocol.ID("/vac/waku/swap/2.0.0-beta1") + +var log = logging.Logger("wakuswap") + +type WakuSwap struct { + params *SwapParameters + + Accounting map[string]int + accountingMutex sync.RWMutex +} + +func NewWakuSwap(opts ...SwapOption) *WakuSwap { + params := &SwapParameters{} + + optList := DefaultOptions() + optList = append(optList, opts...) + for _, opt := range optList { + opt(params) + } + + return &WakuSwap{ + params: params, + Accounting: make(map[string]int), + } +} + +func (s *WakuSwap) sendCheque(peerId string) { + log.Debug("not yet implemented") +} + +func (s *WakuSwap) applyPolicy(peerId string) { + if s.Accounting[peerId] <= s.params.disconnectThreshold { + log.Warnf("Disconnect threshhold has been reached for %s at %d", peerId, s.Accounting[peerId]) + } + + if s.Accounting[peerId] >= s.params.paymentThreshold { + log.Warnf("Disconnect threshhold has been reached for %s at %d", peerId, s.Accounting[peerId]) + if s.params.mode != HardMode { + s.sendCheque(peerId) + } + } +} + +func (s *WakuSwap) Credit(peerId string, n int) { + s.accountingMutex.Lock() + defer s.accountingMutex.Unlock() + + s.Accounting[peerId] -= n + s.applyPolicy(peerId) +} + +func (s *WakuSwap) Debit(peerId string, n int) { + s.accountingMutex.Lock() + defer s.accountingMutex.Unlock() + + s.Accounting[peerId] += n + s.applyPolicy(peerId) +} diff --git a/waku/v2/protocol/swap/waku_swap_option.go b/waku/v2/protocol/swap/waku_swap_option.go new file mode 100644 index 00000000..d73a0047 --- /dev/null +++ b/waku/v2/protocol/swap/waku_swap_option.go @@ -0,0 +1,29 @@ +package swap + +type SwapParameters struct { + mode int + paymentThreshold int + disconnectThreshold int +} + +type SwapOption func(*SwapParameters) + +func WithMode(mode int) SwapOption { + return func(params *SwapParameters) { + params.mode = mode + } +} + +func WithThreshold(payment, disconnect int) SwapOption { + return func(params *SwapParameters) { + params.disconnectThreshold = disconnect + params.paymentThreshold = payment + } +} + +func DefaultOptions() []SwapOption { + return []SwapOption{ + WithMode(SoftMode), + WithThreshold(100, -100), + } +} diff --git a/waku/v2/protocol/swap/waku_swap_option_test.go b/waku/v2/protocol/swap/waku_swap_option_test.go new file mode 100644 index 00000000..f1a010db --- /dev/null +++ b/waku/v2/protocol/swap/waku_swap_option_test.go @@ -0,0 +1,24 @@ +package swap + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSwapOption(t *testing.T) { + options := []SwapOption{ + WithMode(SoftMode), + WithThreshold(10, 0), + } + + params := &SwapParameters{} + + for _, opt := range options { + opt(params) + } + + require.Equal(t, SoftMode, params.mode) + require.Equal(t, 10, params.paymentThreshold) + require.Equal(t, 0, params.disconnectThreshold) +} diff --git a/waku/v2/protocol/swap/waku_swap_test.go b/waku/v2/protocol/swap/waku_swap_test.go new file mode 100644 index 00000000..34e7d255 --- /dev/null +++ b/waku/v2/protocol/swap/waku_swap_test.go @@ -0,0 +1,20 @@ +package swap + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSwapCreditDebit(t *testing.T) { + swap := NewWakuSwap([]SwapOption{ + WithMode(SoftMode), + WithThreshold(0, 0), + }...) + + swap.Credit("1", 1) + require.Equal(t, -1, swap.Accounting["1"]) + + swap.Debit("1", 2) + require.Equal(t, 1, swap.Accounting["1"]) +}