From bdf9aa09ee9cb538cff103fc1e6443cd00a1cc84 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Wed, 13 Dec 2023 14:29:02 -0500 Subject: [PATCH 01/29] Update doc comment --- x/subscription/keeper/subscription.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 2cdeab4956..26004205e3 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -111,7 +111,9 @@ func (k Keeper) CreateSubscription( // What: find plan, update duration (total and remaining), calculate price, // charge fees, save subscription. // - // Subscription upgrade: (TBD) + // Subscription upgrade: + // When: if already exists and existing plan, and new plan's price is higher than current plan's + // What: find subscription, check for sufficient funds, upgrade. // // Subscription downgrade: (TBD) From fc5c862d28e50187044afa351bd87a566bcb004c Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Wed, 13 Dec 2023 14:07:55 -0500 Subject: [PATCH 02/29] Add the FutureSubscription message to Subscripttion --- .../lava/subscription/subscription.proto | 7 + x/subscription/types/subscription.pb.go | 383 ++++++++++++++++-- 2 files changed, 351 insertions(+), 39 deletions(-) diff --git a/proto/lavanet/lava/subscription/subscription.proto b/proto/lavanet/lava/subscription/subscription.proto index 8f6c09e554..02ff434562 100644 --- a/proto/lavanet/lava/subscription/subscription.proto +++ b/proto/lavanet/lava/subscription/subscription.proto @@ -19,4 +19,11 @@ message Subscription { string cluster = 13; // cluster key uint64 duration_total = 14; // continous subscription usage bool auto_renewal = 15; // automatic renewal when the subscription expires + FutureSubscription future_subscription = 16; // future subscription made with buy --advance-purchase } + +message FutureSubscription { + string plan_index = 1; // index (name) of plan + uint64 plan_block = 2; // when the plan was created + uint64 duration_bought = 3; // total requested duration in months +} \ No newline at end of file diff --git a/x/subscription/types/subscription.pb.go b/x/subscription/types/subscription.pb.go index b1e9401ad6..51e91ab16e 100644 --- a/x/subscription/types/subscription.pb.go +++ b/x/subscription/types/subscription.pb.go @@ -23,19 +23,20 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Subscription struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - Consumer string `protobuf:"bytes,2,opt,name=consumer,proto3" json:"consumer,omitempty"` - Block uint64 `protobuf:"varint,3,opt,name=block,proto3" json:"block,omitempty"` - PlanIndex string `protobuf:"bytes,4,opt,name=plan_index,json=planIndex,proto3" json:"plan_index,omitempty"` - PlanBlock uint64 `protobuf:"varint,5,opt,name=plan_block,json=planBlock,proto3" json:"plan_block,omitempty"` - DurationBought uint64 `protobuf:"varint,6,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` - DurationLeft uint64 `protobuf:"varint,7,opt,name=duration_left,json=durationLeft,proto3" json:"duration_left,omitempty"` - MonthExpiryTime uint64 `protobuf:"varint,8,opt,name=month_expiry_time,json=monthExpiryTime,proto3" json:"month_expiry_time,omitempty"` - MonthCuTotal uint64 `protobuf:"varint,10,opt,name=month_cu_total,json=monthCuTotal,proto3" json:"month_cu_total,omitempty"` - MonthCuLeft uint64 `protobuf:"varint,11,opt,name=month_cu_left,json=monthCuLeft,proto3" json:"month_cu_left,omitempty"` - Cluster string `protobuf:"bytes,13,opt,name=cluster,proto3" json:"cluster,omitempty"` - DurationTotal uint64 `protobuf:"varint,14,opt,name=duration_total,json=durationTotal,proto3" json:"duration_total,omitempty"` - AutoRenewal bool `protobuf:"varint,15,opt,name=auto_renewal,json=autoRenewal,proto3" json:"auto_renewal,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Consumer string `protobuf:"bytes,2,opt,name=consumer,proto3" json:"consumer,omitempty"` + Block uint64 `protobuf:"varint,3,opt,name=block,proto3" json:"block,omitempty"` + PlanIndex string `protobuf:"bytes,4,opt,name=plan_index,json=planIndex,proto3" json:"plan_index,omitempty"` + PlanBlock uint64 `protobuf:"varint,5,opt,name=plan_block,json=planBlock,proto3" json:"plan_block,omitempty"` + DurationBought uint64 `protobuf:"varint,6,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` + DurationLeft uint64 `protobuf:"varint,7,opt,name=duration_left,json=durationLeft,proto3" json:"duration_left,omitempty"` + MonthExpiryTime uint64 `protobuf:"varint,8,opt,name=month_expiry_time,json=monthExpiryTime,proto3" json:"month_expiry_time,omitempty"` + MonthCuTotal uint64 `protobuf:"varint,10,opt,name=month_cu_total,json=monthCuTotal,proto3" json:"month_cu_total,omitempty"` + MonthCuLeft uint64 `protobuf:"varint,11,opt,name=month_cu_left,json=monthCuLeft,proto3" json:"month_cu_left,omitempty"` + Cluster string `protobuf:"bytes,13,opt,name=cluster,proto3" json:"cluster,omitempty"` + DurationTotal uint64 `protobuf:"varint,14,opt,name=duration_total,json=durationTotal,proto3" json:"duration_total,omitempty"` + AutoRenewal bool `protobuf:"varint,15,opt,name=auto_renewal,json=autoRenewal,proto3" json:"auto_renewal,omitempty"` + FutureSubscription *FutureSubscription `protobuf:"bytes,16,opt,name=future_subscription,json=futureSubscription,proto3" json:"future_subscription,omitempty"` } func (m *Subscription) Reset() { *m = Subscription{} } @@ -162,8 +163,76 @@ func (m *Subscription) GetAutoRenewal() bool { return false } +func (m *Subscription) GetFutureSubscription() *FutureSubscription { + if m != nil { + return m.FutureSubscription + } + return nil +} + +type FutureSubscription struct { + PlanIndex string `protobuf:"bytes,1,opt,name=plan_index,json=planIndex,proto3" json:"plan_index,omitempty"` + PlanBlock uint64 `protobuf:"varint,2,opt,name=plan_block,json=planBlock,proto3" json:"plan_block,omitempty"` + DurationBought uint64 `protobuf:"varint,3,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` +} + +func (m *FutureSubscription) Reset() { *m = FutureSubscription{} } +func (m *FutureSubscription) String() string { return proto.CompactTextString(m) } +func (*FutureSubscription) ProtoMessage() {} +func (*FutureSubscription) Descriptor() ([]byte, []int) { + return fileDescriptor_c3bc5507ca237d79, []int{1} +} +func (m *FutureSubscription) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FutureSubscription) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FutureSubscription.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 *FutureSubscription) XXX_Merge(src proto.Message) { + xxx_messageInfo_FutureSubscription.Merge(m, src) +} +func (m *FutureSubscription) XXX_Size() int { + return m.Size() +} +func (m *FutureSubscription) XXX_DiscardUnknown() { + xxx_messageInfo_FutureSubscription.DiscardUnknown(m) +} + +var xxx_messageInfo_FutureSubscription proto.InternalMessageInfo + +func (m *FutureSubscription) GetPlanIndex() string { + if m != nil { + return m.PlanIndex + } + return "" +} + +func (m *FutureSubscription) GetPlanBlock() uint64 { + if m != nil { + return m.PlanBlock + } + return 0 +} + +func (m *FutureSubscription) GetDurationBought() uint64 { + if m != nil { + return m.DurationBought + } + return 0 +} + func init() { proto.RegisterType((*Subscription)(nil), "lavanet.lava.subscription.Subscription") + proto.RegisterType((*FutureSubscription)(nil), "lavanet.lava.subscription.FutureSubscription") } func init() { @@ -171,32 +240,35 @@ func init() { } var fileDescriptor_c3bc5507ca237d79 = []byte{ - // 391 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x92, 0xc1, 0xae, 0xd2, 0x40, - 0x14, 0x86, 0xa9, 0xb7, 0xf7, 0x52, 0x0e, 0x2d, 0xe0, 0xc4, 0xc5, 0x68, 0x62, 0x83, 0xa8, 0x91, - 0x18, 0x52, 0x16, 0xbe, 0x01, 0x46, 0x13, 0x89, 0xab, 0xca, 0xca, 0x4d, 0x33, 0x2d, 0x03, 0x34, - 0xb6, 0x9d, 0x66, 0x3a, 0xa3, 0xf0, 0x16, 0x3e, 0x96, 0x0b, 0x17, 0x2c, 0x5d, 0x1a, 0x78, 0x91, - 0x9b, 0x39, 0x2d, 0x0d, 0xac, 0x26, 0xe7, 0x3b, 0xdf, 0xdf, 0xd3, 0x99, 0x1c, 0x98, 0x65, 0xec, - 0x27, 0x2b, 0xb8, 0x9a, 0x9b, 0x73, 0x5e, 0xe9, 0xb8, 0x4a, 0x64, 0x5a, 0xaa, 0x54, 0x14, 0x37, - 0x45, 0x50, 0x4a, 0xa1, 0x04, 0x79, 0xde, 0xd8, 0x81, 0x39, 0x83, 0x6b, 0x61, 0xf2, 0xf7, 0x0e, - 0xdc, 0x6f, 0x57, 0x80, 0x50, 0xe8, 0x26, 0x92, 0x33, 0x25, 0x24, 0xb5, 0xc6, 0xd6, 0xb4, 0x17, - 0x5e, 0x4a, 0xf2, 0x02, 0x9c, 0x44, 0x14, 0x95, 0xce, 0xb9, 0xa4, 0x4f, 0xb0, 0xd5, 0xd6, 0xe4, - 0x19, 0xdc, 0xc7, 0x99, 0x48, 0x7e, 0xd0, 0xbb, 0xb1, 0x35, 0xb5, 0xc3, 0xba, 0x20, 0x2f, 0x01, - 0xca, 0x8c, 0x15, 0x51, 0x5a, 0xac, 0xf9, 0x9e, 0xda, 0x98, 0xe9, 0x19, 0xf2, 0xc5, 0x80, 0xb6, - 0x5d, 0x27, 0xef, 0x31, 0x89, 0xed, 0x05, 0xa6, 0xdf, 0xc1, 0x70, 0xad, 0x25, 0x33, 0x7f, 0x15, - 0xc5, 0x42, 0x6f, 0x77, 0x8a, 0x3e, 0xa0, 0x33, 0xb8, 0xe0, 0x05, 0x52, 0xf2, 0x1a, 0xbc, 0x56, - 0xcc, 0xf8, 0x46, 0xd1, 0x2e, 0x6a, 0xee, 0x05, 0x7e, 0xe5, 0x1b, 0x45, 0xde, 0xc3, 0xd3, 0x5c, - 0x14, 0x6a, 0x17, 0xf1, 0x7d, 0x99, 0xca, 0x43, 0xa4, 0xd2, 0x9c, 0x53, 0x07, 0xc5, 0x21, 0x36, - 0x3e, 0x21, 0x5f, 0xa5, 0x39, 0x27, 0x6f, 0x60, 0x50, 0xbb, 0x89, 0x8e, 0x94, 0x50, 0x2c, 0xa3, - 0x50, 0x7f, 0x11, 0xe9, 0x47, 0xbd, 0x32, 0x8c, 0x4c, 0xc0, 0x6b, 0x2d, 0x1c, 0xdb, 0x47, 0xa9, - 0xdf, 0x48, 0x38, 0xd5, 0xbc, 0x66, 0xa6, 0x2b, 0xc5, 0x25, 0xf5, 0x9a, 0xd7, 0xac, 0x4b, 0xf2, - 0x16, 0xda, 0x6b, 0x34, 0x33, 0x06, 0x18, 0x6f, 0xaf, 0x52, 0x0f, 0x79, 0x05, 0x2e, 0xd3, 0x4a, - 0x44, 0x92, 0x17, 0xfc, 0x17, 0xcb, 0xe8, 0x70, 0x6c, 0x4d, 0x9d, 0xb0, 0x6f, 0x58, 0x58, 0xa3, - 0xa5, 0xed, 0xf4, 0x46, 0xb0, 0xb4, 0x1d, 0x77, 0xe4, 0x2d, 0x3e, 0xff, 0x39, 0xf9, 0xd6, 0xf1, - 0xe4, 0x5b, 0xff, 0x4f, 0xbe, 0xf5, 0xfb, 0xec, 0x77, 0x8e, 0x67, 0xbf, 0xf3, 0xef, 0xec, 0x77, - 0xbe, 0xcf, 0xb6, 0xa9, 0xda, 0xe9, 0x38, 0x48, 0x44, 0x3e, 0xbf, 0x59, 0x9e, 0xfd, 0xed, 0xfa, - 0xa8, 0x43, 0xc9, 0xab, 0xf8, 0x01, 0x17, 0xe7, 0xc3, 0x63, 0x00, 0x00, 0x00, 0xff, 0xff, 0xea, - 0x29, 0x17, 0x34, 0x68, 0x02, 0x00, 0x00, + // 447 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xb3, 0xad, 0xdb, 0x3a, 0x93, 0xbf, 0x2c, 0x1c, 0x16, 0x24, 0xac, 0x10, 0x40, 0x44, + 0xa8, 0x38, 0x12, 0xbc, 0x41, 0x10, 0x95, 0xa8, 0x38, 0x99, 0x9e, 0x38, 0x60, 0xd9, 0xee, 0xa6, + 0xb1, 0xb0, 0xbd, 0xd6, 0x7a, 0x16, 0x52, 0xf1, 0x12, 0x3c, 0x08, 0x0f, 0xc2, 0xb1, 0x47, 0x8e, + 0x28, 0x79, 0x11, 0xe4, 0x71, 0x62, 0x39, 0x04, 0x50, 0x4f, 0xab, 0xf9, 0xcd, 0xf7, 0x79, 0xbc, + 0xfb, 0x69, 0xe0, 0x34, 0x09, 0x3e, 0x07, 0x99, 0xc4, 0x69, 0x79, 0x4e, 0x0b, 0x13, 0x16, 0x91, + 0x8e, 0x73, 0x8c, 0x55, 0xb6, 0x53, 0xb8, 0xb9, 0x56, 0xa8, 0xf8, 0xfd, 0x8d, 0xda, 0x2d, 0x4f, + 0xb7, 0x29, 0x18, 0x7f, 0xb7, 0xa0, 0xfb, 0xbe, 0x01, 0xb8, 0x80, 0x93, 0x48, 0xcb, 0x00, 0x95, + 0x16, 0x6c, 0xc4, 0x26, 0x6d, 0x6f, 0x5b, 0xf2, 0x07, 0x60, 0x47, 0x2a, 0x2b, 0x4c, 0x2a, 0xb5, + 0x38, 0xa0, 0x56, 0x5d, 0xf3, 0x7b, 0x70, 0x14, 0x26, 0x2a, 0xfa, 0x24, 0x0e, 0x47, 0x6c, 0x62, + 0x79, 0x55, 0xc1, 0x1f, 0x02, 0xe4, 0x49, 0x90, 0xf9, 0x71, 0x76, 0x29, 0x97, 0xc2, 0x22, 0x4f, + 0xbb, 0x24, 0x6f, 0x4b, 0x50, 0xb7, 0x2b, 0xe7, 0x11, 0x39, 0xa9, 0x3d, 0x23, 0xf7, 0x33, 0x18, + 0x5c, 0x1a, 0x1d, 0x94, 0x7f, 0xe5, 0x87, 0xca, 0x5c, 0x2d, 0x50, 0x1c, 0x93, 0xa6, 0xbf, 0xc5, + 0x33, 0xa2, 0xfc, 0x31, 0xf4, 0x6a, 0x61, 0x22, 0xe7, 0x28, 0x4e, 0x48, 0xd6, 0xdd, 0xc2, 0x77, + 0x72, 0x8e, 0xfc, 0x39, 0xdc, 0x49, 0x55, 0x86, 0x0b, 0x5f, 0x2e, 0xf3, 0x58, 0x5f, 0xfb, 0x18, + 0xa7, 0x52, 0xd8, 0x24, 0x1c, 0x50, 0xe3, 0x0d, 0xf1, 0x8b, 0x38, 0x95, 0xfc, 0x09, 0xf4, 0x2b, + 0x6d, 0x64, 0x7c, 0x54, 0x18, 0x24, 0x02, 0xaa, 0x2f, 0x12, 0x7d, 0x6d, 0x2e, 0x4a, 0xc6, 0xc7, + 0xd0, 0xab, 0x55, 0x34, 0xb6, 0x43, 0xa2, 0xce, 0x46, 0x44, 0x53, 0xcb, 0xd7, 0x4c, 0x4c, 0x81, + 0x52, 0x8b, 0xde, 0xe6, 0x35, 0xab, 0x92, 0x3f, 0x85, 0xfa, 0x1a, 0x9b, 0x19, 0x7d, 0xb2, 0xd7, + 0x57, 0xa9, 0x86, 0x3c, 0x82, 0x6e, 0x60, 0x50, 0xf9, 0x5a, 0x66, 0xf2, 0x4b, 0x90, 0x88, 0xc1, + 0x88, 0x4d, 0x6c, 0xaf, 0x53, 0x32, 0xaf, 0x42, 0xfc, 0x23, 0xdc, 0x9d, 0x1b, 0x34, 0x5a, 0xfa, + 0xcd, 0x64, 0xc5, 0x70, 0xc4, 0x26, 0x9d, 0x97, 0x2f, 0xdc, 0x7f, 0x66, 0xef, 0x9e, 0x91, 0xab, + 0x99, 0xbe, 0xc7, 0xe7, 0x7b, 0xec, 0xdc, 0xb2, 0xdb, 0x43, 0x38, 0xb7, 0xec, 0xee, 0xb0, 0x37, + 0xfe, 0x0a, 0x7c, 0xdf, 0xf5, 0x47, 0xce, 0xec, 0xff, 0x39, 0x1f, 0xdc, 0x22, 0xe7, 0xc3, 0xbf, + 0xe5, 0x3c, 0x3b, 0xfb, 0xb1, 0x72, 0xd8, 0xcd, 0xca, 0x61, 0xbf, 0x56, 0x0e, 0xfb, 0xb6, 0x76, + 0x5a, 0x37, 0x6b, 0xa7, 0xf5, 0x73, 0xed, 0xb4, 0x3e, 0x9c, 0x5e, 0xc5, 0xb8, 0x30, 0xa1, 0x1b, + 0xa9, 0x74, 0xba, 0xb3, 0x19, 0xcb, 0xdd, 0xdd, 0xc0, 0xeb, 0x5c, 0x16, 0xe1, 0x31, 0x6d, 0xc5, + 0xab, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x85, 0xeb, 0x7c, 0x12, 0x45, 0x03, 0x00, 0x00, } func (m *Subscription) Marshal() (dAtA []byte, err error) { @@ -219,6 +291,20 @@ func (m *Subscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.FutureSubscription != nil { + { + size, err := m.FutureSubscription.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSubscription(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } if m.AutoRenewal { i-- if m.AutoRenewal { @@ -300,6 +386,46 @@ func (m *Subscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *FutureSubscription) 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 *FutureSubscription) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FutureSubscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.DurationBought != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.DurationBought)) + i-- + dAtA[i] = 0x18 + } + if m.PlanBlock != 0 { + i = encodeVarintSubscription(dAtA, i, uint64(m.PlanBlock)) + i-- + dAtA[i] = 0x10 + } + if len(m.PlanIndex) > 0 { + i -= len(m.PlanIndex) + copy(dAtA[i:], m.PlanIndex) + i = encodeVarintSubscription(dAtA, i, uint64(len(m.PlanIndex))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintSubscription(dAtA []byte, offset int, v uint64) int { offset -= sovSubscription(v) base := offset @@ -360,6 +486,29 @@ func (m *Subscription) Size() (n int) { if m.AutoRenewal { n += 2 } + if m.FutureSubscription != nil { + l = m.FutureSubscription.Size() + n += 2 + l + sovSubscription(uint64(l)) + } + return n +} + +func (m *FutureSubscription) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PlanIndex) + if l > 0 { + n += 1 + l + sovSubscription(uint64(l)) + } + if m.PlanBlock != 0 { + n += 1 + sovSubscription(uint64(m.PlanBlock)) + } + if m.DurationBought != 0 { + n += 1 + sovSubscription(uint64(m.DurationBought)) + } return n } @@ -698,6 +847,162 @@ func (m *Subscription) Unmarshal(dAtA []byte) error { } } m.AutoRenewal = bool(v != 0) + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FutureSubscription", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSubscription + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.FutureSubscription == nil { + m.FutureSubscription = &FutureSubscription{} + } + if err := m.FutureSubscription.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSubscription(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSubscription + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *FutureSubscription) 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 ErrIntOverflowSubscription + } + 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: FutureSubscription: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FutureSubscription: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanIndex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + 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 ErrInvalidLengthSubscription + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PlanIndex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanBlock", wireType) + } + m.PlanBlock = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PlanBlock |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DurationBought", wireType) + } + m.DurationBought = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DurationBought |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipSubscription(dAtA[iNdEx:]) From 5d694f592f8102355dd22a09e839c17594494b81 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 14 Dec 2023 04:16:20 -0500 Subject: [PATCH 03/29] Don't allow modifying the plan price on the same block --- x/plans/keeper/plan.go | 4 ++-- x/plans/keeper/plan_test.go | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/x/plans/keeper/plan.go b/x/plans/keeper/plan.go index 39aeeb101e..6a141e27af 100644 --- a/x/plans/keeper/plan.go +++ b/x/plans/keeper/plan.go @@ -20,8 +20,8 @@ func (k Keeper) AddPlan(ctx sdk.Context, planToAdd types.Plan, modify bool) erro var planFromStore types.Plan block, _, _, found := k.plansFS.FindEntryDetailed(ctx, planToAdd.GetIndex(), planToAdd.Block, &planFromStore) if found { - if planFromStore.Price.Amount.LT(planToAdd.Price.Amount) { - return utils.LavaFormatError("failed modifying plan in planFS", fmt.Errorf("plan price cannot be increased"), + if !planFromStore.Price.Amount.Equal(planToAdd.Price.Amount) { + return utils.LavaFormatError("failed modifying plan in planFS", fmt.Errorf("plan price cannot be modified"), utils.Attribute{Key: "planToAdd", Value: planToAdd}, utils.Attribute{Key: "originalPlan", Value: planFromStore}, ) diff --git a/x/plans/keeper/plan_test.go b/x/plans/keeper/plan_test.go index 3c69e7dd2e..c098ecc834 100644 --- a/x/plans/keeper/plan_test.go +++ b/x/plans/keeper/plan_test.go @@ -336,7 +336,7 @@ func TestAddAndDelete(t *testing.T) { // TestModifyPlan checks that plan modification acts as expected: // 1. there should be no new version in the planFS (latest plan should have the same block) -// 2. plan price cannot be increased +// 2. plan price cannot be changed func TestModifyPlan(t *testing.T) { ts := newTester(t) ts.AdvanceEpoch() @@ -369,4 +369,9 @@ func TestModifyPlan(t *testing.T) { originalPlan.Price = originalPlan.Price.AddAmount(math.NewIntFromUint64(1)) err = testkeeper.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []types.Plan{originalPlan}, true) require.NotNil(t, err) + + // modify the plan by decreasing its price. proposal should fail + originalPlan.Price = originalPlan.Price.SubAmount(math.NewIntFromUint64(2)) + err = testkeeper.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []types.Plan{originalPlan}, true) + require.NotNil(t, err) } From 2aaa325cfadf092f836756eb377e74ec22eee0fc Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 14 Dec 2023 09:00:41 -0500 Subject: [PATCH 04/29] Add the AdvancePurchase flag to tx subscription buy --- proto/lavanet/lava/subscription/tx.proto | 1 + x/subscription/client/cli/tx_buy.go | 21 ++++- x/subscription/types/message_buy.go | 16 ++-- x/subscription/types/tx.pb.go | 112 ++++++++++++++++------- 4 files changed, 104 insertions(+), 46 deletions(-) diff --git a/proto/lavanet/lava/subscription/tx.proto b/proto/lavanet/lava/subscription/tx.proto index aa41513f76..ac10f8fd93 100644 --- a/proto/lavanet/lava/subscription/tx.proto +++ b/proto/lavanet/lava/subscription/tx.proto @@ -22,6 +22,7 @@ message MsgBuy { string index = 3; uint64 duration = 4; // in months bool auto_renewal = 6; + bool advance_purchase = 7; } message MsgBuyResponse { diff --git a/x/subscription/client/cli/tx_buy.go b/x/subscription/client/cli/tx_buy.go index 33e2f30127..636e68e28e 100644 --- a/x/subscription/client/cli/tx_buy.go +++ b/x/subscription/client/cli/tx_buy.go @@ -12,7 +12,8 @@ import ( ) const ( - EnableAutoRenewal = "enable-auto-renewal" + EnableAutoRenewalFlag = "enable-auto-renewal" + AdvancedPurchaseFlag = "advance-purchase" ) func CmdBuy() *cobra.Command { @@ -25,7 +26,8 @@ The duration is stated in number of months (default: 1). If the plan index is different than the consumer's current plan, it will upgrade to that plan index.`, Example: `required flags: --from , optional flags: --enable-auto-renewal lavad tx subscription buy [plan-index] --from - lavad tx subscription buy [plan-index] --from 12`, + lavad tx subscription buy [plan-index] --from 12 + lavad tx subscription buy [plan-index] --from 12 --advanced-purchase`, Args: cobra.RangeArgs(1, 3), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientTxContext(cmd) @@ -47,18 +49,26 @@ If the plan index is different than the consumer's current plan, it will upgrade } // check if the command includes --enable-auto-renewal - enableAutoRenewalFlag := cmd.Flags().Lookup(EnableAutoRenewal) + enableAutoRenewalFlag := cmd.Flags().Lookup(EnableAutoRenewalFlag) if enableAutoRenewalFlag == nil { - return fmt.Errorf("%s flag wasn't found", EnableAutoRenewal) + return fmt.Errorf("%s flag wasn't found", EnableAutoRenewalFlag) } autoRenewal := enableAutoRenewalFlag.Changed + // check if the command includes --enable-auto-renewal + advancedPurchasedFlag := cmd.Flags().Lookup(AdvancedPurchaseFlag) + if advancedPurchasedFlag == nil { + return fmt.Errorf("%s flag wasn't found", EnableAutoRenewalFlag) + } + advancedPurchase := advancedPurchasedFlag.Changed + msg := types.NewMsgBuy( creator, argConsumer, argIndex, argDuration, autoRenewal, + advancedPurchase, ) if err := msg.ValidateBasic(); err != nil { return err @@ -68,7 +78,8 @@ If the plan index is different than the consumer's current plan, it will upgrade } flags.AddTxFlagsToCmd(cmd) - cmd.Flags().Bool(EnableAutoRenewal, false, "enables auto-renewal upon expiration") + cmd.Flags().Bool(EnableAutoRenewalFlag, false, "enables auto-renewal upon expiration") + cmd.Flags().Bool(AdvancedPurchaseFlag, false, "make an advanced purchase that will be activated once the current subscription ends") return cmd } diff --git a/x/subscription/types/message_buy.go b/x/subscription/types/message_buy.go index de1c25d7c2..e308f247a9 100644 --- a/x/subscription/types/message_buy.go +++ b/x/subscription/types/message_buy.go @@ -12,13 +12,14 @@ const TypeMsgBuy = "buy" var _ sdk.Msg = &MsgBuy{} -func NewMsgBuy(creator, consumer, index string, duration uint64, autoRenewal bool) *MsgBuy { +func NewMsgBuy(creator, consumer, index string, duration uint64, autoRenewal, advancePurchase bool) *MsgBuy { return &MsgBuy{ - Creator: creator, - Consumer: consumer, - Index: index, - Duration: duration, - AutoRenewal: autoRenewal, + Creator: creator, + Consumer: consumer, + Index: index, + Duration: duration, + AutoRenewal: autoRenewal, + AdvancePurchase: advancePurchase, } } @@ -58,6 +59,9 @@ func (msg *MsgBuy) ValidateBasic() error { if msg.Duration == 0 || msg.Duration > MAX_SUBSCRIPTION_DURATION { return sdkerrors.Wrapf(ErrInvalidParameter, "invalid subscription duration (%s)", msg.Index) } + if msg.AutoRenewal && msg.AdvancePurchase { + return sdkerrors.Wrapf(ErrInvalidParameter, "can't use enable-auto-renewal and advance-purchase flags together") + } return nil } diff --git a/x/subscription/types/tx.pb.go b/x/subscription/types/tx.pb.go index b9ee2e772b..d7c5cbbbf7 100644 --- a/x/subscription/types/tx.pb.go +++ b/x/subscription/types/tx.pb.go @@ -30,11 +30,12 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type MsgBuy struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - Consumer string `protobuf:"bytes,2,opt,name=consumer,proto3" json:"consumer,omitempty"` - Index string `protobuf:"bytes,3,opt,name=index,proto3" json:"index,omitempty"` - Duration uint64 `protobuf:"varint,4,opt,name=duration,proto3" json:"duration,omitempty"` - AutoRenewal bool `protobuf:"varint,6,opt,name=auto_renewal,json=autoRenewal,proto3" json:"auto_renewal,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Consumer string `protobuf:"bytes,2,opt,name=consumer,proto3" json:"consumer,omitempty"` + Index string `protobuf:"bytes,3,opt,name=index,proto3" json:"index,omitempty"` + Duration uint64 `protobuf:"varint,4,opt,name=duration,proto3" json:"duration,omitempty"` + AutoRenewal bool `protobuf:"varint,6,opt,name=auto_renewal,json=autoRenewal,proto3" json:"auto_renewal,omitempty"` + AdvancePurchase bool `protobuf:"varint,7,opt,name=advance_purchase,json=advancePurchase,proto3" json:"advance_purchase,omitempty"` } func (m *MsgBuy) Reset() { *m = MsgBuy{} } @@ -105,6 +106,13 @@ func (m *MsgBuy) GetAutoRenewal() bool { return false } +func (m *MsgBuy) GetAdvancePurchase() bool { + if m != nil { + return m.AdvancePurchase + } + return false +} + type MsgBuyResponse struct { } @@ -421,37 +429,38 @@ func init() { } var fileDescriptor_b1bb075a6865b817 = []byte{ - // 466 bytes of a gzipped FileDescriptorProto + // 490 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0x8d, 0x89, 0x6b, 0xc2, 0xa4, 0xa0, 0x6a, 0x55, 0x8a, 0xf1, 0xc1, 0xa4, 0xe6, 0x12, 0x24, - 0xb4, 0x86, 0x72, 0xe6, 0xd0, 0xa8, 0xe2, 0x00, 0x8a, 0x84, 0xcc, 0x8d, 0x4b, 0xb5, 0xb1, 0x57, - 0x6e, 0x20, 0xd9, 0xb5, 0x76, 0xd7, 0x25, 0xfd, 0x0b, 0xae, 0x88, 0x1f, 0xea, 0xb1, 0x47, 0x4e, - 0x08, 0x25, 0x3f, 0x82, 0xbc, 0x6b, 0xc7, 0x36, 0xa8, 0x71, 0x4f, 0x3b, 0x33, 0xfb, 0xe6, 0xcd, - 0x9b, 0x19, 0xaf, 0x21, 0x58, 0x90, 0x4b, 0xc2, 0xa8, 0x0a, 0x8b, 0x33, 0x94, 0xf9, 0x4c, 0xc6, - 0x62, 0x9e, 0xa9, 0x39, 0x67, 0xa1, 0x5a, 0xe1, 0x4c, 0x70, 0xc5, 0xd1, 0xd3, 0x12, 0x83, 0x8b, - 0x13, 0x37, 0x31, 0xde, 0xf3, 0x56, 0x7a, 0x26, 0xf8, 0x17, 0x1a, 0x2b, 0x59, 0x19, 0x26, 0xdf, - 0x3b, 0x4c, 0x79, 0xca, 0xb5, 0x19, 0x16, 0x96, 0x89, 0x06, 0x3f, 0x2c, 0x70, 0xa6, 0x32, 0x9d, - 0xe4, 0x57, 0xc8, 0x85, 0xfb, 0xb1, 0xa0, 0x44, 0x71, 0xe1, 0x5a, 0x23, 0x6b, 0xfc, 0x20, 0xaa, - 0x5c, 0xe4, 0xc1, 0x20, 0xe6, 0x4c, 0xe6, 0x4b, 0x2a, 0xdc, 0x7b, 0xfa, 0x6a, 0xeb, 0xa3, 0x43, - 0xd8, 0x9b, 0xb3, 0x84, 0xae, 0xdc, 0xbe, 0xbe, 0x30, 0x4e, 0x91, 0x91, 0xe4, 0x82, 0x14, 0xea, - 0x5c, 0x7b, 0x64, 0x8d, 0xed, 0x68, 0xeb, 0xa3, 0x63, 0xd8, 0x27, 0xb9, 0xe2, 0xe7, 0x82, 0x32, - 0xfa, 0x8d, 0x2c, 0x5c, 0x67, 0x64, 0x8d, 0x07, 0xd1, 0xb0, 0x88, 0x45, 0x26, 0xf4, 0xde, 0x1e, - 0xec, 0x1d, 0x38, 0xc1, 0x01, 0x3c, 0x32, 0xd2, 0x22, 0x2a, 0x33, 0xce, 0x24, 0x0d, 0x2e, 0xe1, - 0xe1, 0x54, 0xa6, 0xa7, 0x49, 0xf2, 0xd1, 0xb4, 0xb6, 0x43, 0xf3, 0x07, 0xd8, 0x2f, 0xfb, 0x3f, - 0x4f, 0x88, 0x22, 0x5a, 0xf7, 0xf0, 0x24, 0xc0, 0xad, 0x29, 0x56, 0xa3, 0xc2, 0x25, 0xdf, 0x19, - 0x51, 0x64, 0x62, 0x5f, 0xff, 0x7e, 0xd6, 0x8b, 0x86, 0x59, 0x1d, 0x0a, 0x9e, 0xc0, 0xe3, 0x56, - 0xdd, 0xad, 0xa0, 0xb7, 0x5a, 0xd0, 0x19, 0x5d, 0x74, 0x0b, 0x42, 0x60, 0x33, 0xb2, 0xa4, 0xe5, - 0x00, 0xb5, 0x5d, 0xf2, 0xd6, 0xe9, 0x5b, 0xde, 0x89, 0x6e, 0xfd, 0xb4, 0x1e, 0xc9, 0x0e, 0xe2, - 0x23, 0x70, 0x28, 0x23, 0xb3, 0x85, 0xa1, 0x1e, 0x44, 0xa5, 0x17, 0xb8, 0x70, 0xd4, 0xe6, 0xa8, - 0xd8, 0x4f, 0x7e, 0xf6, 0xa1, 0x3f, 0x95, 0x29, 0xfa, 0x04, 0xfd, 0x62, 0xf1, 0xc7, 0xf8, 0xd6, - 0x4f, 0x0b, 0x9b, 0x05, 0x78, 0x2f, 0x3a, 0x21, 0x15, 0x39, 0xba, 0x00, 0x68, 0x2c, 0x68, 0xbc, - 0x3b, 0xb1, 0x46, 0x7a, 0xaf, 0xee, 0x8a, 0x6c, 0x56, 0x6a, 0x4c, 0xbe, 0xa3, 0x52, 0x8d, 0xec, - 0xaa, 0xf4, 0xff, 0x3a, 0xd0, 0x57, 0x18, 0x36, 0x77, 0xd1, 0x31, 0x8d, 0x06, 0xd4, 0x7b, 0x7d, - 0x67, 0x68, 0x55, 0x6c, 0xf2, 0xee, 0x7a, 0xed, 0x5b, 0x37, 0x6b, 0xdf, 0xfa, 0xb3, 0xf6, 0xad, - 0xef, 0x1b, 0xbf, 0x77, 0xb3, 0xf1, 0x7b, 0xbf, 0x36, 0x7e, 0xef, 0xf3, 0xcb, 0x74, 0xae, 0x2e, - 0xf2, 0x19, 0x8e, 0xf9, 0x32, 0x6c, 0x3d, 0xf9, 0xd5, 0x3f, 0xff, 0x8c, 0xab, 0x8c, 0xca, 0x99, - 0xa3, 0x5f, 0xf8, 0x9b, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x28, 0x35, 0xcb, 0x2c, 0x5d, 0x04, - 0x00, 0x00, + 0x10, 0x8d, 0x89, 0xeb, 0x86, 0x49, 0x81, 0x68, 0x55, 0x8a, 0xf1, 0xc1, 0xa4, 0xe6, 0x92, 0x4a, + 0xc8, 0x86, 0x72, 0xe6, 0xd0, 0xa8, 0xe2, 0x00, 0x8a, 0x54, 0x99, 0x1b, 0x97, 0x68, 0x63, 0xaf, + 0x9c, 0x40, 0xb2, 0x6b, 0xed, 0xae, 0x43, 0xfa, 0x17, 0xdc, 0xf9, 0x1d, 0x0e, 0x3d, 0xf6, 0xc8, + 0x09, 0xa1, 0xe4, 0x47, 0x90, 0xd7, 0xeb, 0xc4, 0x06, 0xb5, 0xce, 0x69, 0x67, 0x66, 0xdf, 0xbc, + 0x99, 0x79, 0xb3, 0x5a, 0xf0, 0xe6, 0x78, 0x89, 0x29, 0x91, 0x41, 0x7e, 0x06, 0x22, 0x9b, 0x88, + 0x88, 0xcf, 0x52, 0x39, 0x63, 0x34, 0x90, 0x2b, 0x3f, 0xe5, 0x4c, 0x32, 0xf4, 0x5c, 0x63, 0xfc, + 0xfc, 0xf4, 0xab, 0x18, 0xe7, 0x65, 0x2d, 0x3d, 0xe5, 0xec, 0x0b, 0x89, 0xa4, 0x28, 0x8d, 0x22, + 0xdf, 0x39, 0x4e, 0x58, 0xc2, 0x94, 0x19, 0xe4, 0x56, 0x11, 0xf5, 0x7e, 0x1a, 0x60, 0x8d, 0x44, + 0x32, 0xcc, 0xae, 0x91, 0x0d, 0x87, 0x11, 0x27, 0x58, 0x32, 0x6e, 0x1b, 0x7d, 0x63, 0xf0, 0x30, + 0x2c, 0x5d, 0xe4, 0x40, 0x27, 0x62, 0x54, 0x64, 0x0b, 0xc2, 0xed, 0x07, 0xea, 0x6a, 0xeb, 0xa3, + 0x63, 0x38, 0x98, 0xd1, 0x98, 0xac, 0xec, 0xb6, 0xba, 0x28, 0x9c, 0x3c, 0x23, 0xce, 0x38, 0xce, + 0xbb, 0xb3, 0xcd, 0xbe, 0x31, 0x30, 0xc3, 0xad, 0x8f, 0x4e, 0xe1, 0x08, 0x67, 0x92, 0x8d, 0x39, + 0xa1, 0xe4, 0x1b, 0x9e, 0xdb, 0x56, 0xdf, 0x18, 0x74, 0xc2, 0x6e, 0x1e, 0x0b, 0x8b, 0x10, 0x3a, + 0x83, 0x1e, 0x8e, 0x97, 0x98, 0x46, 0x64, 0x9c, 0x66, 0x3c, 0x9a, 0x62, 0x41, 0xec, 0x43, 0x05, + 0x7b, 0xa2, 0xe3, 0x57, 0x3a, 0xfc, 0xc1, 0xec, 0x1c, 0xf4, 0x2c, 0xaf, 0x07, 0x8f, 0x8b, 0x29, + 0x42, 0x22, 0x52, 0x46, 0x05, 0xf1, 0x96, 0xf0, 0x68, 0x24, 0x92, 0x8b, 0x38, 0xbe, 0x2a, 0x54, + 0xb8, 0x67, 0xbc, 0x8f, 0x70, 0xa4, 0xa5, 0x1a, 0xc7, 0x58, 0x62, 0x35, 0x62, 0xf7, 0xdc, 0xf3, + 0x6b, 0x82, 0x97, 0xaa, 0xfa, 0x9a, 0xef, 0x12, 0x4b, 0x3c, 0x34, 0x6f, 0x7e, 0xbf, 0x68, 0x85, + 0xdd, 0x74, 0x17, 0xf2, 0x9e, 0xc1, 0xd3, 0x5a, 0xdd, 0x6d, 0x43, 0xef, 0x54, 0x43, 0x97, 0x64, + 0xde, 0xdc, 0x10, 0x02, 0x93, 0xe2, 0x05, 0xd1, 0x5a, 0x2b, 0x5b, 0xf3, 0xee, 0xd2, 0xb7, 0xbc, + 0x43, 0x35, 0xfa, 0x45, 0x45, 0xbd, 0xbb, 0x89, 0x4f, 0xc0, 0x22, 0x14, 0x4f, 0xe6, 0x05, 0x75, + 0x27, 0xd4, 0x9e, 0x67, 0xc3, 0x49, 0x9d, 0xa3, 0x64, 0x3f, 0xff, 0xd1, 0x86, 0xf6, 0x48, 0x24, + 0xe8, 0x13, 0xb4, 0xf3, 0x37, 0x72, 0xea, 0xdf, 0xf9, 0x0a, 0xfd, 0x62, 0x01, 0xce, 0x59, 0x23, + 0xa4, 0x24, 0x47, 0x53, 0x80, 0xca, 0x82, 0x06, 0xf7, 0x27, 0xee, 0x90, 0xce, 0xeb, 0x7d, 0x91, + 0xd5, 0x4a, 0x15, 0xe5, 0x1b, 0x2a, 0xed, 0x90, 0x4d, 0x95, 0xfe, 0x5f, 0x07, 0xfa, 0x0a, 0xdd, + 0xea, 0x2e, 0x1a, 0xd4, 0xa8, 0x40, 0x9d, 0x37, 0x7b, 0x43, 0xcb, 0x62, 0xc3, 0xf7, 0x37, 0x6b, + 0xd7, 0xb8, 0x5d, 0xbb, 0xc6, 0x9f, 0xb5, 0x6b, 0x7c, 0xdf, 0xb8, 0xad, 0xdb, 0x8d, 0xdb, 0xfa, + 0xb5, 0x71, 0x5b, 0x9f, 0x5f, 0x25, 0x33, 0x39, 0xcd, 0x26, 0x7e, 0xc4, 0x16, 0x41, 0xed, 0x77, + 0x58, 0xfd, 0xf3, 0xbd, 0x5c, 0xa7, 0x44, 0x4c, 0x2c, 0xf5, 0x19, 0xbc, 0xfd, 0x1b, 0x00, 0x00, + 0xff, 0xff, 0x9e, 0x2a, 0x4b, 0x16, 0x88, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -662,6 +671,16 @@ func (m *MsgBuy) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.AdvancePurchase { + i-- + if m.AdvancePurchase { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x38 + } if m.AutoRenewal { i-- if m.AutoRenewal { @@ -945,6 +964,9 @@ func (m *MsgBuy) Size() (n int) { if m.AutoRenewal { n += 2 } + if m.AdvancePurchase { + n += 2 + } return n } @@ -1202,6 +1224,26 @@ func (m *MsgBuy) Unmarshal(dAtA []byte) error { } } m.AutoRenewal = bool(v != 0) + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AdvancePurchase", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AdvancePurchase = bool(v != 0) default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) From c3775ecb38c0ca1e756f65ba9b762029de742ba9 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 14 Dec 2023 09:02:00 -0500 Subject: [PATCH 05/29] Allow advanced purchase in subscription.go --- x/subscription/keeper/msg_server_buy.go | 31 +++- x/subscription/keeper/subscription.go | 198 +++++++++++++++++++----- x/subscription/types/types.go | 2 + 3 files changed, 181 insertions(+), 50 deletions(-) diff --git a/x/subscription/keeper/msg_server_buy.go b/x/subscription/keeper/msg_server_buy.go index a429304355..a7e982fd34 100644 --- a/x/subscription/keeper/msg_server_buy.go +++ b/x/subscription/keeper/msg_server_buy.go @@ -11,16 +11,31 @@ import ( func (k msgServer) Buy(goCtx context.Context, msg *types.MsgBuy) (*types.MsgBuyResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + var err error - err := k.Keeper.CreateSubscription(ctx, msg.Creator, msg.Consumer, msg.Index, msg.Duration, msg.AutoRenewal) - if err == nil { - logger := k.Keeper.Logger(ctx) - details := map[string]string{ - "consumer": msg.Consumer, - "duration": strconv.FormatUint(msg.Duration, 10), - "plan": msg.Index, + if msg.AdvancePurchase { + err = k.Keeper.CreateFutureSubscription(ctx, msg.Creator, msg.Consumer, msg.Index, msg.Duration) + if err == nil { + logger := k.Keeper.Logger(ctx) + details := map[string]string{ + "consumer": msg.Consumer, + "duration": strconv.FormatUint(msg.Duration, 10), + "plan": msg.Index, + } + utils.LogLavaEvent(ctx, logger, types.AdvancedBuySubscriptionEventName, details, "advanced subscription purchased") + } + } else { + err = k.Keeper.CreateSubscription(ctx, msg.Creator, msg.Consumer, msg.Index, msg.Duration, msg.AutoRenewal) + if err == nil { + logger := k.Keeper.Logger(ctx) + details := map[string]string{ + "consumer": msg.Consumer, + "duration": strconv.FormatUint(msg.Duration, 10), + "plan": msg.Index, + } + utils.LogLavaEvent(ctx, logger, types.BuySubscriptionEventName, details, "subscription purchased") } - utils.LogLavaEvent(ctx, logger, types.BuySubscriptionEventName, details, "subscription purchased") } + return &types.MsgBuyResponse{}, err } diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 26004205e3..b3b7594176 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -75,30 +75,13 @@ func (k Keeper) CreateSubscription( var err error block := uint64(ctx.BlockHeight()) - - if _, err = sdk.AccAddressFromBech32(consumer); err != nil { - return utils.LavaFormatWarning("invalid subscription consumer address", err, - utils.Attribute{Key: "consumer", Value: consumer}, - ) - } - - creatorAcct, err := sdk.AccAddressFromBech32(creator) + creatorAcct, plan, err := k.verifySubscriptionBuyInput(ctx, block, creator, consumer, planIndex) if err != nil { - return utils.LavaFormatWarning("invalid subscription creator address", err, - utils.Attribute{Key: "creator", Value: creator}, - ) - } - - plan, found := k.plansKeeper.GetPlan(ctx, planIndex) - if !found { - return utils.LavaFormatWarning("cannot create subscription with invalid plan", err, - utils.Attribute{Key: "plan", Value: planIndex}, - utils.Attribute{Key: "block", Value: block}, - ) + return err } var sub types.Subscription - found = k.subsFS.FindEntry(ctx, consumer, block, &sub) + found := k.subsFS.FindEntry(ctx, consumer, block, &sub) // Subscription creation: // When: if not already exists for consumer address) @@ -199,29 +182,11 @@ func (k Keeper) CreateSubscription( // subscription looks good; let's charge the creator price := plan.GetPrice() price.Amount = price.Amount.MulRaw(int64(duration)) + k.applyPlanDiscountIfEligible(duration, &plan, &price) - if duration >= MONTHS_IN_YEAR { - // adjust cost if discount given - discount := plan.GetAnnualDiscountPercentage() - if discount > 0 { - factor := int64(100 - discount) - price.Amount = price.Amount.MulRaw(factor).QuoRaw(100) - } - } - - if k.bankKeeper.GetBalance(ctx, creatorAcct, k.stakingKeeper.BondDenom(ctx)).IsLT(price) { - return utils.LavaFormatWarning("create subscription failed", legacyerrors.ErrInsufficientFunds, - utils.Attribute{Key: "creator", Value: creator}, - utils.Attribute{Key: "price", Value: price}, - ) - } - - err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, creatorAcct, types.ModuleName, []sdk.Coin{price}) + err = k.chargeFromCreatorAccountToModule(ctx, creatorAcct, price) if err != nil { - return utils.LavaFormatError("create subscription failed. funds transfer failed", err, - utils.Attribute{Key: "creator", Value: creator}, - utils.Attribute{Key: "price", Value: price}, - ) + return err } if !found { @@ -236,6 +201,32 @@ func (k Keeper) CreateSubscription( return err } +func (k Keeper) verifySubscriptionBuyInput(ctx sdk.Context, block uint64, creator, consumer, planIndex string) (creatorAcct sdk.AccAddress, plan planstypes.Plan, err error) { + EMPTY_PLAN := planstypes.Plan{} + + if _, err := sdk.AccAddressFromBech32(consumer); err != nil { + return nil, EMPTY_PLAN, utils.LavaFormatWarning("invalid subscription consumer address", err, + utils.Attribute{Key: "consumer", Value: consumer}, + ) + } + + creatorAcct, err = sdk.AccAddressFromBech32(creator) + if err != nil { + return nil, EMPTY_PLAN, utils.LavaFormatWarning("invalid subscription creator address", err, + utils.Attribute{Key: "creator", Value: creator}, + ) + } + + plan, found := k.plansKeeper.GetPlan(ctx, planIndex) + if !found { + return nil, EMPTY_PLAN, utils.LavaFormatWarning("cannot create subscription with invalid plan", nil, + utils.Attribute{Key: "plan", Value: planIndex}, + utils.Attribute{Key: "block", Value: block}, + ) + } + return +} + func (k Keeper) createNewSubscription(ctx sdk.Context, plan *planstypes.Plan, creator, consumer string, block uint64, autoRenewalFlag bool, ) (types.Subscription, error) { @@ -317,7 +308,17 @@ func (k Keeper) advanceMonth(ctx sdk.Context, subkey []byte) { sub.DurationTotal += 1 k.resetSubscriptionDetailsAndAppendEntry(ctx, &sub, block, date) } else { - if sub.AutoRenewal { + if sub.FutureSubscription != nil { + // Consumer made advance purchase. Now we activate it. + newSubInfo := sub.FutureSubscription + + sub.PlanIndex = newSubInfo.PlanIndex + sub.PlanBlock = newSubInfo.PlanBlock + sub.DurationBought = newSubInfo.DurationBought + sub.FutureSubscription = nil + + k.resetSubscriptionDetailsAndAppendEntry(ctx, &sub, block, date) + } else if sub.AutoRenewal { // apply the DurationLeft decrease to 0 and buy an extra month k.subsFS.ModifyEntry(ctx, sub.Consumer, sub.Block, &sub) err := k.CreateSubscription(ctx, sub.Creator, sub.Consumer, sub.PlanIndex, 1, sub.AutoRenewal) @@ -403,6 +404,119 @@ func (k Keeper) resetSubscriptionDetailsAndAppendEntry(ctx sdk.Context, sub *typ } } +func (k Keeper) applyPlanDiscountIfEligible(duration uint64, plan *planstypes.Plan, price *sdk.Coin) { + if duration >= MONTHS_IN_YEAR { + // adjust cost if discount given + discount := plan.GetAnnualDiscountPercentage() + if discount > 0 { + factor := int64(100 - discount) + price.Amount = price.Amount.MulRaw(factor).QuoRaw(100) + } + } +} + +func (k Keeper) chargeFromCreatorAccountToModule(ctx sdk.Context, creator sdk.AccAddress, price sdk.Coin) error { + if k.bankKeeper.GetBalance(ctx, creator, k.stakingKeeper.BondDenom(ctx)).IsLT(price) { + return utils.LavaFormatWarning("create subscription failed", legacyerrors.ErrInsufficientFunds, + utils.LogAttr("creator", creator), + utils.LogAttr("price", price), + ) + } + + err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, creator, types.ModuleName, []sdk.Coin{price}) + if err != nil { + return utils.LavaFormatError("create subscription failed. funds transfer failed", err, + utils.LogAttr("creator", creator), + utils.LogAttr("price", price), + ) + } + + return nil +} + +func (k Keeper) CreateFutureSubscription(ctx sdk.Context, + creator string, + consumer string, + planIndex string, + duration uint64, +) error { + var err error + + block := uint64(ctx.BlockHeight()) + creatorAcct, plan, err := k.verifySubscriptionBuyInput(ctx, block, creator, consumer, planIndex) + if err != nil { + return err + } + + var sub types.Subscription + found := k.subsFS.FindEntry(ctx, consumer, block, &sub) + + if !found { + return utils.LavaFormatWarning("could not find active subscription. advanced purchase is only available for an active subscription", nil, + utils.LogAttr("consumer", consumer), + utils.LogAttr("block", block), + ) + } + + createFutureSubscription := func(sub *types.Subscription, planIndex string, planBlock, duration uint64) { + sub.FutureSubscription = &types.FutureSubscription{ + PlanIndex: planIndex, + PlanBlock: planBlock, + DurationBought: duration, + } + } + + if sub.FutureSubscription != nil { + // Consumer already has a future subscription + // If the new plan's price > current future subscription's plan - change and charge the diff + currentPlan, err := k.GetPlanFromSubscription(ctx, consumer, block) + if err != nil { + return utils.LavaFormatError("panic: could not get active subscription's plan. aborting", err, + utils.Attribute{Key: "creator", Value: creator}, + ) + } + + newPlanCostForDuration := plan.Price.Amount.MulRaw(int64(duration)) + consumerPaid := currentPlan.Price.Amount.MulRaw(int64(sub.FutureSubscription.DurationBought)) + if newPlanCostForDuration.GT(consumerPaid) { + priceDiff := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), newPlanCostForDuration.Sub(consumerPaid)) + err = k.chargeFromCreatorAccountToModule(ctx, creatorAcct, priceDiff) + if err != nil { + return err + } + + createFutureSubscription(&sub, plan.Index, plan.Block, duration) + + details := map[string]string{ + "consumer": consumer, + "duration": strconv.FormatUint(duration, 10), + "oldPlanIndex": currentPlan.Index, + "oldPlanBlock": strconv.FormatUint(currentPlan.Block, 10), + "newPlanIndex": plan.Index, + "newPlanBlock": strconv.FormatUint(plan.Block, 10), + } + utils.LogLavaEvent(ctx, k.Logger(ctx), types.AdvancedBuyUpgradeSubscriptionEventName, details, "advanced subscription upgraded") + return nil + } else { + return utils.LavaFormatWarning("can't purchase another plan in advanced with a lower price", nil) + } + } + + price := plan.GetPrice() + price.Amount = price.Amount.MulRaw(int64(duration)) + k.applyPlanDiscountIfEligible(duration, &plan, &price) + + err = k.chargeFromCreatorAccountToModule(ctx, creatorAcct, price) + if err != nil { + return err + } + + createFutureSubscription(&sub, plan.Index, plan.Block, duration) + + k.subsFS.ModifyEntry(ctx, consumer, sub.Block, &sub) + return nil +} + func (k Keeper) RemoveExpiredSubscription(ctx sdk.Context, consumer string, block uint64) { // delete all projects before deleting k.delAllProjectsFromSubscription(ctx, consumer) diff --git a/x/subscription/types/types.go b/x/subscription/types/types.go index 4d185e209b..5dce2d01b0 100644 --- a/x/subscription/types/types.go +++ b/x/subscription/types/types.go @@ -2,6 +2,8 @@ package types const ( BuySubscriptionEventName = "buy_subscription_event" + AdvancedBuySubscriptionEventName = "advanced_buy_subscription_event" + AdvancedBuyUpgradeSubscriptionEventName = "advanced_buy_upgrade_subscription_event" UpgradeSubscriptionEventName = "upgrade_subscription_event" ExpireSubscriptionEventName = "expire_subscription_event" AddProjectEventName = "add_project_to_subscription_event" From 31be4e035f03edda74b9d6da3c04ac19718503f6 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 14 Dec 2023 09:02:24 -0500 Subject: [PATCH 06/29] Add tests --- testutil/common/tester.go | 13 +- .../keeper/msg_server_detection_test.go | 2 +- x/pairing/keeper/cu_tracker_test.go | 10 +- x/pairing/keeper/delegator_rewards_test.go | 8 +- x/pairing/keeper/helpers_test.go | 2 +- .../msg_server_relay_payment_gov_test.go | 2 +- .../keeper/msg_server_relay_payment_test.go | 2 +- x/pairing/keeper/pairing_subscription_test.go | 2 +- x/pairing/keeper/pairing_test.go | 32 +- x/projects/keeper/project_test.go | 6 +- x/subscription/keeper/cluster_test.go | 2 +- x/subscription/keeper/subscription_test.go | 627 ++++++++++++++++-- 12 files changed, 612 insertions(+), 96 deletions(-) diff --git a/testutil/common/tester.go b/testutil/common/tester.go index b456898c9d..b64e4924d7 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -445,13 +445,14 @@ func (ts *Tester) TxDualstakingClaimRewards( } // TxSubscriptionBuy: implement 'tx subscription buy' -func (ts *Tester) TxSubscriptionBuy(creator, consumer, plan string, months int, autoRenewal bool) (*subscriptiontypes.MsgBuyResponse, error) { +func (ts *Tester) TxSubscriptionBuy(creator, consumer, plan string, months int, autoRenewal, advancePurchase bool) (*subscriptiontypes.MsgBuyResponse, error) { msg := &subscriptiontypes.MsgBuy{ - Creator: creator, - Consumer: consumer, - Index: plan, - Duration: uint64(months), - AutoRenewal: autoRenewal, + Creator: creator, + Consumer: consumer, + Index: plan, + Duration: uint64(months), + AutoRenewal: autoRenewal, + AdvancePurchase: advancePurchase, } return ts.Servers.SubscriptionServer.Buy(ts.GoCtx, msg) } diff --git a/x/conflict/keeper/msg_server_detection_test.go b/x/conflict/keeper/msg_server_detection_test.go index 10a1e8ef12..d9a4886886 100644 --- a/x/conflict/keeper/msg_server_detection_test.go +++ b/x/conflict/keeper/msg_server_detection_test.go @@ -50,7 +50,7 @@ func (ts *tester) setupForConflict(providersCount int) *tester { ts.spec = ts.Spec("mock") consumer, consumerAddr := ts.AddAccount("consumer", 0, balance) - _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, ts.plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, ts.plan.Index, 1, false, false) require.Nil(ts.T, err) ts.consumer = consumer diff --git a/x/pairing/keeper/cu_tracker_test.go b/x/pairing/keeper/cu_tracker_test.go index c6f71a12b9..04b18e1176 100644 --- a/x/pairing/keeper/cu_tracker_test.go +++ b/x/pairing/keeper/cu_tracker_test.go @@ -26,7 +26,7 @@ func TestAddingTrackedCuWithoutPay(t *testing.T) { _, provider1Addr := ts.GetAccount(common.PROVIDER, 0) _, provider2Addr := ts.GetAccount(common.PROVIDER, 1) - ts.TxSubscriptionBuy(client1Addr, client1Addr, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client1Addr, client1Addr, "free", 1, false, false) // extend by a month so the sub won't expire res, err := ts.QuerySubscriptionCurrent(client1Addr) require.Nil(t, err) @@ -115,7 +115,7 @@ func TestTrackedCuWithExpiredSubscription(t *testing.T) { ts.AddPlan(ts.plan.Index, ts.plan) clientAcct, clientAddr := ts.AddAccount(common.CONSUMER, 0, testBalance) - _, err := ts.TxSubscriptionBuy(clientAddr, clientAddr, ts.plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(clientAddr, clientAddr, ts.plan.Index, 1, false, false) require.Nil(t, err) err = ts.addProvider(1) @@ -178,7 +178,7 @@ func TestTrackedCuWithQos(t *testing.T) { provider1Acc, provider1 := ts.GetAccount(common.PROVIDER, 0) provider2Acc, provider2 := ts.GetAccount(common.PROVIDER, 1) - ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire badQoS := &types.QualityOfServiceReport{ Latency: sdk.ZeroDec(), @@ -381,7 +381,7 @@ func TestProviderMonthlyPayoutQuery(t *testing.T) { clientAcc, client := ts.GetAccount(common.CONSUMER, 0) providerAcct, provider := ts.GetAccount(common.PROVIDER, 0) - ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire // stake the provider on an additional chain and apply pairing (advance epoch) spec1 := ts.spec @@ -657,7 +657,7 @@ func TestTrackedCuDeletion(t *testing.T) { clientAcc, client := ts.GetAccount(common.CONSUMER, 0) _, provider := ts.GetAccount(common.PROVIDER, 0) - ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire // send relay to track CU relayPayment := sendRelay(ts, provider, clientAcc, []string{ts.spec.Index}) diff --git a/x/pairing/keeper/delegator_rewards_test.go b/x/pairing/keeper/delegator_rewards_test.go index 8898fc661b..dc2c4ae5c4 100644 --- a/x/pairing/keeper/delegator_rewards_test.go +++ b/x/pairing/keeper/delegator_rewards_test.go @@ -73,7 +73,7 @@ func TestProviderDelegatorsRewards(t *testing.T) { _, delegator1 := ts.GetAccount(common.CONSUMER, 1) _, delegator2 := ts.GetAccount(common.CONSUMER, 2) - ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire ts.AdvanceEpoch() // to apply pairing @@ -193,7 +193,7 @@ func TestDelegationLimitAffectingProviderReward(t *testing.T) { ts.AdvanceEpoch() // to apply pairing - ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire delegationAmount1 := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(uint64(testStake)/2)) delegationAmount2 := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(uint64(testStake))) @@ -241,7 +241,7 @@ func TestProviderRewardWithCommission(t *testing.T) { clientAcc, client := ts.GetAccount(common.CONSUMER, 0) delegator1Acc, delegator1 := ts.GetAccount(common.CONSUMER, 1) - ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire ts.AdvanceEpoch() // to apply pairing @@ -347,7 +347,7 @@ func TestQueryDelegatorRewards(t *testing.T) { _, delegator1 := ts.GetAccount(common.CONSUMER, 1) _, delegator2 := ts.GetAccount(common.CONSUMER, 2) // delegates to no one - ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire spec1 := common.CreateMockSpec() spec1.Index = "mock1" diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index 6c00bb34d0..caa2cb0311 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -42,7 +42,7 @@ func (ts *tester) addClient(count int) { start := len(ts.Accounts(common.CONSUMER)) for i := 0; i < count; i++ { _, addr := ts.AddAccount(common.CONSUMER, start+i, testBalance) - _, err := ts.TxSubscriptionBuy(addr, addr, ts.plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(addr, addr, ts.plan.Index, 1, false, false) if err != nil { panic("addClient: failed to buy subscription: " + err.Error()) } diff --git a/x/pairing/keeper/msg_server_relay_payment_gov_test.go b/x/pairing/keeper/msg_server_relay_payment_gov_test.go index 7e8a2b21a4..2953131737 100644 --- a/x/pairing/keeper/msg_server_relay_payment_gov_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_gov_test.go @@ -259,7 +259,7 @@ func TestRelayPaymentGovEpochToSaveDecrease(t *testing.T) { client1Acct, client := ts.GetAccount(common.CONSUMER, 0) providerAcct, providerAddr := ts.GetAccount(common.PROVIDER, 0) - ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client, client, "free", 1, false, false) // extend by a month so the sub won't expire epochBlocks := ts.EpochBlocks() epochsToSave := ts.EpochsToSave() diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 98fb06cac4..77c6102735 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -761,7 +761,7 @@ func TestBadgeUsedCuMapTimeout(t *testing.T) { client1Acct, client1Addr := ts.GetAccount(common.CONSUMER, 0) providerAcct, providerAddr := ts.GetAccount(common.PROVIDER, 0) - ts.TxSubscriptionBuy(client1Addr, client1Addr, "free", 1, false) // extend by a month so the sub won't expire + ts.TxSubscriptionBuy(client1Addr, client1Addr, "free", 1, false, false) // extend by a month so the sub won't expire badgeAcct, _ := ts.AddAccount("badge", 0, testBalance) diff --git a/x/pairing/keeper/pairing_subscription_test.go b/x/pairing/keeper/pairing_subscription_test.go index 69679a7b12..7d8ef1db58 100644 --- a/x/pairing/keeper/pairing_subscription_test.go +++ b/x/pairing/keeper/pairing_subscription_test.go @@ -445,7 +445,7 @@ func TestPairingNotChangingDueToCuOveruse(t *testing.T) { client1Acct, client1Addr := ts.GetAccount(common.CONSUMER, 0) // add 10 months to the subscription - _, err := ts.TxSubscriptionBuy(client1Addr, client1Addr, ts.plan.Index, 10, false) + _, err := ts.TxSubscriptionBuy(client1Addr, client1Addr, ts.plan.Index, 10, false, false) require.Nil(t, err) totalCuLimit := ts.plan.PlanPolicy.TotalCuLimit diff --git a/x/pairing/keeper/pairing_test.go b/x/pairing/keeper/pairing_test.go index 34a7e9aada..3997a5ec32 100644 --- a/x/pairing/keeper/pairing_test.go +++ b/x/pairing/keeper/pairing_test.go @@ -29,9 +29,9 @@ func TestPairingUniqueness(t *testing.T) { _, sub1Addr := ts.Account("sub1") _, sub2Addr := ts.Account("sub2") - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false, false) require.Nil(t, err) - _, err = ts.TxSubscriptionBuy(sub2Addr, sub2Addr, ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(sub2Addr, sub2Addr, ts.plan.Index, 1, false, false) require.Nil(t, err) for i := 1; i <= 1000; i++ { @@ -97,7 +97,7 @@ func TestValidatePairingDeterminism(t *testing.T) { _, sub1Addr := ts.Account("sub1") - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false, false) require.Nil(t, err) for i := 1; i <= 10; i++ { @@ -247,7 +247,7 @@ func TestPairingStatic(t *testing.T) { ts.AdvanceEpoch() - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false, false) require.Nil(t, err) for i := 0; i < int(ts.plan.PlanPolicy.MaxProvidersToPair)*2; i++ { @@ -519,7 +519,7 @@ func TestAddonPairing(t *testing.T) { _, sub1Addr := ts.AddAccount("sub", 0, 10000) - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) // get the admin project and set its policies @@ -710,7 +710,7 @@ func TestSelectedProvidersPairing(t *testing.T) { ts.AdvanceEpoch() - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) // get the admin project and set its policies @@ -872,7 +872,7 @@ func TestPairingUniformDistribution(t *testing.T) { _, clientAddr := ts.GetAccount(common.CONSUMER, 0) // extend the subscription to accommodate many (pairing) epochs - _, err := ts.TxSubscriptionBuy(clientAddr, clientAddr, ts.plan.Index, 5, false) + _, err := ts.TxSubscriptionBuy(clientAddr, clientAddr, ts.plan.Index, 5, false, false) require.NoError(t, err) weightFunc := func(p epochstoragetypes.StakeEntry) int64 { return p.Stake.Amount.Int64() } @@ -899,7 +899,7 @@ func TestPairingDistributionPerStake(t *testing.T) { ts.AdvanceEpoch() // extend the subscription to accommodate many (pairing) epochs - _, err = ts.TxSubscriptionBuy(clientAddr, clientAddr, ts.plan.Index, 10, false) + _, err = ts.TxSubscriptionBuy(clientAddr, clientAddr, ts.plan.Index, 10, false, false) require.Nil(t, err) weightFunc := func(p epochstoragetypes.StakeEntry) int64 { return p.Stake.Amount.Int64() } @@ -1007,9 +1007,9 @@ func TestGeolocationPairingScores(t *testing.T) { basicAcct, basicAddr := ts.GetAccount(common.CONSUMER, 1) premiumAcct, premiumAddr := ts.GetAccount(common.CONSUMER, 2) - ts.TxSubscriptionBuy(freeAddr, freeAddr, freePlan.Index, 1, false) - ts.TxSubscriptionBuy(basicAddr, basicAddr, basicPlan.Index, 1, false) - ts.TxSubscriptionBuy(premiumAddr, premiumAddr, premiumPlan.Index, 1, false) + ts.TxSubscriptionBuy(freeAddr, freeAddr, freePlan.Index, 1, false, false) + ts.TxSubscriptionBuy(basicAddr, basicAddr, basicPlan.Index, 1, false, false) + ts.TxSubscriptionBuy(premiumAddr, premiumAddr, premiumPlan.Index, 1, false, false) for geoName, geo := range planstypes.Geolocation_value { if geoName != "GL" && geoName != "GLS" { @@ -1199,7 +1199,7 @@ func TestDuplicateProviders(t *testing.T) { require.Nil(t, err) ts.AdvanceEpoch() - ts.TxSubscriptionBuy(basicAddr, basicAddr, basicPlan.Index, 1, false) + ts.TxSubscriptionBuy(basicAddr, basicAddr, basicPlan.Index, 1, false, false) for geoName, geo := range planstypes.Geolocation_value { if geoName != "GL" && geoName != "GLS" { @@ -1247,7 +1247,7 @@ func TestNoRequiredGeo(t *testing.T) { require.Nil(t, err) ts.AdvanceEpoch() - ts.TxSubscriptionBuy(freeAddr, freeAddr, freePlan.Index, 1, false) + ts.TxSubscriptionBuy(freeAddr, freeAddr, freePlan.Index, 1, false, false) // add 5 more providers that are not in US-E (the only allowed providers in the free plan) err = ts.addProviderGeolocation(5, planstypes.Geolocation_value["AS"]) @@ -1929,7 +1929,7 @@ func TestExtensionAndAddonPairing(t *testing.T) { _, sub1Addr := ts.AddAccount("sub", 0, 10000) - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) // get the admin project and set its policies @@ -2094,7 +2094,7 @@ func TestMixSelectedProvidersAndArchivePairing(t *testing.T) { _, sub1Addr := ts.AddAccount("sub", 0, 10000) - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) // get the admin project and set its policies @@ -2222,7 +2222,7 @@ func TestPairingPerformance(t *testing.T) { _, sub1Addr := ts.Account("sub1") - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, ts.plan.Index, 1, false, false) require.Nil(t, err) for i := 1; i <= 1000; i++ { diff --git a/x/projects/keeper/project_test.go b/x/projects/keeper/project_test.go index d4ee7745d2..43d1cacd90 100644 --- a/x/projects/keeper/project_test.go +++ b/x/projects/keeper/project_test.go @@ -200,7 +200,7 @@ func TestProjectsServerAPI(t *testing.T) { err := ts.TxProposalAddPlans(plan) require.Nil(t, err) - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) projectData := types.ProjectData{ @@ -1050,7 +1050,7 @@ func TestSetPolicySelectedProviders(t *testing.T) { require.NotNil(t, err) } - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) res, err := ts.QuerySubscriptionListProjects(sub1Addr) @@ -1224,7 +1224,7 @@ func TestPendingProject(t *testing.T) { _, sub := ts.Account("sub1") - _, err := ts.TxSubscriptionBuy(sub, sub, "free", 1, false) + _, err := ts.TxSubscriptionBuy(sub, sub, "free", 1, false, false) require.Nil(t, err) res, err := ts.QuerySubscriptionListProjects(sub) diff --git a/x/subscription/keeper/cluster_test.go b/x/subscription/keeper/cluster_test.go index 1ed607b658..b617ee434e 100644 --- a/x/subscription/keeper/cluster_test.go +++ b/x/subscription/keeper/cluster_test.go @@ -39,7 +39,7 @@ func TestGetCluster(t *testing.T) { for _, tt := range template { t.Run(tt.name, func(t *testing.T) { - _, err := ts.TxSubscriptionBuy(tt.sub, tt.sub, tt.plan, 12, false) + _, err := ts.TxSubscriptionBuy(tt.sub, tt.sub, tt.plan, 12, false, false) require.Nil(t, err) prevCluster := "" diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index f9c6fd7f32..4e9d47b2bb 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "fmt" "strconv" "testing" "time" @@ -22,7 +23,16 @@ type tester struct { func newTester(t *testing.T) *tester { ts := &tester{Tester: *common.NewTester(t)} - ts.AddPlan("free", common.CreateMockPlan()) + freePlan := common.CreateMockPlan() + freePlan.Block = ts.BlockHeight() + ts.AddPlan("free", freePlan) + + premiumPlan := common.CreateMockPlan() + premiumPlan.Index = "premium" + premiumPlan.Price = freePlan.Price.AddAmount(math.NewInt(100)) + premiumPlan.Block = ts.BlockHeight() + ts.AddPlan(premiumPlan.Index, premiumPlan) + return ts } @@ -169,7 +179,7 @@ func TestCreateSubscription(t *testing.T) { PlanIndex: tt.index, } - _, err := ts.TxSubscriptionBuy(sub.Creator, sub.Consumer, sub.PlanIndex, tt.duration, false) + _, err := ts.TxSubscriptionBuy(sub.Creator, sub.Consumer, sub.PlanIndex, tt.duration, false, false) if tt.success { require.Nil(t, err, tt.name) _, found := ts.getSubscription(sub.Consumer) @@ -189,7 +199,7 @@ func TestSubscriptionExpiration(t *testing.T) { _, sub1Addr := ts.Account("sub1") plan := ts.Plan("free") - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) _, found := ts.getSubscription(sub1Addr) require.True(t, found) @@ -209,7 +219,7 @@ func TestRenewSubscription(t *testing.T) { _, sub1Addr := ts.Account("sub1") plan := ts.Plan("free") - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 6, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 6, false, false) require.Nil(t, err) _, found := ts.getSubscription(sub1Addr) require.True(t, found) @@ -221,11 +231,11 @@ func TestRenewSubscription(t *testing.T) { require.Equal(t, uint64(3), sub.DurationLeft) // with 3 months duration left, asking for 12 more should fail - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 12, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 12, false, false) require.NotNil(t, err) // but 9 additional month (even 10, the extra month extension below) - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 9, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 9, false, false) require.Nil(t, err) sub, found = ts.getSubscription(sub1Addr) require.True(t, found) @@ -244,7 +254,7 @@ func TestRenewSubscription(t *testing.T) { // try extending the subscription (we could extend with 1 more month, // but since the subscription's plan changed and its new price is increased // by more than 5% , the extension should fail) - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.NotNil(t, err) require.Equal(t, uint64(12), sub.DurationLeft) require.Equal(t, uint64(9), sub.DurationBought) @@ -264,7 +274,7 @@ func TestRenewSubscription(t *testing.T) { ts.AdvanceMonths(1).AdvanceEpoch() _, found = ts.getSubscription(sub1Addr) require.True(t, found) - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 10, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 10, false, false) require.NotNil(t, err) } @@ -275,7 +285,7 @@ func TestSubscriptionAdminProject(t *testing.T) { _, sub1Addr := ts.Account("sub1") plan := ts.Plan("free") - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) // a newly created subscription is expected to have one default project, @@ -293,7 +303,7 @@ func TestMonthlyRechargeCU(t *testing.T) { _, dev1Addr := ts.Account("dev1") plan := ts.Plan("free") - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 3, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 3, false, false) require.Nil(t, err) // add another project under the subscription @@ -425,7 +435,7 @@ func TestExpiryTime(t *testing.T) { delta := now.Sub(ts.BlockTime()) ts.AdvanceBlock(delta) - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, tt.months, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, tt.months, false, false) require.Nil(t, err) sub, found := ts.getSubscription(sub1Addr) @@ -449,7 +459,7 @@ func TestSubscriptionExpire(t *testing.T) { coins := common.NewCoins(ts.TokenDenom(), 10000) ts.Keepers.BankKeeper.SetBalance(ts.Ctx, sub1Acct.Addr, coins) - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) block := ts.BlockHeight() @@ -508,7 +518,7 @@ func TestPrice(t *testing.T) { err := ts.TxProposalAddPlans(plan) require.Nil(t, err) - _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, tt.duration, false) + _, err = ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, tt.duration, false, false) require.Nil(t, err) _, found := ts.getSubscription(sub1Addr) @@ -532,7 +542,7 @@ func TestAddProjectToSubscription(t *testing.T) { _, dev1Addr := ts.Account("dev1") plan := ts.Plan("free") - _, err := ts.TxSubscriptionBuy(sub1Addr, dev1Addr, plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, dev1Addr, plan.Index, 1, false, false) require.Nil(t, err) template := []struct { @@ -581,9 +591,9 @@ func TestGetProjectsForSubscription(t *testing.T) { plan := ts.Plan("free") // buy two subscriptions - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) - _, err = ts.TxSubscriptionBuy(sub2Addr, sub2Addr, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(sub2Addr, sub2Addr, plan.Index, 1, false, false) require.Nil(t, err) // add two projects to the first subscription @@ -625,7 +635,7 @@ func TestAddDelProjectForSubscription(t *testing.T) { plan := ts.Plan("free") // buy subscription and add project - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) projData := projectstypes.ProjectData{ @@ -661,7 +671,7 @@ func TestDelProjectEndSubscription(t *testing.T) { plan := ts.Plan("free") // buy subscription - _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false, false) require.Nil(t, err) // time of buy subscription @@ -708,7 +718,7 @@ func TestDurationTotal(t *testing.T) { plan := ts.Plan("free") _, subAddr := ts.Account("sub1") - _, err := ts.TxSubscriptionBuy(subAddr, subAddr, plan.Index, months, false) + _, err := ts.TxSubscriptionBuy(subAddr, subAddr, plan.Index, months, false, false) require.Nil(t, err) for i := 0; i < months-1; i++ { @@ -726,7 +736,7 @@ func TestDurationTotal(t *testing.T) { durationSoFar := subRes.Sub.DurationTotal extraMonths := 4 - _, err = ts.TxSubscriptionBuy(subAddr, subAddr, plan.Index, extraMonths, false) + _, err = ts.TxSubscriptionBuy(subAddr, subAddr, plan.Index, extraMonths, false, false) require.Nil(t, err) for i := 0; i < extraMonths; i++ { @@ -745,7 +755,7 @@ func TestDurationTotal(t *testing.T) { require.Nil(t, err) require.Nil(t, subRes.Sub) - _, err = ts.TxSubscriptionBuy(subAddr, subAddr, plan.Index, extraMonths, false) + _, err = ts.TxSubscriptionBuy(subAddr, subAddr, plan.Index, extraMonths, false, false) require.Nil(t, err) subRes, err = ts.QuerySubscriptionCurrent(subAddr) require.Nil(t, err) @@ -767,13 +777,13 @@ func TestSubAutoRenewal(t *testing.T) { // buy two subscriptions with enabled auto-renewal in two different ways // and one with disabled auto-renewal. // verify the auto-renewal flag is true in the first two subs - _, err := ts.TxSubscriptionBuy(subAddr1, subAddr1, plan.Index, 1, true) + _, err := ts.TxSubscriptionBuy(subAddr1, subAddr1, plan.Index, 1, true, false) require.Nil(t, err) - _, err = ts.TxSubscriptionBuy(subAddr2, subAddr2, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(subAddr2, subAddr2, plan.Index, 1, false, false) require.Nil(t, err) err = ts.TxSubscriptionAutoRenewal(subAddr2, true) require.Nil(t, err) - _, err = ts.TxSubscriptionBuy(subAddr3, subAddr3, plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(subAddr3, subAddr3, plan.Index, 1, false, false) require.Nil(t, err) sub1, found := ts.getSubscription(subAddr1) @@ -812,7 +822,7 @@ func TestSubRenewalFailHighPlanPrice(t *testing.T) { _, subAddr1 := ts.Account("sub1") plan := ts.Plan("free") - _, err := ts.TxSubscriptionBuy(subAddr1, subAddr1, plan.Index, 1, true) + _, err := ts.TxSubscriptionBuy(subAddr1, subAddr1, plan.Index, 1, true, false) require.Nil(t, err) _, found := ts.getSubscription(subAddr1) require.True(t, found) @@ -848,15 +858,15 @@ func TestNextToMonthExpiryQuery(t *testing.T) { _, sub3 := ts.Account("sub3") // buy 3 subs - 2 at the same time and one a second later - _, err := ts.TxSubscriptionBuy(sub1, sub1, plan.Index, months, false) + _, err := ts.TxSubscriptionBuy(sub1, sub1, plan.Index, months, false, false) require.Nil(t, err) - _, err = ts.TxSubscriptionBuy(sub2, sub2, plan.Index, months, false) + _, err = ts.TxSubscriptionBuy(sub2, sub2, plan.Index, months, false, false) require.Nil(t, err) sub1Obj, found := ts.getSubscription(sub1) require.True(t, found) ts.AdvanceBlock(time.Second) - _, err = ts.TxSubscriptionBuy(sub3, sub3, plan.Index, months, false) + _, err = ts.TxSubscriptionBuy(sub3, sub3, plan.Index, months, false, false) require.Nil(t, err) sub3Obj, found := ts.getSubscription(sub3) require.True(t, found) @@ -898,15 +908,10 @@ func TestSubscriptionUpgrade(t *testing.T) { _, consumer := ts.Account("sub1") freePlan := ts.Plan("free") - - // Add premium plan - upgradedPlan := common.CreateMockPlan() - upgradedPlan.Index = "premium" - upgradedPlan.Price = freePlan.Price.AddAmount(math.NewInt(100)) - ts.AddPlan(upgradedPlan.Index, upgradedPlan) + premiumPlan := ts.Plan("premium") // Buy free plan - _, err := ts.TxSubscriptionBuy(consumer, consumer, freePlan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(consumer, consumer, freePlan.Index, 1, false, false) require.Nil(t, err) // Verify subscription found inside getSubscription getSubscriptionAndFailTestIfNotFound(t, ts, consumer) @@ -925,7 +930,7 @@ func TestSubscriptionUpgrade(t *testing.T) { currentDurationTotal := sub.DurationTotal // Buy premium plan - _, err = ts.TxSubscriptionBuy(consumer, consumer, upgradedPlan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumer, consumer, premiumPlan.Index, 1, false, false) require.Nil(t, err) nextEpoch := ts.GetNextEpoch() @@ -944,7 +949,7 @@ func TestSubscriptionUpgrade(t *testing.T) { // Test that the subscription is now updated sub = getSubscriptionAndFailTestIfNotFound(t, ts, consumer) - require.Equal(t, upgradedPlan.Index, sub.PlanIndex) + require.Equal(t, premiumPlan.Index, sub.PlanIndex) // Test that the project is now updated project = getProjectAndFailTestIfNotFound(t, ts, consumer, ts.BlockHeight()) @@ -957,15 +962,10 @@ func TestSubscriptionDowngradeFails(t *testing.T) { _, consumer := ts.Account("sub1") freePlan := ts.Plan("free") - - // Add premium plan - upgradedPlan := common.CreateMockPlan() - upgradedPlan.Index = "premium" - upgradedPlan.Price = freePlan.Price.AddAmount(math.NewInt(100)) - ts.AddPlan(upgradedPlan.Index, upgradedPlan) + premiumPlan := ts.Plan("premium") // Buy premium plan - _, err := ts.TxSubscriptionBuy(consumer, consumer, upgradedPlan.Index, 1, false) + _, err := ts.TxSubscriptionBuy(consumer, consumer, premiumPlan.Index, 1, false, false) require.Nil(t, err) // Verify subscription found inside getSubscription getSubscriptionAndFailTestIfNotFound(t, ts, consumer) @@ -973,13 +973,13 @@ func TestSubscriptionDowngradeFails(t *testing.T) { ts.AdvanceEpochs(2) // Buy premium plan - _, err = ts.TxSubscriptionBuy(consumer, consumer, freePlan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumer, consumer, freePlan.Index, 1, false, false) require.NotNil(t, err) ts.AdvanceEpoch() sub := getSubscriptionAndFailTestIfNotFound(t, ts, consumer) - require.Equal(t, upgradedPlan.Index, sub.PlanIndex) + require.Equal(t, premiumPlan.Index, sub.PlanIndex) } func TestSubscriptionCuExhaustAndUpgrade(t *testing.T) { @@ -1004,15 +1004,10 @@ func TestSubscriptionCuExhaustAndUpgrade(t *testing.T) { ts.AdvanceEpoch() freePlan := ts.Plan("free") - - // Add premium plan - upgradedPlan := common.CreateMockPlan() - upgradedPlan.Index = "premium" - upgradedPlan.Price = freePlan.Price.AddAmount(math.NewInt(100)) - ts.AddPlan(upgradedPlan.Index, upgradedPlan) + premiumPlan := ts.Plan("premium") // Buy free plan - _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, freePlan.Index, 3, false) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, freePlan.Index, 3, false, false) require.Nil(t, err) // Verify subscription found inside getSubscription @@ -1047,7 +1042,7 @@ func TestSubscriptionCuExhaustAndUpgrade(t *testing.T) { sendRelayPayment() // Buy premium plan - _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, upgradedPlan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, premiumPlan.Index, 1, false, false) require.Nil(t, err) // Trigger new subscription @@ -1055,7 +1050,7 @@ func TestSubscriptionCuExhaustAndUpgrade(t *testing.T) { // Test that the subscription is now updated sub := getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) - require.Equal(t, upgradedPlan.Index, sub.PlanIndex) + require.Equal(t, premiumPlan.Index, sub.PlanIndex) // Test that the project is now updated project := getProjectAndFailTestIfNotFound(t, ts, consumerAddr, ts.BlockHeight()) @@ -1075,5 +1070,525 @@ func TestSubscriptionCuExhaustAndUpgrade(t *testing.T) { reward := rewards.Rewards[0] // Verify that provider got rewarded for both subscriptions - require.Equal(t, freePlan.Price.AddAmount(upgradedPlan.Price.Amount), reward.Amount) + require.Equal(t, freePlan.Price.AddAmount(premiumPlan.Price.Amount), reward.Amount) +} + +func TestSubscriptionAdvancePurchaseStartsOnExpirationOfCurrent(t *testing.T) { + ts := newTester(t) + ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + + consumerAcc, consumerAdd := ts.Account("sub1") + freePlan := ts.Plan("free") + premiumPlan := ts.Plan("premium") + consumerBalance := ts.GetBalance(consumerAcc.Addr) + + // Buy free plan + freePlanDuration := int64(2) + _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, freePlan.Index, int(freePlanDuration), false, false) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + consumerBalance -= freePlan.Price.Amount.MulRaw(freePlanDuration).Int64() + // Make sure the balance checks out + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + newSubDuration := int64(4) + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, premiumPlan.Index, int(newSubDuration), false, true) + require.Nil(t, err) + + // Verify that the consumer charged with the correct amount + consumerShouldPay := premiumPlan.Price.Amount.MulRaw(newSubDuration) + expectedConsumerBalance := consumerBalance - consumerShouldPay.Int64() + require.Equal(t, expectedConsumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Verify new future subscription + sub := getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + futureSub := sub.FutureSubscription + require.NotNil(t, futureSub) + require.Equal(t, premiumPlan.Index, futureSub.PlanIndex) + require.Equal(t, premiumPlan.Block, futureSub.PlanBlock) + require.Equal(t, newSubDuration, futureSub.DurationBought) + + ts.AdvanceMonths(1).AdvanceEpoch() + + // Should still be the same before the subscription expires + sub = getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + futureSub = sub.FutureSubscription + require.NotNil(t, futureSub) + require.Equal(t, premiumPlan.Index, futureSub.PlanIndex) + require.Equal(t, premiumPlan.Block, futureSub.PlanBlock) + require.Equal(t, newSubDuration, futureSub.DurationBought) + + ts.AdvanceMonths(1).AdvanceEpoch() + + // New subscription should now be active + sub = getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + require.Nil(t, sub.FutureSubscription) + require.Equal(t, premiumPlan.Index, sub.PlanIndex) + require.Equal(t, premiumPlan.Block, sub.PlanBlock) + require.Equal(t, newSubDuration, sub.DurationBought) +} + +func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_SameBlock(t *testing.T) { + ts := newTester(t) + ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + + CHEAP := "cheap" + MEDIUM := "medium" + EXPENSIVE := "expensive" + + cheapPlan := common.CreateMockPlan() + cheapPlan.Index = CHEAP + cheapPlan.Price = common.NewCoin(ts.TokenDenom(), 100) + cheapPlan.Block = ts.BlockHeight() + ts.AddPlan(cheapPlan.Index, cheapPlan) + + mediumPlan := common.CreateMockPlan() + mediumPlan.Index = MEDIUM + mediumPlan.Price = common.NewCoin(ts.TokenDenom(), 200) + mediumPlan.Block = ts.BlockHeight() + ts.AddPlan(mediumPlan.Index, mediumPlan) + + expansivePlan := common.CreateMockPlan() + expansivePlan.Index = EXPENSIVE + expansivePlan.Price = common.NewCoin(ts.TokenDenom(), 400) + expansivePlan.Block = ts.BlockHeight() + ts.AddPlan(expansivePlan.Index, expansivePlan) + + // We start with the medium plan. + // All these test cases should be with a new plan that is more expensive than the plan before them: + // 1. Expansive plan && less duration + // 2. Cheaper plan && more duration + // 3. Same plan && more duration + // 4. Expansive plan && same duration + // 5. Expansive plan && more duration + + startingDuration := int64(3) + originalPlanCost := mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() + testCases := []struct { + name string + plan *planstypes.Plan + duration int64 + price int64 + }{ + { + name: "Expansive plan && less duration", + plan: &expansivePlan, // 400 + duration: startingDuration - 1, // * 2 + price: expansivePlan.Price.Amount.MulRaw(startingDuration - 1).Int64(), // = 800, + }, + { + name: "Cheaper plan && more duration", + plan: &cheapPlan, // 100 + duration: startingDuration + 6, // * 9 + price: cheapPlan.Price.Amount.MulRaw(startingDuration + 6).Int64(), // = 900 + }, + { + name: "Same plan && more duration", + plan: &mediumPlan, // 200 + duration: startingDuration + 2, // * 5 + price: mediumPlan.Price.Amount.MulRaw(startingDuration + 2).Int64(), // = 1000 + }, + { + name: "Expansive plan && same duration", + plan: &expansivePlan, // 400 + duration: startingDuration, // * 3 + price: expansivePlan.Price.Amount.MulRaw(startingDuration).Int64(), // = 1200, + }, + { + name: "Expansive plan && more duration", + plan: &expansivePlan, // 400 + duration: startingDuration + 1, // * 4 + price: expansivePlan.Price.Amount.MulRaw(startingDuration + 1).Int64(), // = 1600, + }, + } + + consumerAcc, consumerAdd := ts.Account("sub1") + consumerBalance := ts.GetBalance(consumerAcc.Addr) + + // Buy medium plan + _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, 1, false, false) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + + consumerBalance -= mediumPlan.Price.Amount.Int64() + // Make sure the balance checks out + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Buy future medium plan + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, int(startingDuration), false, true) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + + consumerBalance -= mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() + // Make sure the balance checks out + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + for _, testCase := range testCases { + testName := fmt.Sprintf("%s -> Price: %d", testCase.name, testCase.price) + // Buy new plan + _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, testCase.plan.Index, int(testCase.duration), false, true) + require.Nil(t, err, testName) + + priceDiff := testCase.price - originalPlanCost + consumerBalance -= priceDiff + + // Make sure the balance is updated + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr), testName) + } +} + +func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) { + ts := newTester(t) + ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + + MEDIUM := "medium" + + mediumPlan := common.CreateMockPlan() + mediumPlan.Index = MEDIUM + mediumPlan.Price = common.NewCoin(ts.TokenDenom(), 200) + mediumPlan.Block = ts.BlockHeight() + ts.AddPlan(mediumPlan.Index, mediumPlan) + + // We start with the medium plan. + // All these test cases should be with a new plan that is more expensive than current: + // 1. Same plan && cheaper && more duration + // 2. Same plan && more expensive && less duration + // 3. Same plan && more expensive && same duration + // 4. Same plan && more expensive && more duration + + startingDuration := int64(2) + originalPlanCost := mediumPlan.Price.Amount.MulRaw(startingDuration) + // Original cost: 200 * 2 = 400 + + consumerAcc, consumerAdd := ts.Account("sub1") + consumerBalance := ts.GetBalance(consumerAcc.Addr) + + // Buy medium plan + _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, 1, false, false) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + + // Make sure the balance checks out + consumerBalance -= mediumPlan.Price.Amount.Int64() + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Buy future medium plan + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, int(startingDuration), false, true) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + + // Make sure the balance checks out + consumerBalance -= mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + ts.AdvanceBlock() + + // Create plan with same index - cheaper price + mediumPlanCheaper := common.CreateMockPlan() + mediumPlanCheaper.Index = MEDIUM + mediumPlanCheaper.Price = common.NewCoin(ts.TokenDenom(), 100) + mediumPlanCheaper.Block = ts.BlockHeight() + ts.AddPlan(mediumPlanCheaper.Index, mediumPlanCheaper) + + // 1. Buy new plan + newPlanDuration := startingDuration + 3 // 5 + newPlanCost := mediumPlanCheaper.Price.Amount.MulRaw(newPlanDuration) // 500 + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(newPlanDuration), false, true) + require.Nil(t, err, "Same plan && cheaper && more duration -> Price: "+newPlanCost.String()) + + priceDiff := newPlanCost.Sub(originalPlanCost).Int64() + consumerBalance -= priceDiff + + // Make sure the balance has changed + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + ts.AdvanceBlock() + + // Create plan with same index - higher price + mediumPlanExpensive := common.CreateMockPlan() + mediumPlanExpensive.Index = MEDIUM + mediumPlanExpensive.Price = common.NewCoin(ts.TokenDenom(), 600) + mediumPlanExpensive.Block = ts.BlockHeight() + ts.AddPlan(mediumPlanExpensive.Index, mediumPlanExpensive) + + // 2. Buy new plan + newPlanDuration = startingDuration - 1 // 1 + newPlanCost = mediumPlanExpensive.Price.Amount.MulRaw(newPlanDuration) // 600 + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanExpensive.Index, int(newPlanDuration), false, true) + require.Nil(t, err, "Same plan && more expensive && less duration -> Price: "+newPlanCost.String()) + + priceDiff = newPlanCost.Sub(originalPlanCost).Int64() + consumerBalance -= priceDiff + + // Make sure the balance has changed + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // 3. Buy new plan + newPlanDuration = startingDuration // 2 + newPlanCost = mediumPlanExpensive.Price.Amount.MulRaw(newPlanDuration) // 1200 + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanExpensive.Index, int(newPlanDuration), false, true) + require.Nil(t, err, "Same plan && more expensive && same duration -> Price: "+newPlanCost.String()) + + priceDiff = newPlanCost.Sub(originalPlanCost).Int64() + consumerBalance -= priceDiff + + // Make sure the balance has changed + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // 4. Buy new plan + newPlanDuration = startingDuration + 1 // 3 + newPlanCost = mediumPlanExpensive.Price.Amount.MulRaw(newPlanDuration) // 1800 + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanExpensive.Index, int(newPlanDuration), false, true) + require.Nil(t, err, "Same plan && more expensive && more duration -> Price: "+newPlanCost.String()) + + priceDiff = newPlanCost.Sub(originalPlanCost).Int64() + consumerBalance -= priceDiff + + // Make sure the balance has changed + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) +} + +func TestSubscriptionAdvancePurchaseFailOnCheaperPlans_SameBlock(t *testing.T) { + ts := newTester(t) + ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + + CHEAP := "cheap" + MEDIUM := "medium" + EXPENSIVE := "expensive" + + cheapPlan := common.CreateMockPlan() + cheapPlan.Index = CHEAP + cheapPlan.Price = common.NewCoin(ts.TokenDenom(), 100) + cheapPlan.Block = ts.BlockHeight() + ts.AddPlan(cheapPlan.Index, cheapPlan) + + mediumPlan := common.CreateMockPlan() + mediumPlan.Index = MEDIUM + mediumPlan.Price = common.NewCoin(ts.TokenDenom(), 200) + mediumPlan.Block = ts.BlockHeight() + ts.AddPlan(mediumPlan.Index, mediumPlan) + + expansivePlan := common.CreateMockPlan() + expansivePlan.Index = EXPENSIVE + expansivePlan.Price = common.NewCoin(ts.TokenDenom(), 300) + expansivePlan.Block = ts.BlockHeight() + ts.AddPlan(expansivePlan.Index, expansivePlan) + + // We start with the medium plan. + // All these test cases should be with a new plan that is equal or cheaper than current: + // 1. Same plan && same duration = equal + // 2. Same plan && less duration = cheaper + // 3. Cheaper plan && same duration = cheaper + // 4. Cheaper plan && more duration = equal + // 5. Cheaper plan && more duration = cheaper + // 6. Expansive plan && less duration = equal + // 7. Expansive plan && less duration = cheaper + + startingDuration := int64(3) + // Original cost: 200 * 3 = 600 + testCases := []struct { + name string + plan *planstypes.Plan + duration int64 + price int64 + }{ + { + name: "Same plan && same duration", + plan: &mediumPlan, // 200 + duration: startingDuration, // * 3 + price: mediumPlan.Price.Amount.MulRaw(startingDuration).Int64(), // = 600 + }, + { + name: "Same plan && less duration", + plan: &mediumPlan, // 200 + duration: startingDuration - 1, // * 2 + price: mediumPlan.Price.Amount.MulRaw(startingDuration - 1).Int64(), // = 400 + }, + { + name: "Cheaper plan && same duration", + plan: &cheapPlan, // 100 + duration: startingDuration, // * 3 + price: cheapPlan.Price.Amount.MulRaw(startingDuration).Int64(), // = 300, + }, + { + name: "Cheaper plan && more duration", + plan: &cheapPlan, // 100 + duration: startingDuration + 3, // * 6 + price: cheapPlan.Price.Amount.MulRaw(startingDuration + 3).Int64(), // = 600, + }, + { + name: "Cheaper plan && more duration", + plan: &cheapPlan, // 100 + duration: startingDuration + 1, // * 4 + price: cheapPlan.Price.Amount.MulRaw(startingDuration + 1).Int64(), // = 400, + }, + { + name: "Expansive plan && less duration", + plan: &expansivePlan, // 300 + duration: startingDuration - 1, // * 2 + price: expansivePlan.Price.Amount.MulRaw(startingDuration - 1).Int64(), // = 600, + }, + { + name: "Expansive plan && less duration", + plan: &expansivePlan, // 300 + duration: startingDuration - 2, // * 1 + price: expansivePlan.Price.Amount.MulRaw(startingDuration - 2).Int64(), // = 300, + }, + } + + consumerAcc, consumerAdd := ts.Account("sub1") + consumerBalance := ts.GetBalance(consumerAcc.Addr) + + // Buy medium plan + _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, 1, false, false) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + + consumerBalance -= mediumPlan.Price.Amount.Int64() + // Make sure the balance checks out + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Buy future medium plan + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, int(startingDuration), false, true) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + + consumerBalance -= mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() + // Make sure the balance checks out + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + for _, testCase := range testCases { + testName := fmt.Sprintf("%s -> Price: %d", testCase.name, testCase.price) + + // Buy new plan + _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, testCase.plan.Index, int(testCase.duration), false, true) + require.NotNil(t, err, testName) + + // Make sure the balance is not changed + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr), testName) + } +} + +func TestSubscriptionAdvancePurchaseFailOnCheaperPlans_NewBlock(t *testing.T) { + ts := newTester(t) + ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + + MEDIUM := "medium" + + mediumPlan := common.CreateMockPlan() + mediumPlan.Index = MEDIUM + mediumPlan.Price = common.NewCoin(ts.TokenDenom(), 200) + mediumPlan.Block = ts.BlockHeight() + ts.AddPlan(mediumPlan.Index, mediumPlan) + + // We start with the medium plan. + // All these test cases should be with a new plan that is equal or cheaper than current: + // 1. Same plan && more expensive && less duration = equal + // 2. Same plan && more expensive && less duration = cheaper + // 3. Same plan && cheaper && more duration = equal + // 4. Same plan && cheaper && more duration = cheaper + + startingDuration := int64(3) + // Original cost: 200 * 3 = 600 + + consumerAcc, consumerAdd := ts.Account("sub1") + consumerBalance := ts.GetBalance(consumerAcc.Addr) + + // Buy medium plan + _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, 1, false, false) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + + // Make sure the balance checks out + consumerBalance -= mediumPlan.Price.Amount.Int64() + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Buy future medium plan + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, int(startingDuration), false, true) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + + // Make sure the balance checks out + consumerBalance -= mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + ts.AdvanceBlock() + + // Create plan with same index - cheaper price + mediumPlanCheaper := common.CreateMockPlan() + mediumPlanCheaper.Index = MEDIUM + mediumPlanCheaper.Price = common.NewCoin(ts.TokenDenom(), 100) + mediumPlanCheaper.Block = ts.BlockHeight() + ts.AddPlan(mediumPlanCheaper.Index, mediumPlanCheaper) + + // Buy new plan + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(startingDuration+3), false, true) + require.NotNil(t, err, "Same plan && cheaper && more duration -> Price: "+ + mediumPlanCheaper.Price.Amount.MulRaw(startingDuration+3).String()) // 600 + + // Make sure the balance is not changed + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Buy new plan + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(startingDuration+2), false, true) + require.NotNil(t, err, "Same plan && cheaper && more duration -> Price: "+ + mediumPlanCheaper.Price.Amount.MulRaw(startingDuration+2).String()) // 500 + + // Make sure the balance is not changed + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + ts.AdvanceBlock() + + // Create plan with same index - higher price + mediumPlanExpensive := common.CreateMockPlan() + mediumPlanExpensive.Index = MEDIUM + mediumPlanExpensive.Price = common.NewCoin(ts.TokenDenom(), 300) + mediumPlanExpensive.Block = ts.BlockHeight() + ts.AddPlan(mediumPlanExpensive.Index, mediumPlanExpensive) + + // Buy new plan + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(startingDuration-1), false, true) + require.NotNil(t, err, "Same plan && cheaper && more duration -> Price: "+ + mediumPlanCheaper.Price.Amount.MulRaw(startingDuration-1).String()) // 600 + + // Make sure the balance is not changed + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Buy new plan + _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(startingDuration-2), false, true) + require.NotNil(t, err, "Same plan && cheaper && more duration -> Price: "+ + mediumPlanCheaper.Price.Amount.MulRaw(startingDuration-2).String()) // 500 + + // Make sure the balance is not changed + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) +} + +func TestSubscriptionAdvancePurchaseFailOnNoSubscription(t *testing.T) { + ts := newTester(t) + ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + + consumerAcc, consumerAdd := ts.Account("sub1") + premiumPlan := ts.Plan("premium") + consumerBalance := ts.GetBalance(consumerAcc.Addr) + + // Advance purchase the subscription with no active subscription + newSubDuration := int64(4) + _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, premiumPlan.Index, int(newSubDuration), false, true) + require.NotNil(t, err) + + // Verify that the consumer is not charged + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Verify that there is no new subscription + _, found := ts.getSubscription(consumerAdd) + require.False(t, found) } From 61159995eda9502bc7c9dbc695109e29af3a937b Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 14 Dec 2023 11:50:16 -0500 Subject: [PATCH 07/29] Small fix to test --- x/subscription/keeper/subscription_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index 4e9d47b2bb..deaccccb42 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -1092,12 +1092,12 @@ func TestSubscriptionAdvancePurchaseStartsOnExpirationOfCurrent(t *testing.T) { // Make sure the balance checks out require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) - newSubDuration := int64(4) + newSubDuration := uint64(4) _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, premiumPlan.Index, int(newSubDuration), false, true) require.Nil(t, err) // Verify that the consumer charged with the correct amount - consumerShouldPay := premiumPlan.Price.Amount.MulRaw(newSubDuration) + consumerShouldPay := premiumPlan.Price.Amount.MulRaw(int64(newSubDuration)) expectedConsumerBalance := consumerBalance - consumerShouldPay.Int64() require.Equal(t, expectedConsumerBalance, ts.GetBalance(consumerAcc.Addr)) From c6ac1ab3bd143eaba20fa3e96e850ed957ec83ae Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 17 Dec 2023 08:29:15 -0500 Subject: [PATCH 08/29] Small cli fix --- x/subscription/client/cli/tx_buy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/subscription/client/cli/tx_buy.go b/x/subscription/client/cli/tx_buy.go index 636e68e28e..563999398d 100644 --- a/x/subscription/client/cli/tx_buy.go +++ b/x/subscription/client/cli/tx_buy.go @@ -58,7 +58,7 @@ If the plan index is different than the consumer's current plan, it will upgrade // check if the command includes --enable-auto-renewal advancedPurchasedFlag := cmd.Flags().Lookup(AdvancedPurchaseFlag) if advancedPurchasedFlag == nil { - return fmt.Errorf("%s flag wasn't found", EnableAutoRenewalFlag) + return fmt.Errorf("%s flag wasn't found", AdvancedPurchaseFlag) } advancedPurchase := advancedPurchasedFlag.Changed From ce3150f9c2f2b83e4f396f248659aae8dd181854 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 17 Dec 2023 11:29:11 -0500 Subject: [PATCH 09/29] Fix a bug in the advance purchase --- x/subscription/keeper/subscription.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index b3b7594176..80eabc1a50 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -315,6 +315,8 @@ func (k Keeper) advanceMonth(ctx sdk.Context, subkey []byte) { sub.PlanIndex = newSubInfo.PlanIndex sub.PlanBlock = newSubInfo.PlanBlock sub.DurationBought = newSubInfo.DurationBought + sub.DurationLeft = newSubInfo.DurationBought + sub.DurationTotal += 1 sub.FutureSubscription = nil k.resetSubscriptionDetailsAndAppendEntry(ctx, &sub, block, date) From ad4130f5781d2e2441afb8855522868e8ce0c252 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 17 Dec 2023 11:30:22 -0500 Subject: [PATCH 10/29] Save the new creator as current creator after advance purchase is activated --- .../lava/subscription/subscription.proto | 7 +- x/subscription/keeper/subscription.go | 9 +- x/subscription/keeper/subscription_test.go | 157 +++++++++++++----- x/subscription/types/subscription.pb.go | 118 +++++++++---- 4 files changed, 212 insertions(+), 79 deletions(-) diff --git a/proto/lavanet/lava/subscription/subscription.proto b/proto/lavanet/lava/subscription/subscription.proto index 02ff434562..e60780e6c2 100644 --- a/proto/lavanet/lava/subscription/subscription.proto +++ b/proto/lavanet/lava/subscription/subscription.proto @@ -23,7 +23,8 @@ message Subscription { } message FutureSubscription { - string plan_index = 1; // index (name) of plan - uint64 plan_block = 2; // when the plan was created - uint64 duration_bought = 3; // total requested duration in months + string creator = 1; // creator pays for the future subscription. Will replace the original one once activated + string plan_index = 2; // index (name) of plan + uint64 plan_block = 3; // when the plan was created + uint64 duration_bought = 4; // total requested duration in months } \ No newline at end of file diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 80eabc1a50..d22a417635 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -312,6 +312,7 @@ func (k Keeper) advanceMonth(ctx sdk.Context, subkey []byte) { // Consumer made advance purchase. Now we activate it. newSubInfo := sub.FutureSubscription + sub.Creator = newSubInfo.Creator sub.PlanIndex = newSubInfo.PlanIndex sub.PlanBlock = newSubInfo.PlanBlock sub.DurationBought = newSubInfo.DurationBought @@ -460,8 +461,9 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, ) } - createFutureSubscription := func(sub *types.Subscription, planIndex string, planBlock, duration uint64) { + createFutureSubscription := func(sub *types.Subscription, creator, planIndex string, planBlock, duration uint64) { sub.FutureSubscription = &types.FutureSubscription{ + Creator: creator, PlanIndex: planIndex, PlanBlock: planBlock, DurationBought: duration, @@ -487,9 +489,10 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, return err } - createFutureSubscription(&sub, plan.Index, plan.Block, duration) + createFutureSubscription(&sub, creator, plan.Index, plan.Block, duration) details := map[string]string{ + "creator": creator, "consumer": consumer, "duration": strconv.FormatUint(duration, 10), "oldPlanIndex": currentPlan.Index, @@ -513,7 +516,7 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, return err } - createFutureSubscription(&sub, plan.Index, plan.Block, duration) + createFutureSubscription(&sub, creator, plan.Index, plan.Block, duration) k.subsFS.ModifyEntry(ctx, consumer, sub.Block, &sub) return nil diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index deaccccb42..6d298cf11f 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -1077,23 +1077,23 @@ func TestSubscriptionAdvancePurchaseStartsOnExpirationOfCurrent(t *testing.T) { ts := newTester(t) ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev - consumerAcc, consumerAdd := ts.Account("sub1") + consumerAcc, consumerAddr := ts.Account("sub1") freePlan := ts.Plan("free") premiumPlan := ts.Plan("premium") consumerBalance := ts.GetBalance(consumerAcc.Addr) // Buy free plan freePlanDuration := int64(2) - _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, freePlan.Index, int(freePlanDuration), false, false) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, freePlan.Index, int(freePlanDuration), false, false) require.Nil(t, err) // Verify subscription found inside getSubscription - getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) consumerBalance -= freePlan.Price.Amount.MulRaw(freePlanDuration).Int64() // Make sure the balance checks out require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) newSubDuration := uint64(4) - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, premiumPlan.Index, int(newSubDuration), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, premiumPlan.Index, int(newSubDuration), false, true) require.Nil(t, err) // Verify that the consumer charged with the correct amount @@ -1102,7 +1102,7 @@ func TestSubscriptionAdvancePurchaseStartsOnExpirationOfCurrent(t *testing.T) { require.Equal(t, expectedConsumerBalance, ts.GetBalance(consumerAcc.Addr)) // Verify new future subscription - sub := getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + sub := getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) futureSub := sub.FutureSubscription require.NotNil(t, futureSub) require.Equal(t, premiumPlan.Index, futureSub.PlanIndex) @@ -1112,7 +1112,7 @@ func TestSubscriptionAdvancePurchaseStartsOnExpirationOfCurrent(t *testing.T) { ts.AdvanceMonths(1).AdvanceEpoch() // Should still be the same before the subscription expires - sub = getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + sub = getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) futureSub = sub.FutureSubscription require.NotNil(t, futureSub) require.Equal(t, premiumPlan.Index, futureSub.PlanIndex) @@ -1122,11 +1122,13 @@ func TestSubscriptionAdvancePurchaseStartsOnExpirationOfCurrent(t *testing.T) { ts.AdvanceMonths(1).AdvanceEpoch() // New subscription should now be active - sub = getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + sub = getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) require.Nil(t, sub.FutureSubscription) require.Equal(t, premiumPlan.Index, sub.PlanIndex) require.Equal(t, premiumPlan.Block, sub.PlanBlock) require.Equal(t, newSubDuration, sub.DurationBought) + require.Equal(t, newSubDuration, sub.DurationLeft) + require.Equal(t, uint64(2), sub.DurationTotal) } func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_SameBlock(t *testing.T) { @@ -1203,24 +1205,24 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_SameBlock(t *testing.T) }, } - consumerAcc, consumerAdd := ts.Account("sub1") + consumerAcc, consumerAddr := ts.Account("sub1") consumerBalance := ts.GetBalance(consumerAcc.Addr) // Buy medium plan - _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, 1, false, false) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, 1, false, false) require.Nil(t, err) // Verify subscription found inside getSubscription - getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) consumerBalance -= mediumPlan.Price.Amount.Int64() // Make sure the balance checks out require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) // Buy future medium plan - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, int(startingDuration), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, int(startingDuration), false, true) require.Nil(t, err) // Verify subscription found inside getSubscription - getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) consumerBalance -= mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() // Make sure the balance checks out @@ -1229,7 +1231,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_SameBlock(t *testing.T) for _, testCase := range testCases { testName := fmt.Sprintf("%s -> Price: %d", testCase.name, testCase.price) // Buy new plan - _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, testCase.plan.Index, int(testCase.duration), false, true) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, testCase.plan.Index, int(testCase.duration), false, true) require.Nil(t, err, testName) priceDiff := testCase.price - originalPlanCost @@ -1263,24 +1265,24 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) originalPlanCost := mediumPlan.Price.Amount.MulRaw(startingDuration) // Original cost: 200 * 2 = 400 - consumerAcc, consumerAdd := ts.Account("sub1") + consumerAcc, consumerAddr := ts.Account("sub1") consumerBalance := ts.GetBalance(consumerAcc.Addr) // Buy medium plan - _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, 1, false, false) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, 1, false, false) require.Nil(t, err) // Verify subscription found inside getSubscription - getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) // Make sure the balance checks out consumerBalance -= mediumPlan.Price.Amount.Int64() require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) // Buy future medium plan - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, int(startingDuration), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, int(startingDuration), false, true) require.Nil(t, err) // Verify subscription found inside getSubscription - getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) // Make sure the balance checks out consumerBalance -= mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() @@ -1298,7 +1300,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) // 1. Buy new plan newPlanDuration := startingDuration + 3 // 5 newPlanCost := mediumPlanCheaper.Price.Amount.MulRaw(newPlanDuration) // 500 - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(newPlanDuration), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanCheaper.Index, int(newPlanDuration), false, true) require.Nil(t, err, "Same plan && cheaper && more duration -> Price: "+newPlanCost.String()) priceDiff := newPlanCost.Sub(originalPlanCost).Int64() @@ -1319,7 +1321,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) // 2. Buy new plan newPlanDuration = startingDuration - 1 // 1 newPlanCost = mediumPlanExpensive.Price.Amount.MulRaw(newPlanDuration) // 600 - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanExpensive.Index, int(newPlanDuration), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanExpensive.Index, int(newPlanDuration), false, true) require.Nil(t, err, "Same plan && more expensive && less duration -> Price: "+newPlanCost.String()) priceDiff = newPlanCost.Sub(originalPlanCost).Int64() @@ -1331,7 +1333,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) // 3. Buy new plan newPlanDuration = startingDuration // 2 newPlanCost = mediumPlanExpensive.Price.Amount.MulRaw(newPlanDuration) // 1200 - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanExpensive.Index, int(newPlanDuration), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanExpensive.Index, int(newPlanDuration), false, true) require.Nil(t, err, "Same plan && more expensive && same duration -> Price: "+newPlanCost.String()) priceDiff = newPlanCost.Sub(originalPlanCost).Int64() @@ -1343,7 +1345,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) // 4. Buy new plan newPlanDuration = startingDuration + 1 // 3 newPlanCost = mediumPlanExpensive.Price.Amount.MulRaw(newPlanDuration) // 1800 - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanExpensive.Index, int(newPlanDuration), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanExpensive.Index, int(newPlanDuration), false, true) require.Nil(t, err, "Same plan && more expensive && more duration -> Price: "+newPlanCost.String()) priceDiff = newPlanCost.Sub(originalPlanCost).Int64() @@ -1441,24 +1443,24 @@ func TestSubscriptionAdvancePurchaseFailOnCheaperPlans_SameBlock(t *testing.T) { }, } - consumerAcc, consumerAdd := ts.Account("sub1") + consumerAcc, consumerAddr := ts.Account("sub1") consumerBalance := ts.GetBalance(consumerAcc.Addr) // Buy medium plan - _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, 1, false, false) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, 1, false, false) require.Nil(t, err) // Verify subscription found inside getSubscription - getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) consumerBalance -= mediumPlan.Price.Amount.Int64() // Make sure the balance checks out require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) // Buy future medium plan - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, int(startingDuration), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, int(startingDuration), false, true) require.Nil(t, err) // Verify subscription found inside getSubscription - getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) consumerBalance -= mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() // Make sure the balance checks out @@ -1468,7 +1470,7 @@ func TestSubscriptionAdvancePurchaseFailOnCheaperPlans_SameBlock(t *testing.T) { testName := fmt.Sprintf("%s -> Price: %d", testCase.name, testCase.price) // Buy new plan - _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, testCase.plan.Index, int(testCase.duration), false, true) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, testCase.plan.Index, int(testCase.duration), false, true) require.NotNil(t, err, testName) // Make sure the balance is not changed @@ -1498,24 +1500,24 @@ func TestSubscriptionAdvancePurchaseFailOnCheaperPlans_NewBlock(t *testing.T) { startingDuration := int64(3) // Original cost: 200 * 3 = 600 - consumerAcc, consumerAdd := ts.Account("sub1") + consumerAcc, consumerAddr := ts.Account("sub1") consumerBalance := ts.GetBalance(consumerAcc.Addr) // Buy medium plan - _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, 1, false, false) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, 1, false, false) require.Nil(t, err) // Verify subscription found inside getSubscription - getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) // Make sure the balance checks out consumerBalance -= mediumPlan.Price.Amount.Int64() require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) // Buy future medium plan - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlan.Index, int(startingDuration), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, int(startingDuration), false, true) require.Nil(t, err) // Verify subscription found inside getSubscription - getSubscriptionAndFailTestIfNotFound(t, ts, consumerAdd) + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) // Make sure the balance checks out consumerBalance -= mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() @@ -1531,7 +1533,7 @@ func TestSubscriptionAdvancePurchaseFailOnCheaperPlans_NewBlock(t *testing.T) { ts.AddPlan(mediumPlanCheaper.Index, mediumPlanCheaper) // Buy new plan - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(startingDuration+3), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanCheaper.Index, int(startingDuration+3), false, true) require.NotNil(t, err, "Same plan && cheaper && more duration -> Price: "+ mediumPlanCheaper.Price.Amount.MulRaw(startingDuration+3).String()) // 600 @@ -1539,7 +1541,7 @@ func TestSubscriptionAdvancePurchaseFailOnCheaperPlans_NewBlock(t *testing.T) { require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) // Buy new plan - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(startingDuration+2), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanCheaper.Index, int(startingDuration+2), false, true) require.NotNil(t, err, "Same plan && cheaper && more duration -> Price: "+ mediumPlanCheaper.Price.Amount.MulRaw(startingDuration+2).String()) // 500 @@ -1556,7 +1558,7 @@ func TestSubscriptionAdvancePurchaseFailOnCheaperPlans_NewBlock(t *testing.T) { ts.AddPlan(mediumPlanExpensive.Index, mediumPlanExpensive) // Buy new plan - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(startingDuration-1), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanCheaper.Index, int(startingDuration-1), false, true) require.NotNil(t, err, "Same plan && cheaper && more duration -> Price: "+ mediumPlanCheaper.Price.Amount.MulRaw(startingDuration-1).String()) // 600 @@ -1564,7 +1566,7 @@ func TestSubscriptionAdvancePurchaseFailOnCheaperPlans_NewBlock(t *testing.T) { require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) // Buy new plan - _, err = ts.TxSubscriptionBuy(consumerAdd, consumerAdd, mediumPlanCheaper.Index, int(startingDuration-2), false, true) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanCheaper.Index, int(startingDuration-2), false, true) require.NotNil(t, err, "Same plan && cheaper && more duration -> Price: "+ mediumPlanCheaper.Price.Amount.MulRaw(startingDuration-2).String()) // 500 @@ -1576,19 +1578,94 @@ func TestSubscriptionAdvancePurchaseFailOnNoSubscription(t *testing.T) { ts := newTester(t) ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev - consumerAcc, consumerAdd := ts.Account("sub1") + consumerAcc, consumerAddr := ts.Account("sub1") premiumPlan := ts.Plan("premium") consumerBalance := ts.GetBalance(consumerAcc.Addr) // Advance purchase the subscription with no active subscription newSubDuration := int64(4) - _, err := ts.TxSubscriptionBuy(consumerAdd, consumerAdd, premiumPlan.Index, int(newSubDuration), false, true) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, premiumPlan.Index, int(newSubDuration), false, true) require.NotNil(t, err) // Verify that the consumer is not charged require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) // Verify that there is no new subscription - _, found := ts.getSubscription(consumerAdd) + _, found := ts.getSubscription(consumerAddr) require.False(t, found) } + +func TestSubscriptionAdvancePurchaseNewCreator(t *testing.T) { + ts := newTester(t) + ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + + creator1Acc, creator1Addr := ts.AddAccount("sugar1", 0, 20000) + creator1Balance := ts.GetBalance(creator1Acc.Addr) + + creator2Acc, creator2Addr := ts.AddAccount("sugar2", 1, 20000) + creator2Balance := ts.GetBalance(creator2Acc.Addr) + + consumerAcc, consumerAddr := ts.Account("sub1") + consumerBalance := ts.GetBalance(consumerAcc.Addr) + freePlan := ts.Plan("free") + premiumPlan := ts.Plan("premium") + + // Buy free plan + freePlanDuration := int64(2) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, freePlan.Index, int(freePlanDuration), false, false) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) + consumerBalance -= freePlan.Price.Amount.MulRaw(freePlanDuration).Int64() + // Make sure that creator1 payed for the subscription + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Creator1 buys a future subscription + newSubDuration := uint64(1) + _, err = ts.TxSubscriptionBuy(creator1Addr, consumerAddr, premiumPlan.Index, int(newSubDuration), false, true) + require.Nil(t, err) + + // Make sure that creator1 payed for the new subscription + creator1Balance -= premiumPlan.Price.Amount.MulRaw(int64(newSubDuration)).Int64() + require.Equal(t, creator1Balance, ts.GetBalance(creator1Acc.Addr)) + + // Trigger new subscription + ts.AdvanceMonths(int(freePlanDuration)).AdvanceEpoch() + + // Make sure that creator1 is now the creator of the subscription + sub := getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) + require.Nil(t, sub.FutureSubscription) + require.Equal(t, creator1Addr, sub.Creator) + + // Creator2 buys a future subscription + _, err = ts.TxSubscriptionBuy(creator2Addr, consumerAddr, premiumPlan.Index, int(newSubDuration), false, true) + require.Nil(t, err) + + // Make sure that creator2 payed for the new subscription + creator2Balance -= premiumPlan.Price.Amount.MulRaw(int64(newSubDuration)).Int64() + require.Equal(t, creator2Balance, ts.GetBalance(creator2Acc.Addr)) + + // Trigger new subscription + ts.AdvanceMonths(int(newSubDuration)).AdvanceEpoch() + + // Make sure that creator2 is now the creator of the subscription + sub = getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) + require.Nil(t, sub.FutureSubscription) + require.Equal(t, creator2Addr, sub.Creator) + + // Original consumer buys a future subscription + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, premiumPlan.Index, int(newSubDuration), false, true) + require.Nil(t, err) + + // Make sure that consumer payed for the new subscription + consumerBalance -= premiumPlan.Price.Amount.MulRaw(int64(newSubDuration)).Int64() + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Trigger new subscription + ts.AdvanceMonths(int(newSubDuration)).AdvanceEpoch() + + // Make sure that consumer is now the creator of the subscription + sub = getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) + require.Nil(t, sub.FutureSubscription) + require.Equal(t, consumerAddr, sub.Creator) +} diff --git a/x/subscription/types/subscription.pb.go b/x/subscription/types/subscription.pb.go index 51e91ab16e..f131a31091 100644 --- a/x/subscription/types/subscription.pb.go +++ b/x/subscription/types/subscription.pb.go @@ -171,9 +171,10 @@ func (m *Subscription) GetFutureSubscription() *FutureSubscription { } type FutureSubscription struct { - PlanIndex string `protobuf:"bytes,1,opt,name=plan_index,json=planIndex,proto3" json:"plan_index,omitempty"` - PlanBlock uint64 `protobuf:"varint,2,opt,name=plan_block,json=planBlock,proto3" json:"plan_block,omitempty"` - DurationBought uint64 `protobuf:"varint,3,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + PlanIndex string `protobuf:"bytes,2,opt,name=plan_index,json=planIndex,proto3" json:"plan_index,omitempty"` + PlanBlock uint64 `protobuf:"varint,3,opt,name=plan_block,json=planBlock,proto3" json:"plan_block,omitempty"` + DurationBought uint64 `protobuf:"varint,4,opt,name=duration_bought,json=durationBought,proto3" json:"duration_bought,omitempty"` } func (m *FutureSubscription) Reset() { *m = FutureSubscription{} } @@ -209,6 +210,13 @@ func (m *FutureSubscription) XXX_DiscardUnknown() { var xxx_messageInfo_FutureSubscription proto.InternalMessageInfo +func (m *FutureSubscription) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + func (m *FutureSubscription) GetPlanIndex() string { if m != nil { return m.PlanIndex @@ -240,35 +248,36 @@ func init() { } var fileDescriptor_c3bc5507ca237d79 = []byte{ - // 447 bytes of a gzipped FileDescriptorProto + // 452 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xcf, 0x6e, 0xd3, 0x40, 0x10, 0xc6, 0xb3, 0xad, 0xdb, 0x3a, 0x93, 0xbf, 0x2c, 0x1c, 0x16, 0x24, 0xac, 0x10, 0x40, 0x44, 0xa8, 0x38, 0x12, 0xbc, 0x41, 0x10, 0x95, 0xa8, 0x38, 0x99, 0x9e, 0x38, 0x60, 0xd9, 0xee, 0xa6, - 0xb1, 0xb0, 0xbd, 0xd6, 0x7a, 0x16, 0x52, 0xf1, 0x12, 0x3c, 0x08, 0x0f, 0xc2, 0xb1, 0x47, 0x8e, - 0x28, 0x79, 0x11, 0xe4, 0x71, 0x62, 0x39, 0x04, 0x50, 0x4f, 0xab, 0xf9, 0xcd, 0xf7, 0x79, 0xbc, - 0xfb, 0x69, 0xe0, 0x34, 0x09, 0x3e, 0x07, 0x99, 0xc4, 0x69, 0x79, 0x4e, 0x0b, 0x13, 0x16, 0x91, - 0x8e, 0x73, 0x8c, 0x55, 0xb6, 0x53, 0xb8, 0xb9, 0x56, 0xa8, 0xf8, 0xfd, 0x8d, 0xda, 0x2d, 0x4f, - 0xb7, 0x29, 0x18, 0x7f, 0xb7, 0xa0, 0xfb, 0xbe, 0x01, 0xb8, 0x80, 0x93, 0x48, 0xcb, 0x00, 0x95, - 0x16, 0x6c, 0xc4, 0x26, 0x6d, 0x6f, 0x5b, 0xf2, 0x07, 0x60, 0x47, 0x2a, 0x2b, 0x4c, 0x2a, 0xb5, - 0x38, 0xa0, 0x56, 0x5d, 0xf3, 0x7b, 0x70, 0x14, 0x26, 0x2a, 0xfa, 0x24, 0x0e, 0x47, 0x6c, 0x62, - 0x79, 0x55, 0xc1, 0x1f, 0x02, 0xe4, 0x49, 0x90, 0xf9, 0x71, 0x76, 0x29, 0x97, 0xc2, 0x22, 0x4f, - 0xbb, 0x24, 0x6f, 0x4b, 0x50, 0xb7, 0x2b, 0xe7, 0x11, 0x39, 0xa9, 0x3d, 0x23, 0xf7, 0x33, 0x18, - 0x5c, 0x1a, 0x1d, 0x94, 0x7f, 0xe5, 0x87, 0xca, 0x5c, 0x2d, 0x50, 0x1c, 0x93, 0xa6, 0xbf, 0xc5, - 0x33, 0xa2, 0xfc, 0x31, 0xf4, 0x6a, 0x61, 0x22, 0xe7, 0x28, 0x4e, 0x48, 0xd6, 0xdd, 0xc2, 0x77, - 0x72, 0x8e, 0xfc, 0x39, 0xdc, 0x49, 0x55, 0x86, 0x0b, 0x5f, 0x2e, 0xf3, 0x58, 0x5f, 0xfb, 0x18, - 0xa7, 0x52, 0xd8, 0x24, 0x1c, 0x50, 0xe3, 0x0d, 0xf1, 0x8b, 0x38, 0x95, 0xfc, 0x09, 0xf4, 0x2b, - 0x6d, 0x64, 0x7c, 0x54, 0x18, 0x24, 0x02, 0xaa, 0x2f, 0x12, 0x7d, 0x6d, 0x2e, 0x4a, 0xc6, 0xc7, - 0xd0, 0xab, 0x55, 0x34, 0xb6, 0x43, 0xa2, 0xce, 0x46, 0x44, 0x53, 0xcb, 0xd7, 0x4c, 0x4c, 0x81, - 0x52, 0x8b, 0xde, 0xe6, 0x35, 0xab, 0x92, 0x3f, 0x85, 0xfa, 0x1a, 0x9b, 0x19, 0x7d, 0xb2, 0xd7, - 0x57, 0xa9, 0x86, 0x3c, 0x82, 0x6e, 0x60, 0x50, 0xf9, 0x5a, 0x66, 0xf2, 0x4b, 0x90, 0x88, 0xc1, - 0x88, 0x4d, 0x6c, 0xaf, 0x53, 0x32, 0xaf, 0x42, 0xfc, 0x23, 0xdc, 0x9d, 0x1b, 0x34, 0x5a, 0xfa, - 0xcd, 0x64, 0xc5, 0x70, 0xc4, 0x26, 0x9d, 0x97, 0x2f, 0xdc, 0x7f, 0x66, 0xef, 0x9e, 0x91, 0xab, - 0x99, 0xbe, 0xc7, 0xe7, 0x7b, 0xec, 0xdc, 0xb2, 0xdb, 0x43, 0x38, 0xb7, 0xec, 0xee, 0xb0, 0x37, - 0xfe, 0x0a, 0x7c, 0xdf, 0xf5, 0x47, 0xce, 0xec, 0xff, 0x39, 0x1f, 0xdc, 0x22, 0xe7, 0xc3, 0xbf, - 0xe5, 0x3c, 0x3b, 0xfb, 0xb1, 0x72, 0xd8, 0xcd, 0xca, 0x61, 0xbf, 0x56, 0x0e, 0xfb, 0xb6, 0x76, - 0x5a, 0x37, 0x6b, 0xa7, 0xf5, 0x73, 0xed, 0xb4, 0x3e, 0x9c, 0x5e, 0xc5, 0xb8, 0x30, 0xa1, 0x1b, - 0xa9, 0x74, 0xba, 0xb3, 0x19, 0xcb, 0xdd, 0xdd, 0xc0, 0xeb, 0x5c, 0x16, 0xe1, 0x31, 0x6d, 0xc5, - 0xab, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x85, 0xeb, 0x7c, 0x12, 0x45, 0x03, 0x00, 0x00, + 0xb1, 0xb0, 0xbd, 0xd6, 0x7a, 0x16, 0xd2, 0xb7, 0xe0, 0xc2, 0x5b, 0xf0, 0x20, 0x1c, 0x7b, 0xe4, + 0x88, 0x92, 0x17, 0x41, 0x1e, 0x27, 0x56, 0xac, 0x42, 0xd4, 0xd3, 0x6a, 0x7e, 0xf3, 0x7d, 0x1e, + 0xef, 0xce, 0x0c, 0x9c, 0x26, 0xc1, 0xd7, 0x20, 0x93, 0x38, 0x2d, 0xcf, 0x69, 0x61, 0xc2, 0x22, + 0xd2, 0x71, 0x8e, 0xb1, 0xca, 0x1a, 0x81, 0x9b, 0x6b, 0x85, 0x8a, 0x3f, 0xdc, 0xa8, 0xdd, 0xf2, + 0x74, 0x77, 0x05, 0xe3, 0x9f, 0x16, 0x74, 0x3f, 0xee, 0x00, 0x2e, 0xe0, 0x24, 0xd2, 0x32, 0x40, + 0xa5, 0x05, 0x1b, 0xb1, 0x49, 0xdb, 0xdb, 0x86, 0xfc, 0x11, 0xd8, 0x91, 0xca, 0x0a, 0x93, 0x4a, + 0x2d, 0x0e, 0x28, 0x55, 0xc7, 0xfc, 0x01, 0x1c, 0x85, 0x89, 0x8a, 0xbe, 0x88, 0xc3, 0x11, 0x9b, + 0x58, 0x5e, 0x15, 0xf0, 0xc7, 0x00, 0x79, 0x12, 0x64, 0x7e, 0x9c, 0x5d, 0xca, 0xa5, 0xb0, 0xc8, + 0xd3, 0x2e, 0xc9, 0xfb, 0x12, 0xd4, 0xe9, 0xca, 0x79, 0x44, 0x4e, 0x4a, 0xcf, 0xc8, 0xfd, 0x02, + 0x06, 0x97, 0x46, 0x07, 0xe5, 0x5f, 0xf9, 0xa1, 0x32, 0x57, 0x0b, 0x14, 0xc7, 0xa4, 0xe9, 0x6f, + 0xf1, 0x8c, 0x28, 0x7f, 0x0a, 0xbd, 0x5a, 0x98, 0xc8, 0x39, 0x8a, 0x13, 0x92, 0x75, 0xb7, 0xf0, + 0x83, 0x9c, 0x23, 0x7f, 0x09, 0xf7, 0x52, 0x95, 0xe1, 0xc2, 0x97, 0xcb, 0x3c, 0xd6, 0xd7, 0x3e, + 0xc6, 0xa9, 0x14, 0x36, 0x09, 0x07, 0x94, 0x78, 0x47, 0xfc, 0x22, 0x4e, 0x25, 0x7f, 0x06, 0xfd, + 0x4a, 0x1b, 0x19, 0x1f, 0x15, 0x06, 0x89, 0x80, 0xea, 0x8b, 0x44, 0xdf, 0x9a, 0x8b, 0x92, 0xf1, + 0x31, 0xf4, 0x6a, 0x15, 0x95, 0xed, 0x90, 0xa8, 0xb3, 0x11, 0x51, 0xd5, 0xf2, 0x35, 0x13, 0x53, + 0xa0, 0xd4, 0xa2, 0xb7, 0x79, 0xcd, 0x2a, 0xe4, 0xcf, 0xa1, 0xbe, 0xc6, 0xa6, 0x46, 0x9f, 0xec, + 0xf5, 0x55, 0xaa, 0x22, 0x4f, 0xa0, 0x1b, 0x18, 0x54, 0xbe, 0x96, 0x99, 0xfc, 0x16, 0x24, 0x62, + 0x30, 0x62, 0x13, 0xdb, 0xeb, 0x94, 0xcc, 0xab, 0x10, 0xff, 0x0c, 0xf7, 0xe7, 0x06, 0x8d, 0x96, + 0xfe, 0x6e, 0x67, 0xc5, 0x70, 0xc4, 0x26, 0x9d, 0xd7, 0xaf, 0xdc, 0xff, 0xf6, 0xde, 0x3d, 0x23, + 0xd7, 0x6e, 0xf7, 0x3d, 0x3e, 0xbf, 0xc5, 0xce, 0x2d, 0xbb, 0x3d, 0x84, 0x73, 0xcb, 0xee, 0x0e, + 0x7b, 0xe3, 0x1f, 0x0c, 0xf8, 0x6d, 0xdb, 0x9e, 0xa1, 0x69, 0x8e, 0xc0, 0xc1, 0xfe, 0x11, 0x38, + 0xbc, 0xc3, 0x08, 0x58, 0xff, 0x1a, 0x81, 0xd9, 0xd9, 0xaf, 0x95, 0xc3, 0x6e, 0x56, 0x0e, 0xfb, + 0xb3, 0x72, 0xd8, 0xf7, 0xb5, 0xd3, 0xba, 0x59, 0x3b, 0xad, 0xdf, 0x6b, 0xa7, 0xf5, 0xe9, 0xf4, + 0x2a, 0xc6, 0x85, 0x09, 0xdd, 0x48, 0xa5, 0xd3, 0xc6, 0xd2, 0x2c, 0x9b, 0x6b, 0x83, 0xd7, 0xb9, + 0x2c, 0xc2, 0x63, 0x5a, 0x98, 0x37, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xb1, 0xdc, 0x42, 0x8e, + 0x60, 0x03, 0x00, 0x00, } func (m *Subscription) Marshal() (dAtA []byte, err error) { @@ -409,18 +418,25 @@ func (m *FutureSubscription) MarshalToSizedBuffer(dAtA []byte) (int, error) { if m.DurationBought != 0 { i = encodeVarintSubscription(dAtA, i, uint64(m.DurationBought)) i-- - dAtA[i] = 0x18 + dAtA[i] = 0x20 } if m.PlanBlock != 0 { i = encodeVarintSubscription(dAtA, i, uint64(m.PlanBlock)) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x18 } if len(m.PlanIndex) > 0 { i -= len(m.PlanIndex) copy(dAtA[i:], m.PlanIndex) i = encodeVarintSubscription(dAtA, i, uint64(len(m.PlanIndex))) i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintSubscription(dAtA, i, uint64(len(m.Creator))) + i-- dAtA[i] = 0xa } return len(dAtA) - i, nil @@ -499,6 +515,10 @@ func (m *FutureSubscription) Size() (n int) { } var l int _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovSubscription(uint64(l)) + } l = len(m.PlanIndex) if l > 0 { n += 1 + l + sovSubscription(uint64(l)) @@ -934,6 +954,38 @@ func (m *FutureSubscription) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSubscription + } + 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 ErrInvalidLengthSubscription + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSubscription + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field PlanIndex", wireType) } @@ -965,7 +1017,7 @@ func (m *FutureSubscription) Unmarshal(dAtA []byte) error { } m.PlanIndex = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 3: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field PlanBlock", wireType) } @@ -984,7 +1036,7 @@ func (m *FutureSubscription) Unmarshal(dAtA []byte) error { break } } - case 3: + case 4: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field DurationBought", wireType) } From 4620db68491b3e8207000f6f58932aa066698814 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 21 Dec 2023 12:00:15 -0500 Subject: [PATCH 11/29] Fix typo --- x/subscription/keeper/subscription_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index 6d298cf11f..1f4231b5e6 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -1617,7 +1617,7 @@ func TestSubscriptionAdvancePurchaseNewCreator(t *testing.T) { // Verify subscription found inside getSubscription getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) consumerBalance -= freePlan.Price.Amount.MulRaw(freePlanDuration).Int64() - // Make sure that creator1 payed for the subscription + // Make sure that creator1 paid for the subscription require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) // Creator1 buys a future subscription @@ -1625,7 +1625,7 @@ func TestSubscriptionAdvancePurchaseNewCreator(t *testing.T) { _, err = ts.TxSubscriptionBuy(creator1Addr, consumerAddr, premiumPlan.Index, int(newSubDuration), false, true) require.Nil(t, err) - // Make sure that creator1 payed for the new subscription + // Make sure that creator1 paid for the new subscription creator1Balance -= premiumPlan.Price.Amount.MulRaw(int64(newSubDuration)).Int64() require.Equal(t, creator1Balance, ts.GetBalance(creator1Acc.Addr)) @@ -1641,7 +1641,7 @@ func TestSubscriptionAdvancePurchaseNewCreator(t *testing.T) { _, err = ts.TxSubscriptionBuy(creator2Addr, consumerAddr, premiumPlan.Index, int(newSubDuration), false, true) require.Nil(t, err) - // Make sure that creator2 payed for the new subscription + // Make sure that creator2 paid for the new subscription creator2Balance -= premiumPlan.Price.Amount.MulRaw(int64(newSubDuration)).Int64() require.Equal(t, creator2Balance, ts.GetBalance(creator2Acc.Addr)) @@ -1657,7 +1657,7 @@ func TestSubscriptionAdvancePurchaseNewCreator(t *testing.T) { _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, premiumPlan.Index, int(newSubDuration), false, true) require.Nil(t, err) - // Make sure that consumer payed for the new subscription + // Make sure that consumer paid for the new subscription consumerBalance -= premiumPlan.Price.Amount.MulRaw(int64(newSubDuration)).Int64() require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) From 277d168723045bc10763f4e60eba12b6057bff81 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 21 Dec 2023 13:11:54 -0500 Subject: [PATCH 12/29] Bug fix + CR Fix: Reset DurationTotal --- x/subscription/keeper/subscription.go | 13 ++++++++++++- x/subscription/keeper/subscription_test.go | 11 ++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 058c38cb62..c55d710cc5 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -272,13 +272,24 @@ func (k Keeper) advanceMonth(ctx sdk.Context, subkey []byte) { // Consumer made advance purchase. Now we activate it. newSubInfo := sub.FutureSubscription + plan, found := k.plansKeeper.GetPlan(ctx, newSubInfo.PlanIndex) + if !found { + utils.LavaFormatWarning("subscription advance purchase failed: could not find plan. removing subscription", nil, + utils.Attribute{Key: "consumer", Value: sub.Consumer}, + utils.Attribute{Key: "planIndex", Value: newSubInfo.PlanIndex}, + ) + k.RemoveExpiredSubscription(ctx, consumer, block, sub.PlanIndex, sub.PlanBlock) + return + } + sub.Creator = newSubInfo.Creator sub.PlanIndex = newSubInfo.PlanIndex sub.PlanBlock = newSubInfo.PlanBlock sub.DurationBought = newSubInfo.DurationBought sub.DurationLeft = newSubInfo.DurationBought - sub.DurationTotal += 1 + sub.DurationTotal = 0 sub.FutureSubscription = nil + sub.MonthCuTotal = plan.PlanPolicy.TotalCuLimit k.resetSubscriptionDetailsAndAppendEntry(ctx, &sub, block, date) } else if sub.AutoRenewal { diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index 0b088e6e08..6e1a1311aa 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -31,6 +31,8 @@ func newTester(t *testing.T) *tester { premiumPlan.Index = "premium" premiumPlan.Price = freePlan.Price.AddAmount(math.NewInt(100)) premiumPlan.Block = ts.BlockHeight() + premiumPlan.PlanPolicy.TotalCuLimit += 100 + premiumPlan.PlanPolicy.EpochCuLimit += 10 ts.AddPlan(premiumPlan.Index, premiumPlan) return ts @@ -1114,8 +1116,10 @@ func TestSubscriptionCuExhaustAndUpgrade(t *testing.T) { func TestSubscriptionAdvancePurchaseStartsOnExpirationOfCurrent(t *testing.T) { ts := newTester(t) ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + ts.AddSpec("myspec", common.CreateMockSpec()) consumerAcc, consumerAddr := ts.Account("sub1") + spec := ts.Spec("myspec") freePlan := ts.Plan("free") premiumPlan := ts.Plan("premium") consumerBalance := ts.GetBalance(consumerAcc.Addr) @@ -1166,7 +1170,12 @@ func TestSubscriptionAdvancePurchaseStartsOnExpirationOfCurrent(t *testing.T) { require.Equal(t, premiumPlan.Block, sub.PlanBlock) require.Equal(t, newSubDuration, sub.DurationBought) require.Equal(t, newSubDuration, sub.DurationLeft) - require.Equal(t, uint64(2), sub.DurationTotal) + require.Equal(t, uint64(0), sub.DurationTotal) + require.Equal(t, premiumPlan.PlanPolicy.TotalCuLimit, sub.MonthCuTotal) + + pairingEffectivePolicy, err := ts.QueryPairingEffectivePolicy(spec.Index, consumerAddr) + require.NoError(t, err) + require.Equal(t, premiumPlan.PlanPolicy.EpochCuLimit, pairingEffectivePolicy.Policy.EpochCuLimit) } func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_SameBlock(t *testing.T) { From 45b4e2d8c333118aac7ad1934fb9daadfe3a00cf Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 21 Dec 2023 14:16:18 -0500 Subject: [PATCH 13/29] Add PutPlan to old plan when upgrading subscription --- x/subscription/keeper/subscription.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index c55d710cc5..dd2ca1a897 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -237,6 +237,9 @@ func (k Keeper) upgradeSubscriptionPlan(ctx sdk.Context, duration uint64, sub *t utils.LogAttr("consumer", sub.Consumer)) } + // Remove one refcount for previous plan + k.plansKeeper.PutPlan(ctx, sub.PlanIndex, sub.PlanBlock) + sub.PlanIndex = toPlanIndex sub.PlanBlock = toPlanBlock From 4d3c36f74c9c33c755e5ab57d384eef5cd573b25 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 08:41:40 -0500 Subject: [PATCH 14/29] Rename function verifySubscriptionBuyInput to be more clear --- x/subscription/keeper/subscription.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index dd2ca1a897..f8b1d898da 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -35,7 +35,7 @@ func (k Keeper) CreateSubscription( var err error block := uint64(ctx.BlockHeight()) - creatorAcct, plan, err := k.verifySubscriptionBuyInput(ctx, block, creator, consumer, planIndex) + creatorAcct, plan, err := k.verifySubscriptionBuyInputAndGetPlan(ctx, block, creator, consumer, planIndex) if err != nil { return err } @@ -161,7 +161,7 @@ func (k Keeper) CreateSubscription( return err } -func (k Keeper) verifySubscriptionBuyInput(ctx sdk.Context, block uint64, creator, consumer, planIndex string) (creatorAcct sdk.AccAddress, plan planstypes.Plan, err error) { +func (k Keeper) verifySubscriptionBuyInputAndGetPlan(ctx sdk.Context, block uint64, creator, consumer, planIndex string) (creatorAcct sdk.AccAddress, plan planstypes.Plan, err error) { EMPTY_PLAN := planstypes.Plan{} if _, err := sdk.AccAddressFromBech32(consumer); err != nil { @@ -420,7 +420,7 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, var err error block := uint64(ctx.BlockHeight()) - creatorAcct, plan, err := k.verifySubscriptionBuyInput(ctx, block, creator, consumer, planIndex) + creatorAcct, plan, err := k.verifySubscriptionBuyInputAndGetPlan(ctx, block, creator, consumer, planIndex) if err != nil { return err } From 01777ebbe4bf855682f80eb0debaee36874ce310 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 08:42:14 -0500 Subject: [PATCH 15/29] Call PutPlan for prev plan after plan upgrade --- x/subscription/keeper/subscription.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index f8b1d898da..4239a59543 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -84,11 +84,16 @@ func (k Keeper) CreateSubscription( utils.LogAttr("block", block), ) } + originalPlanIndex := sub.PlanIndex + originalPlanBlock := sub.PlanBlock err = k.upgradeSubscriptionPlan(ctx, duration, &sub, plan.Index, plan.Block) if err != nil { return err } + // Upgrade worked, now we can decrease the old plan's refcount + k.plansKeeper.PutPlan(ctx, originalPlanIndex, originalPlanBlock) + details := map[string]string{ "consumer": consumer, "oldPlan": sub.PlanIndex, From 8694a6b8be1317b68c8930bd6cc67b4bb7698861 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 08:55:45 -0500 Subject: [PATCH 16/29] Return the error from resetSubscriptionDetailsAndAppendEntry --- x/subscription/keeper/subscription.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 4239a59543..b3d22f418a 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -248,9 +248,7 @@ func (k Keeper) upgradeSubscriptionPlan(ctx sdk.Context, duration uint64, sub *t sub.PlanIndex = toPlanIndex sub.PlanBlock = toPlanBlock - k.resetSubscriptionDetailsAndAppendEntry(ctx, sub, nextEpoch, date) - - return nil + return k.resetSubscriptionDetailsAndAppendEntry(ctx, sub, nextEpoch, date) } func (k Keeper) advanceMonth(ctx sdk.Context, subkey []byte) { @@ -358,7 +356,7 @@ func (k Keeper) handleZeroDurationLeftForSubscription(ctx sdk.Context, block uin k.subsTS.AddTimerByBlockTime(ctx, expiry, []byte(sub.Consumer), []byte{}) } -func (k Keeper) resetSubscriptionDetailsAndAppendEntry(ctx sdk.Context, sub *types.Subscription, block uint64, blockTime time.Time) { +func (k Keeper) resetSubscriptionDetailsAndAppendEntry(ctx sdk.Context, sub *types.Subscription, block uint64, blockTime time.Time) error { // reset projects CU allowance for this coming month k.projectsKeeper.SnapshotSubscriptionProjects(ctx, sub.Consumer, block) @@ -376,14 +374,19 @@ func (k Keeper) resetSubscriptionDetailsAndAppendEntry(ctx sdk.Context, sub *typ err := k.subsFS.AppendEntry(ctx, sub.Consumer, block, sub) if err != nil { + // Remove new timer if failed + k.subsTS.DelTimerByBlockTime(ctx, expiry, []byte(sub.Consumer)) + // normally would panic! but ok to ignore - the subscription remains // as is with same remaining duration (but not renewed CU) - utils.LavaFormatError("critical: failed to recharge subscription", err, + return utils.LavaFormatError("critical: failed to recharge subscription", err, utils.Attribute{Key: "consumer", Value: sub.Consumer}, utils.Attribute{Key: "plan", Value: sub.PlanIndex}, utils.Attribute{Key: "block", Value: block}, ) } + + return nil } func (k Keeper) applyPlanDiscountIfEligible(duration uint64, plan *planstypes.Plan, price *sdk.Coin) { From 9711290f20707be8ba311e8aaf23539ea371d5e8 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 08:58:55 -0500 Subject: [PATCH 17/29] Use FindPlan instead of GetPlan in advanceMonth --- x/subscription/keeper/subscription.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index b3d22f418a..2162c0a0bc 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -278,7 +278,7 @@ func (k Keeper) advanceMonth(ctx sdk.Context, subkey []byte) { // Consumer made advance purchase. Now we activate it. newSubInfo := sub.FutureSubscription - plan, found := k.plansKeeper.GetPlan(ctx, newSubInfo.PlanIndex) + plan, found := k.plansKeeper.FindPlan(ctx, newSubInfo.PlanIndex, newSubInfo.PlanBlock) if !found { utils.LavaFormatWarning("subscription advance purchase failed: could not find plan. removing subscription", nil, utils.Attribute{Key: "consumer", Value: sub.Consumer}, From b6dddab73b997bdb2cb9d0c4bfa86c02efee33fa Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 09:00:05 -0500 Subject: [PATCH 18/29] Test Fix --- x/subscription/keeper/subscription_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index 6e1a1311aa..f13e23fd71 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -1317,7 +1317,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) // Buy medium plan _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, 1, false, false) - require.Nil(t, err) + require.NoError(t, err) // Verify subscription found inside getSubscription getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) @@ -1327,7 +1327,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) // Buy future medium plan _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlan.Index, int(startingDuration), false, true) - require.Nil(t, err) + require.NoError(t, err) // Verify subscription found inside getSubscription getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) @@ -1348,9 +1348,9 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) newPlanDuration := startingDuration + 3 // 5 newPlanCost := mediumPlanCheaper.Price.Amount.MulRaw(newPlanDuration) // 500 _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanCheaper.Index, int(newPlanDuration), false, true) - require.Nil(t, err, "Same plan && cheaper && more duration -> Price: "+newPlanCost.String()) + require.NoError(t, err, "Same plan && cheaper && more duration -> Price: "+newPlanCost.String()) - priceDiff := newPlanCost.Sub(originalPlanCost).Int64() + priceDiff := newPlanCost.Sub(mediumPlan.Price.Amount).Int64() consumerBalance -= priceDiff // Make sure the balance has changed @@ -1369,7 +1369,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) newPlanDuration = startingDuration - 1 // 1 newPlanCost = mediumPlanExpensive.Price.Amount.MulRaw(newPlanDuration) // 600 _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanExpensive.Index, int(newPlanDuration), false, true) - require.Nil(t, err, "Same plan && more expensive && less duration -> Price: "+newPlanCost.String()) + require.NoError(t, err, "Same plan && more expensive && less duration -> Price: "+newPlanCost.String()) priceDiff = newPlanCost.Sub(originalPlanCost).Int64() consumerBalance -= priceDiff @@ -1381,7 +1381,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) newPlanDuration = startingDuration // 2 newPlanCost = mediumPlanExpensive.Price.Amount.MulRaw(newPlanDuration) // 1200 _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanExpensive.Index, int(newPlanDuration), false, true) - require.Nil(t, err, "Same plan && more expensive && same duration -> Price: "+newPlanCost.String()) + require.NoError(t, err, "Same plan && more expensive && same duration -> Price: "+newPlanCost.String()) priceDiff = newPlanCost.Sub(originalPlanCost).Int64() consumerBalance -= priceDiff @@ -1393,7 +1393,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) newPlanDuration = startingDuration + 1 // 3 newPlanCost = mediumPlanExpensive.Price.Amount.MulRaw(newPlanDuration) // 1800 _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanExpensive.Index, int(newPlanDuration), false, true) - require.Nil(t, err, "Same plan && more expensive && more duration -> Price: "+newPlanCost.String()) + require.NoError(t, err, "Same plan && more expensive && more duration -> Price: "+newPlanCost.String()) priceDiff = newPlanCost.Sub(originalPlanCost).Int64() consumerBalance -= priceDiff From d1cdacb13c784c24012469435a11ed2bccec5ef8 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 09:00:24 -0500 Subject: [PATCH 19/29] Bug fix in FutureSubscription --- x/subscription/keeper/subscription.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 2162c0a0bc..97c09cda85 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -455,10 +455,11 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, if sub.FutureSubscription != nil { // Consumer already has a future subscription // If the new plan's price > current future subscription's plan - change and charge the diff - currentPlan, err := k.GetPlanFromSubscription(ctx, consumer, block) - if err != nil { - return utils.LavaFormatError("panic: could not get active subscription's plan. aborting", err, + currentPlan, found := k.plansKeeper.FindPlan(ctx, sub.FutureSubscription.PlanIndex, sub.FutureSubscription.PlanBlock) + if !found { + return utils.LavaFormatError("panic: could not future subscription's plan. aborting", err, utils.Attribute{Key: "creator", Value: creator}, + utils.Attribute{Key: "planIndex", Value: sub.FutureSubscription.PlanIndex}, ) } From 925952e91666c3958cd8f324022528f64b4326c1 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 09:00:54 -0500 Subject: [PATCH 20/29] CR Fix: Annual discount in future subscription --- x/subscription/keeper/subscription.go | 13 ++++- x/subscription/keeper/subscription_test.go | 59 ++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 97c09cda85..ef97823118 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -464,7 +464,18 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, } newPlanCostForDuration := plan.Price.Amount.MulRaw(int64(duration)) - consumerPaid := currentPlan.Price.Amount.MulRaw(int64(sub.FutureSubscription.DurationBought)) + // Take into consideration the annually discount + newPlanCostCoin := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), newPlanCostForDuration) + k.applyPlanDiscountIfEligible(duration, &plan, &newPlanCostCoin) + newPlanCostForDuration = newPlanCostCoin.Amount + + consumerOriginalBoughtDuration := sub.FutureSubscription.DurationBought + consumerPaid := currentPlan.Price.Amount.MulRaw(int64(consumerOriginalBoughtDuration)) + // Take into consideration the annually discount + consumerPaidCoin := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), consumerPaid) + k.applyPlanDiscountIfEligible(uint64(consumerOriginalBoughtDuration), &plan, &consumerPaidCoin) + consumerPaid = consumerPaidCoin.Amount + if newPlanCostForDuration.GT(consumerPaid) { priceDiff := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), newPlanCostForDuration.Sub(consumerPaid)) err = k.chargeFromCreatorAccountToModule(ctx, creatorAcct, priceDiff) diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index f13e23fd71..eba59d73f3 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -31,6 +31,7 @@ func newTester(t *testing.T) *tester { premiumPlan.Index = "premium" premiumPlan.Price = freePlan.Price.AddAmount(math.NewInt(100)) premiumPlan.Block = ts.BlockHeight() + premiumPlan.AnnualDiscountPercentage += 5 premiumPlan.PlanPolicy.TotalCuLimit += 100 premiumPlan.PlanPolicy.EpochCuLimit += 10 ts.AddPlan(premiumPlan.Index, premiumPlan) @@ -1716,3 +1717,61 @@ func TestSubscriptionAdvancePurchaseNewCreator(t *testing.T) { require.Nil(t, sub.FutureSubscription) require.Equal(t, consumerAddr, sub.Creator) } + +func TestSubscriptionAdvancePurchaseAnnuallyDiscount(t *testing.T) { + ts := newTester(t) + ts.SetupAccounts(1, 0, 0) // 1 sub, 0 adm, 0 dev + + consumerAcc, consumerAddr := ts.Account("sub1") + consumerBalance := ts.GetBalance(consumerAcc.Addr) + freePlan := ts.Plan("free") + premiumPlan := ts.Plan("premium") + + premiumPlusPlan := common.CreateMockPlan() + premiumPlusPlan.Index = "premiumPlus" + premiumPlusPlan.Price = premiumPlan.Price.AddAmount(math.NewInt(100)) + premiumPlusPlan.Block = ts.BlockHeight() + premiumPlusPlan.AnnualDiscountPercentage += 5 + premiumPlusPlan.PlanPolicy.TotalCuLimit += 100 + premiumPlusPlan.PlanPolicy.EpochCuLimit += 10 + ts.AddPlan(premiumPlusPlan.Index, premiumPlusPlan) + + // Buy free plan + freePlanDuration := int64(12) + _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, freePlan.Index, int(freePlanDuration), false, false) + require.Nil(t, err) + // Verify subscription found inside getSubscription + getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) + + discount := freePlan.GetAnnualDiscountPercentage() + factor := int64(100 - discount) + freePlanPriceAfterDiscount := freePlan.Price.Amount.MulRaw(freePlanDuration).MulRaw(factor).QuoRaw(100).Int64() + consumerBalance -= freePlanPriceAfterDiscount + + // Make sure that consumer paid for the subscription + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Consumer buys a future premium subscription + newSubDuration := uint64(12) + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, premiumPlan.Index, int(newSubDuration), false, true) + require.Nil(t, err) + + // Make sure that consumer paid for the new subscription + discount = premiumPlan.GetAnnualDiscountPercentage() + factor = int64(100 - discount) + premiumPlanPriceAfterDiscount := premiumPlan.Price.Amount.MulRaw(int64(newSubDuration)).MulRaw(factor).QuoRaw(100).Int64() + consumerBalance -= premiumPlanPriceAfterDiscount + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + + // Consumer buys a future premiumPlus subscription + _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, premiumPlusPlan.Index, int(newSubDuration), false, true) + require.Nil(t, err) + + // Make sure that consumer paid for the new subscription + discount = premiumPlusPlan.GetAnnualDiscountPercentage() + factor = int64(100 - discount) + premiumPlusPlanPriceAfterDiscount := premiumPlusPlan.Price.Amount.MulRaw(int64(newSubDuration)).MulRaw(factor).QuoRaw(100).Int64() + diffPrice := premiumPlusPlanPriceAfterDiscount - premiumPlanPriceAfterDiscount + consumerBalance -= diffPrice + require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) +} From 35a31b4ef0476e078ccbf97f74eb9e6ec2b5085b Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 09:08:10 -0500 Subject: [PATCH 21/29] Bug Fix and CR Fix: Unnecessary func args --- x/subscription/keeper/subscription.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index ef97823118..3c83ef3e97 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -443,11 +443,11 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, ) } - createFutureSubscription := func(sub *types.Subscription, creator, planIndex string, planBlock, duration uint64) { + createFutureSubscription := func() { sub.FutureSubscription = &types.FutureSubscription{ Creator: creator, - PlanIndex: planIndex, - PlanBlock: planBlock, + PlanIndex: plan.Index, + PlanBlock: plan.Block, DurationBought: duration, } } @@ -483,7 +483,8 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, return err } - createFutureSubscription(&sub, creator, plan.Index, plan.Block, duration) + createFutureSubscription() + k.subsFS.ModifyEntry(ctx, consumer, sub.Block, &sub) details := map[string]string{ "creator": creator, @@ -510,8 +511,7 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, return err } - createFutureSubscription(&sub, creator, plan.Index, plan.Block, duration) - + createFutureSubscription() k.subsFS.ModifyEntry(ctx, consumer, sub.Block, &sub) return nil } From ce15660d4c7194550083ec0fdf3eaf870a0fb208 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 09:51:58 -0500 Subject: [PATCH 22/29] Fix tests --- x/subscription/keeper/subscription_test.go | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index ca98d8ebc8..3d0c35bc16 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -1316,15 +1316,18 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_SameBlock(t *testing.T) // Make sure the balance checks out require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) + prevPlanPrice := originalPlanCost for _, testCase := range testCases { testName := fmt.Sprintf("%s -> Price: %d", testCase.name, testCase.price) // Buy new plan _, err := ts.TxSubscriptionBuy(consumerAddr, consumerAddr, testCase.plan.Index, int(testCase.duration), false, true) require.Nil(t, err, testName) - priceDiff := testCase.price - originalPlanCost + priceDiff := testCase.price - prevPlanPrice consumerBalance -= priceDiff + prevPlanPrice = testCase.price + // Make sure the balance is updated require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr), testName) } @@ -1350,8 +1353,6 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) // 4. Same plan && more expensive && more duration startingDuration := int64(2) - originalPlanCost := mediumPlan.Price.Amount.MulRaw(startingDuration) - // Original cost: 200 * 2 = 400 consumerAcc, consumerAddr := ts.Account("sub1") consumerBalance := ts.GetBalance(consumerAcc.Addr) @@ -1373,7 +1374,8 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) getSubscriptionAndFailTestIfNotFound(t, ts, consumerAddr) // Make sure the balance checks out - consumerBalance -= mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() + prevPlanCost := mediumPlan.Price.Amount.MulRaw(startingDuration).Int64() + consumerBalance -= prevPlanCost require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) ts.AdvanceBlock() @@ -1391,9 +1393,11 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanCheaper.Index, int(newPlanDuration), false, true) require.NoError(t, err, "Same plan && cheaper && more duration -> Price: "+newPlanCost.String()) - priceDiff := newPlanCost.Sub(mediumPlan.Price.Amount).Int64() + priceDiff := newPlanCost.SubRaw(prevPlanCost).Int64() consumerBalance -= priceDiff + prevPlanCost = newPlanCost.Int64() + // Make sure the balance has changed require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) @@ -1412,9 +1416,11 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanExpensive.Index, int(newPlanDuration), false, true) require.NoError(t, err, "Same plan && more expensive && less duration -> Price: "+newPlanCost.String()) - priceDiff = newPlanCost.Sub(originalPlanCost).Int64() + priceDiff = newPlanCost.SubRaw(prevPlanCost).Int64() consumerBalance -= priceDiff + prevPlanCost = newPlanCost.Int64() + // Make sure the balance has changed require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) @@ -1424,9 +1430,11 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanExpensive.Index, int(newPlanDuration), false, true) require.NoError(t, err, "Same plan && more expensive && same duration -> Price: "+newPlanCost.String()) - priceDiff = newPlanCost.Sub(originalPlanCost).Int64() + priceDiff = newPlanCost.SubRaw(prevPlanCost).Int64() consumerBalance -= priceDiff + prevPlanCost = newPlanCost.Int64() + // Make sure the balance has changed require.Equal(t, consumerBalance, ts.GetBalance(consumerAcc.Addr)) @@ -1436,7 +1444,7 @@ func TestSubscriptionAdvancePurchaseSuccessOnPricierPlan_NewBlock(t *testing.T) _, err = ts.TxSubscriptionBuy(consumerAddr, consumerAddr, mediumPlanExpensive.Index, int(newPlanDuration), false, true) require.NoError(t, err, "Same plan && more expensive && more duration -> Price: "+newPlanCost.String()) - priceDiff = newPlanCost.Sub(originalPlanCost).Int64() + priceDiff = newPlanCost.SubRaw(prevPlanCost).Int64() consumerBalance -= priceDiff // Make sure the balance has changed From c7eb8c3832b7dd70bfabe3bf8039f822a2b0b48b Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 10:04:48 -0500 Subject: [PATCH 23/29] CR Fix: Find sub in next epoch --- x/subscription/keeper/subscription.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 955d1cc48b..90b4705267 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -462,7 +462,18 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, } var sub types.Subscription - found := k.subsFS.FindEntry(ctx, consumer, block, &sub) + nextEpoch, err := k.epochstorageKeeper.GetNextEpoch(ctx, block) + if err != nil { + return utils.LavaFormatError("Got an error while trying to get next epoch on CreateSubscription", err, + utils.LogAttr("consumer", sub.Consumer), + utils.LogAttr("block", block), + ) + } + + // When we make a subscription upgrade, we append the new subscription entry on the next epoch, + // but, we want to get the most updated subscription here. + // Hence, in case of user making double upgrade in the same epoch, we take the next epoch. + found := k.subsFS.FindEntry(ctx, consumer, nextEpoch, &sub) if !found { return utils.LavaFormatWarning("could not find active subscription. advanced purchase is only available for an active subscription", nil, From ae2689b0cffa1422627f0139bffc39b3785473ae Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 10:07:37 -0500 Subject: [PATCH 24/29] Fix lint --- x/subscription/keeper/subscription.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 90b4705267..0dd2cb6f06 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -512,7 +512,7 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, consumerPaid := currentPlan.Price.Amount.MulRaw(int64(consumerOriginalBoughtDuration)) // Take into consideration the annually discount consumerPaidCoin := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), consumerPaid) - k.applyPlanDiscountIfEligible(uint64(consumerOriginalBoughtDuration), &plan, &consumerPaidCoin) + k.applyPlanDiscountIfEligible(consumerOriginalBoughtDuration, &plan, &consumerPaidCoin) consumerPaid = consumerPaidCoin.Amount if newPlanCostForDuration.GT(consumerPaid) { From 45d5d61e806e6281af3e924463f1f2a09a40a984 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Fri, 22 Dec 2023 10:22:51 -0500 Subject: [PATCH 25/29] CR Fix: Union flows in CreateFutureSubscription --- x/subscription/keeper/subscription.go | 38 ++++++++------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 0dd2cb6f06..e323e5ce93 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -491,6 +491,10 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, } } + newPlanPrice := plan.GetPrice() + newPlanPrice.Amount = newPlanPrice.Amount.MulRaw(int64(duration)) + k.applyPlanDiscountIfEligible(duration, &plan, &newPlanPrice) + if sub.FutureSubscription != nil { // Consumer already has a future subscription // If the new plan's price > current future subscription's plan - change and charge the diff @@ -502,28 +506,13 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, ) } - newPlanCostForDuration := plan.Price.Amount.MulRaw(int64(duration)) - // Take into consideration the annually discount - newPlanCostCoin := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), newPlanCostForDuration) - k.applyPlanDiscountIfEligible(duration, &plan, &newPlanCostCoin) - newPlanCostForDuration = newPlanCostCoin.Amount - - consumerOriginalBoughtDuration := sub.FutureSubscription.DurationBought - consumerPaid := currentPlan.Price.Amount.MulRaw(int64(consumerOriginalBoughtDuration)) - // Take into consideration the annually discount - consumerPaidCoin := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), consumerPaid) - k.applyPlanDiscountIfEligible(consumerOriginalBoughtDuration, &plan, &consumerPaidCoin) - consumerPaid = consumerPaidCoin.Amount - - if newPlanCostForDuration.GT(consumerPaid) { - priceDiff := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), newPlanCostForDuration.Sub(consumerPaid)) - err = k.chargeFromCreatorAccountToModule(ctx, creatorAcct, priceDiff) - if err != nil { - return err - } + consumerBoughDuration := sub.FutureSubscription.DurationBought + consumerPaid := currentPlan.GetPrice() + consumerPaid.Amount = consumerPaid.Amount.MulRaw(int64(consumerBoughDuration)) + k.applyPlanDiscountIfEligible(consumerBoughDuration, &plan, &consumerPaid) - createFutureSubscription() - k.subsFS.ModifyEntry(ctx, consumer, sub.Block, &sub) + if newPlanPrice.Amount.GT(consumerPaid.Amount) { + newPlanPrice.Amount = newPlanPrice.Amount.Sub(consumerPaid.Amount) details := map[string]string{ "creator": creator, @@ -535,17 +524,12 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, "newPlanBlock": strconv.FormatUint(plan.Block, 10), } utils.LogLavaEvent(ctx, k.Logger(ctx), types.AdvancedBuyUpgradeSubscriptionEventName, details, "advanced subscription upgraded") - return nil } else { return utils.LavaFormatWarning("can't purchase another plan in advanced with a lower price", nil) } } - price := plan.GetPrice() - price.Amount = price.Amount.MulRaw(int64(duration)) - k.applyPlanDiscountIfEligible(duration, &plan, &price) - - err = k.chargeFromCreatorAccountToModule(ctx, creatorAcct, price) + err = k.chargeFromCreatorAccountToModule(ctx, creatorAcct, newPlanPrice) if err != nil { return err } From 3d3762fc24e56805f81b1a9057d77dedaf071a14 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 24 Dec 2023 06:51:44 -0500 Subject: [PATCH 26/29] CR Fix: Add creator and consumer to log --- x/subscription/keeper/subscription.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index e323e5ce93..7d386cac03 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -195,6 +195,8 @@ func (k Keeper) verifySubscriptionBuyInputAndGetPlan(ctx sdk.Context, block uint plan, found := k.plansKeeper.GetPlan(ctx, planIndex) if !found { return nil, EMPTY_PLAN, utils.LavaFormatWarning("cannot create subscription with invalid plan", nil, + utils.Attribute{Key: "creator", Value: creator}, + utils.Attribute{Key: "consumer", Value: consumer}, utils.Attribute{Key: "plan", Value: planIndex}, utils.Attribute{Key: "block", Value: block}, ) From b65f4d001eb17933f66cf5adfc8ed53d343cd1ef Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 24 Dec 2023 09:46:51 -0500 Subject: [PATCH 27/29] Remove unnecessary function --- x/subscription/keeper/subscription.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 7d386cac03..a7eda803f5 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -484,15 +484,6 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, ) } - createFutureSubscription := func() { - sub.FutureSubscription = &types.FutureSubscription{ - Creator: creator, - PlanIndex: plan.Index, - PlanBlock: plan.Block, - DurationBought: duration, - } - } - newPlanPrice := plan.GetPrice() newPlanPrice.Amount = newPlanPrice.Amount.MulRaw(int64(duration)) k.applyPlanDiscountIfEligible(duration, &plan, &newPlanPrice) @@ -536,7 +527,13 @@ func (k Keeper) CreateFutureSubscription(ctx sdk.Context, return err } - createFutureSubscription() + sub.FutureSubscription = &types.FutureSubscription{ + Creator: creator, + PlanIndex: plan.Index, + PlanBlock: plan.Block, + DurationBought: duration, + } + k.subsFS.ModifyEntry(ctx, consumer, sub.Block, &sub) return nil } From b21e1294ae0fede4c23ec537585bf30f4d04dd95 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 24 Dec 2023 09:47:15 -0500 Subject: [PATCH 28/29] Update init_chain_command script --- scripts/init_chain_commands.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/init_chain_commands.sh b/scripts/init_chain_commands.sh index 5479c7d42d..a8b910b634 100755 --- a/scripts/init_chain_commands.sh +++ b/scripts/init_chain_commands.sh @@ -22,8 +22,20 @@ echo; echo "#### Waiting 4 blocks ####" wait_count_blocks 4 sleep 4 +echo; echo "#### Sending proposal for test plans add ####" +lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/test_plans/default.json,./cookbook/plans/test_plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE + +echo; echo "#### Waiting 2 blocks ####" +wait_count_blocks 2 + +echo; echo "#### Voting on plans test add proposal ####" +lavad tx gov vote $(latest_vote) yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE + +echo; echo "#### Waiting 4 blocks ####" +wait_count_blocks 2 + echo; echo "#### Sending proposal for plans add ####" -lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/whale.json,./cookbook/plans/explorer.json,./cookbook/plans/test_plans/default.json,./cookbook/plans/test_plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE +lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/explorer.json,./cookbook/plans/adventurer.json,./cookbook/plans/whale.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE echo; echo "#### Waiting 2 blocks ####" wait_count_blocks 2 From a536a17de6946872f26c0810920f2b0b24f508cb Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 24 Dec 2023 12:59:53 -0500 Subject: [PATCH 29/29] Fix broken tests --- x/rewards/keeper/providers_test.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/x/rewards/keeper/providers_test.go b/x/rewards/keeper/providers_test.go index ee9db40d8e..41573428ee 100644 --- a/x/rewards/keeper/providers_test.go +++ b/x/rewards/keeper/providers_test.go @@ -22,7 +22,7 @@ func TestZeroProvidersRewards(t *testing.T) { ts.AdvanceEpoch() consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) // first months there are no bonus rewards, just payment from the subscription @@ -55,7 +55,7 @@ func TestBasicBoostProvidersRewards(t *testing.T) { ts.AdvanceEpoch() consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) baserewards := uint64(100) @@ -99,7 +99,7 @@ func TestSpecAllocationProvidersRewards(t *testing.T) { ts.AdvanceEpoch() consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) msg := ts.SendRelay(providerAcc.Addr.String(), consumerAcc, []string{ts.spec.Index}, ts.plan.Price.Amount.Uint64()) @@ -143,7 +143,7 @@ func TestProvidersDiminishingRewards(t *testing.T) { for i := 0; i < 7; i++ { consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) msg := ts.SendRelay(providerAcc.Addr.String(), consumerAcc, []string{ts.spec.Index}, ts.plan.Price.Amount.Uint64()) @@ -191,7 +191,7 @@ func TestProvidersEndRewards(t *testing.T) { for i := 0; i < 50; i++ { consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) msg := ts.SendRelay(providerAcc.Addr.String(), consumerAcc, []string{ts.spec.Index}, ts.plan.Price.Amount.Uint64()) @@ -243,7 +243,7 @@ func Test2SpecsZeroShares(t *testing.T) { ts.AdvanceEpoch() consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) msg := ts.SendRelay(providerAcc.Addr.String(), consumerAcc, []string{ts.spec.Index}, ts.plan.Price.Amount.Uint64()) @@ -251,7 +251,7 @@ func Test2SpecsZeroShares(t *testing.T) { require.Nil(t, err) consumerAcc2, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc2.Addr.String(), consumerAcc2.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc2.Addr.String(), consumerAcc2.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) msg = ts.SendRelay(providerAcc.Addr.String(), consumerAcc2, []string{spec2.Index}, ts.plan.Price.Amount.Uint64()) @@ -306,7 +306,7 @@ func Test2SpecsDoubleShares(t *testing.T) { ts.AdvanceEpoch() consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) msg := ts.SendRelay(providerAcc.Addr.String(), consumerAcc, []string{ts.spec.Index}, ts.plan.Price.Amount.Uint64()) @@ -314,7 +314,7 @@ func Test2SpecsDoubleShares(t *testing.T) { require.Nil(t, err) consumerAcc2, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc2.Addr.String(), consumerAcc2.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc2.Addr.String(), consumerAcc2.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) msg = ts.SendRelay(providerAcc.Addr.String(), consumerAcc2, []string{spec2.Index}, ts.plan.Price.Amount.Uint64()) @@ -366,7 +366,7 @@ func TestBonusRewards3Providers(t *testing.T) { ts.AdvanceEpoch() consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) msg := ts.SendRelay(providerAcc1.Addr.String(), consumerAcc, []string{ts.spec.Index}, ts.plan.Price.Amount.Uint64()/2) @@ -461,7 +461,7 @@ func TestValidatorsAndCommunityParticipation(t *testing.T) { ts.AdvanceEpoch() consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) baserewards := uint64(100) @@ -505,7 +505,7 @@ func TestBonusReward49months(t *testing.T) { ts.AdvanceEpoch() consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()*100) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, true) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, true, false) require.Nil(t, err) for i := 0; i < 50; i++ { @@ -567,7 +567,7 @@ func TestCommunityTaxOne(t *testing.T) { ts.AdvanceEpoch() consumerAcc, _ := ts.AddAccount(common.CONSUMER, 1, ts.plan.Price.Amount.Int64()) - _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false) + _, err = ts.TxSubscriptionBuy(consumerAcc.Addr.String(), consumerAcc.Addr.String(), ts.plan.Index, 1, false, false) require.Nil(t, err) baserewards := uint64(100)