From db9e43879411f3dde2909f2ceff9543ffbe1b408 Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Tue, 19 Oct 2021 14:26:06 +0900 Subject: [PATCH 1/9] feat: add reference_count field to HistoricalRewards --- .../tendermint/farming/v1beta1/farming.proto | 2 + x/farming/types/farming.pb.go | 181 ++++++++++-------- 2 files changed, 107 insertions(+), 76 deletions(-) diff --git a/proto/tendermint/farming/v1beta1/farming.proto b/proto/tendermint/farming/v1beta1/farming.proto index 75a30b17..84f7664f 100644 --- a/proto/tendermint/farming/v1beta1/farming.proto +++ b/proto/tendermint/farming/v1beta1/farming.proto @@ -171,6 +171,8 @@ message HistoricalRewards { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", (gogoproto.nullable) = false ]; + + uint32 reference_count = 2 [(gogoproto.moretags) = "yaml:\"reference_count\""]; } // OutstandingRewards represents outstanding(un-withdrawn) rewards diff --git a/x/farming/types/farming.pb.go b/x/farming/types/farming.pb.go index ddabc670..92fc435c 100644 --- a/x/farming/types/farming.pb.go +++ b/x/farming/types/farming.pb.go @@ -368,6 +368,7 @@ var xxx_messageInfo_TotalStakings proto.InternalMessageInfo type HistoricalRewards struct { CumulativeUnitRewards github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,1,rep,name=cumulative_unit_rewards,json=cumulativeUnitRewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"cumulative_unit_rewards" yaml:"cumulative_unit_rewards"` + ReferenceCount uint32 `protobuf:"varint,2,opt,name=reference_count,json=referenceCount,proto3" json:"reference_count,omitempty" yaml:"reference_count"` } func (m *HistoricalRewards) Reset() { *m = HistoricalRewards{} } @@ -467,82 +468,83 @@ func init() { } var fileDescriptor_5b657e0809d9de86 = []byte{ - // 1192 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x3f, 0x6f, 0xdb, 0x46, - 0x14, 0xd7, 0x39, 0x8a, 0x2d, 0x9d, 0x6a, 0x5b, 0x3e, 0xff, 0x89, 0xac, 0x24, 0x22, 0x41, 0xa0, - 0x85, 0x90, 0x22, 0x12, 0x92, 0x74, 0xf2, 0x54, 0xd3, 0xb2, 0x5c, 0x01, 0x81, 0xa3, 0x30, 0x72, - 0xd3, 0x16, 0x28, 0x88, 0x13, 0x79, 0x96, 0x09, 0x53, 0xa4, 0xc0, 0x3b, 0xd9, 0xd6, 0xd8, 0xa1, - 0xa8, 0xe1, 0x29, 0x28, 0x3a, 0x74, 0x71, 0x11, 0xb4, 0x5b, 0xba, 0xf6, 0x3b, 0x34, 0xa3, 0x51, - 0xa0, 0x40, 0xd1, 0x81, 0x29, 0xec, 0x6f, 0xa0, 0xb9, 0x43, 0xc1, 0xbb, 0xa3, 0xc2, 0x06, 0x72, - 0x1d, 0x01, 0xe9, 0x44, 0xde, 0xfb, 0xf3, 0x7b, 0xbf, 0xf7, 0xf8, 0xde, 0x3b, 0xc2, 0x32, 0x23, - 0x9e, 0x4d, 0x82, 0xae, 0xe3, 0xb1, 0xea, 0x2e, 0x8e, 0x9e, 0x9d, 0xea, 0xc1, 0xbd, 0x36, 0x61, - 0xf8, 0x5e, 0x7c, 0xae, 0xf4, 0x02, 0x9f, 0xf9, 0x68, 0xc5, 0xf2, 0x69, 0xd7, 0xa7, 0x95, 0x58, - 0x2a, 0xad, 0x8a, 0x4b, 0x1d, 0xbf, 0xe3, 0x73, 0x93, 0x6a, 0xf4, 0x26, 0xac, 0x8b, 0xab, 0xc2, - 0xda, 0x14, 0x0a, 0xe9, 0x2a, 0x54, 0x25, 0x71, 0xaa, 0xb6, 0x31, 0x25, 0xa3, 0x58, 0x96, 0xef, - 0x78, 0x52, 0xaf, 0x74, 0x7c, 0xbf, 0xe3, 0x92, 0x2a, 0x3f, 0xb5, 0xfb, 0xbb, 0x55, 0xe6, 0x74, - 0x09, 0x65, 0xb8, 0xdb, 0x13, 0x06, 0xda, 0xc5, 0x35, 0x38, 0xdd, 0xc4, 0x01, 0xee, 0x52, 0xf4, - 0x02, 0xc0, 0xd5, 0x5e, 0xe0, 0x1c, 0x60, 0x46, 0xcc, 0x9e, 0x8b, 0x3d, 0xd3, 0x0a, 0x08, 0x66, - 0x8e, 0xef, 0x99, 0xbb, 0x84, 0x14, 0x80, 0x7a, 0xad, 0x9c, 0xbb, 0xbf, 0x5a, 0x91, 0xe1, 0xa3, - 0x80, 0x31, 0xed, 0xca, 0x86, 0xef, 0x78, 0x7a, 0xeb, 0x65, 0xa8, 0xa4, 0x86, 0xa1, 0xa2, 0x0e, - 0x70, 0xd7, 0x5d, 0xd3, 0x2e, 0x45, 0xd2, 0x5e, 0xbc, 0x52, 0xca, 0x1d, 0x87, 0xed, 0xf5, 0xdb, - 0x15, 0xcb, 0xef, 0xca, 0x7c, 0xe4, 0xe3, 0x2e, 0xb5, 0xf7, 0xab, 0x6c, 0xd0, 0x23, 0x94, 0x83, - 0x52, 0x63, 0x45, 0xe2, 0x34, 0x5d, 0xec, 0x6d, 0x48, 0x94, 0x3a, 0x21, 0x48, 0x87, 0xf3, 0x1e, - 0x39, 0x62, 0x26, 0xe9, 0xf9, 0xd6, 0x9e, 0x69, 0xe3, 0x01, 0x2d, 0x4c, 0xa9, 0xa0, 0x3c, 0xab, - 0x17, 0x87, 0xa1, 0xb2, 0x22, 0x28, 0xbc, 0x61, 0xa0, 0x19, 0xb3, 0x91, 0x64, 0x33, 0x12, 0xd4, - 0xf0, 0x80, 0xa2, 0x16, 0x5c, 0x96, 0x1f, 0x20, 0xe2, 0x65, 0x5a, 0xbe, 0xeb, 0x12, 0x8b, 0xf9, - 0x41, 0xe1, 0x9a, 0x0a, 0xca, 0x59, 0x5d, 0x1d, 0x86, 0xca, 0x2d, 0x81, 0x34, 0xd6, 0x4c, 0x33, - 0x16, 0xa5, 0xbc, 0x4e, 0xc8, 0x46, 0x2c, 0x45, 0xdf, 0x00, 0x78, 0xc3, 0x26, 0x2e, 0x1e, 0x10, - 0xdb, 0xa4, 0x0c, 0xef, 0x47, 0x7e, 0x1d, 0x4c, 0x79, 0x11, 0xd3, 0x2a, 0x28, 0xa7, 0xf5, 0x66, - 0x54, 0xa9, 0x3f, 0x43, 0xe5, 0x83, 0xb7, 0xa8, 0xc2, 0x16, 0xa6, 0xc3, 0x50, 0x29, 0x09, 0x1a, - 0x97, 0xc0, 0x6a, 0xc6, 0x92, 0xd4, 0x3c, 0x11, 0x8a, 0x2d, 0x4c, 0xeb, 0x84, 0xac, 0x65, 0x8e, - 0x9f, 0x2b, 0xa9, 0xef, 0x9f, 0x2b, 0x29, 0xed, 0x87, 0x19, 0x98, 0xd1, 0x31, 0xe5, 0x55, 0x44, - 0x73, 0x70, 0xca, 0xb1, 0x0b, 0x20, 0xa2, 0x62, 0x4c, 0x39, 0x36, 0x42, 0x30, 0xed, 0xe1, 0x2e, - 0xe1, 0xf5, 0xcb, 0x1a, 0xfc, 0x1d, 0x7d, 0x04, 0xd3, 0x51, 0x7c, 0x5e, 0x89, 0xb9, 0xfb, 0x6a, - 0x65, 0x7c, 0xbf, 0x56, 0x22, 0xbc, 0xd6, 0xa0, 0x47, 0x0c, 0x6e, 0x8d, 0x1e, 0xc3, 0xa5, 0xb8, - 0x52, 0x3d, 0xdf, 0x77, 0x4d, 0x6c, 0xdb, 0x01, 0xa1, 0x94, 0xa7, 0x9d, 0xd5, 0x95, 0x61, 0xa8, - 0xdc, 0xfc, 0x77, 0x3d, 0x93, 0x56, 0x9a, 0x81, 0xa4, 0xb8, 0xe9, 0xfb, 0xee, 0xba, 0x10, 0xa2, - 0x47, 0x70, 0x91, 0xf1, 0x91, 0x12, 0xfd, 0x13, 0x23, 0x5e, 0xe7, 0x88, 0xa5, 0x61, 0xa8, 0x14, - 0x05, 0xe2, 0x18, 0x23, 0xcd, 0x40, 0x09, 0x69, 0x0c, 0xf8, 0x23, 0x80, 0x4b, 0x71, 0xfd, 0xa2, - 0x41, 0x31, 0x0f, 0x89, 0xd3, 0xd9, 0x63, 0xb4, 0x30, 0xcd, 0x1b, 0xfc, 0xd6, 0xd8, 0x06, 0xaf, - 0x11, 0x8b, 0xf7, 0xb8, 0x21, 0x7b, 0x5c, 0xa6, 0x31, 0x0e, 0x27, 0x6a, 0xef, 0x0f, 0xdf, 0xe2, - 0xc3, 0x4a, 0x48, 0x6a, 0x20, 0x89, 0x12, 0x9d, 0x9e, 0x0a, 0x0c, 0xf4, 0x19, 0x84, 0x94, 0xe1, - 0x80, 0x99, 0xd1, 0xb8, 0x16, 0x66, 0x54, 0x50, 0xce, 0xdd, 0x2f, 0x56, 0xc4, 0x2c, 0x57, 0xe2, - 0x59, 0xae, 0xb4, 0xe2, 0x59, 0xd6, 0x6f, 0x4b, 0x5e, 0x0b, 0x23, 0x5e, 0xd2, 0x57, 0x7b, 0xf6, - 0x4a, 0x01, 0x46, 0x96, 0x0b, 0x22, 0x73, 0x64, 0xc0, 0x0c, 0xf1, 0x6c, 0x81, 0x9b, 0xb9, 0x12, - 0xf7, 0xa6, 0xc4, 0x9d, 0x17, 0xb8, 0xb1, 0xa7, 0x40, 0x9d, 0x21, 0x9e, 0xcd, 0x31, 0x4b, 0x10, - 0xc6, 0x85, 0x26, 0x76, 0x21, 0xab, 0x82, 0x72, 0xc6, 0x48, 0x48, 0xd0, 0x21, 0x5c, 0x71, 0x31, - 0x65, 0xa6, 0xed, 0x50, 0x16, 0x38, 0xed, 0x3e, 0xff, 0x48, 0x9c, 0x01, 0xbc, 0x92, 0xc1, 0xfb, - 0xc3, 0x50, 0xb9, 0x2d, 0xa2, 0x8f, 0xc7, 0x10, 0x5c, 0x96, 0x22, 0x65, 0x2d, 0xa1, 0xe3, 0xc4, - 0xbe, 0x03, 0x70, 0x61, 0xe4, 0x40, 0x6c, 0xfe, 0x9d, 0x68, 0x21, 0x77, 0xd5, 0x26, 0x7b, 0x28, - 0xb3, 0x2e, 0xc8, 0xa9, 0x7b, 0x13, 0x61, 0xb2, 0x0d, 0x96, 0x4f, 0xf8, 0x73, 0xc9, 0xda, 0x42, - 0x3c, 0x97, 0xbf, 0xfd, 0x72, 0xf7, 0x7a, 0x34, 0x42, 0x0d, 0xed, 0x6f, 0x00, 0xe7, 0xeb, 0xce, - 0x11, 0xb1, 0xd7, 0xbb, 0x7e, 0xdf, 0x63, 0x7c, 0x4e, 0x9f, 0xc2, 0x6c, 0xc4, 0x8d, 0x6f, 0x50, - 0x3e, 0xae, 0xb9, 0xcb, 0x07, 0x31, 0x1e, 0x6e, 0xbd, 0x70, 0x16, 0x2a, 0x60, 0x18, 0x2a, 0x79, - 0xc1, 0x7d, 0x04, 0xa0, 0x19, 0x99, 0x76, 0xbc, 0x00, 0xbe, 0x06, 0xf0, 0x3d, 0xb1, 0x16, 0x31, - 0x8f, 0x56, 0x98, 0xba, 0xaa, 0x22, 0x5b, 0xb2, 0x22, 0x8b, 0xb2, 0x0f, 0x12, 0xce, 0x93, 0x15, - 0x23, 0xc7, 0x5d, 0x45, 0x92, 0x89, 0xfd, 0xf4, 0x3b, 0x80, 0x59, 0x23, 0x1a, 0xd3, 0xff, 0x37, - 0x71, 0x02, 0x45, 0x7c, 0x33, 0x88, 0x62, 0x89, 0x85, 0xa7, 0xd7, 0x26, 0xd8, 0xc6, 0x35, 0x62, - 0x0d, 0x43, 0x05, 0x25, 0xab, 0xc0, 0xa1, 0x34, 0x03, 0xf2, 0x13, 0xcf, 0x21, 0x91, 0xd7, 0x29, - 0x80, 0x33, 0x72, 0x27, 0xa3, 0x3a, 0x9c, 0x96, 0xe5, 0x06, 0x3c, 0x6e, 0x65, 0x82, 0xb8, 0x0d, - 0x8f, 0x19, 0xd2, 0x1b, 0x7d, 0x0c, 0xe7, 0xf8, 0x38, 0x47, 0x8b, 0x87, 0x07, 0xe5, 0x79, 0xa4, - 0xf5, 0xd5, 0x61, 0xa8, 0x2c, 0x27, 0xe6, 0x7f, 0xa4, 0xd7, 0x8c, 0xd9, 0x58, 0xc0, 0xef, 0xbe, - 0x04, 0xbf, 0x2f, 0xe1, 0xec, 0xe3, 0x3e, 0xe9, 0x8f, 0x2e, 0x8e, 0x77, 0x45, 0x72, 0x2d, 0x7d, - 0x2c, 0xe1, 0x5b, 0x3e, 0xc3, 0xae, 0x44, 0xa7, 0xef, 0x18, 0xfe, 0x57, 0x00, 0x17, 0x3e, 0x71, - 0x28, 0xf3, 0x03, 0xc7, 0xc2, 0xae, 0x41, 0x0e, 0x71, 0x60, 0x53, 0xf4, 0x33, 0x80, 0x37, 0xac, - 0x7e, 0xb7, 0xef, 0x62, 0xe6, 0x1c, 0x10, 0xb3, 0xef, 0x39, 0xcc, 0x0c, 0x84, 0x4e, 0xfe, 0xc4, - 0xfc, 0xf7, 0x8e, 0xdf, 0x91, 0xbd, 0x2e, 0xef, 0xdc, 0x4b, 0xa0, 0x26, 0x5e, 0xf3, 0xcb, 0xaf, - 0x81, 0x76, 0x3c, 0x87, 0x49, 0xb6, 0x32, 0x93, 0xaf, 0x00, 0x44, 0x8f, 0xfa, 0x8c, 0x32, 0xec, - 0xd9, 0x8e, 0xd7, 0x89, 0x53, 0xd9, 0x87, 0x33, 0x93, 0x30, 0x7f, 0x10, 0x31, 0x9f, 0x94, 0x57, - 0x1c, 0xe1, 0xce, 0xb7, 0x00, 0x66, 0xe2, 0xfb, 0x1c, 0xdd, 0x81, 0xcb, 0xcd, 0x87, 0xeb, 0xdb, - 0x66, 0xeb, 0xf3, 0xe6, 0xa6, 0xb9, 0xb3, 0xfd, 0xa4, 0xb9, 0xb9, 0xd1, 0xa8, 0x37, 0x36, 0x6b, - 0xf9, 0x54, 0x71, 0xfe, 0xe4, 0x54, 0xcd, 0xc5, 0x86, 0xdb, 0x8e, 0x8b, 0xca, 0x30, 0xff, 0xda, - 0xb6, 0xb9, 0xa3, 0x3f, 0x6c, 0x6c, 0xe4, 0x41, 0x11, 0x9d, 0x9c, 0xaa, 0x73, 0xb1, 0x59, 0xb3, - 0xdf, 0x76, 0x1d, 0x0b, 0xdd, 0x81, 0x0b, 0x09, 0x4b, 0xa3, 0xf1, 0xe9, 0x7a, 0x6b, 0x33, 0x3f, - 0x55, 0x5c, 0x3c, 0x39, 0x55, 0xe7, 0x47, 0xa6, 0xe2, 0x7f, 0xaf, 0x98, 0x3e, 0xfe, 0xa9, 0x94, - 0xd2, 0xb7, 0x5e, 0x9e, 0x97, 0xc0, 0xd9, 0x79, 0x09, 0xfc, 0x75, 0x5e, 0x02, 0xcf, 0x2e, 0x4a, - 0xa9, 0xb3, 0x8b, 0x52, 0xea, 0x8f, 0x8b, 0x52, 0xea, 0x8b, 0xbb, 0x89, 0x24, 0xc7, 0xfc, 0x77, - 0x1f, 0x8d, 0xde, 0x78, 0xbe, 0xed, 0x69, 0x7e, 0xb7, 0x3c, 0xf8, 0x27, 0x00, 0x00, 0xff, 0xff, - 0xc5, 0xee, 0x6f, 0xb4, 0xa4, 0x0b, 0x00, 0x00, + // 1216 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x6f, 0x1b, 0x45, + 0x18, 0xf7, 0xa4, 0x6e, 0x62, 0x4f, 0x48, 0xe2, 0x4c, 0x1e, 0x75, 0xdc, 0xd6, 0xbb, 0x5a, 0x09, + 0x64, 0x15, 0xd5, 0x56, 0x5b, 0x4e, 0x39, 0x91, 0xb5, 0xe3, 0x60, 0xa9, 0x6a, 0xdd, 0xad, 0x43, + 0x01, 0x09, 0xad, 0xc6, 0xbb, 0x13, 0x77, 0xd5, 0xf5, 0xae, 0xb5, 0x33, 0x6e, 0xeb, 0x23, 0x07, + 0x44, 0x55, 0x71, 0xa8, 0x10, 0x07, 0x2e, 0x41, 0x15, 0xdc, 0xca, 0x95, 0x3f, 0xa2, 0xc7, 0x0a, + 0x09, 0x09, 0x71, 0xd8, 0xa2, 0xe4, 0x3f, 0xf0, 0x99, 0x03, 0x9a, 0xc7, 0xba, 0x4b, 0xe4, 0x90, + 0x5a, 0x2a, 0xa7, 0xdd, 0xf9, 0x1e, 0xbf, 0xef, 0xb1, 0xdf, 0xef, 0xdb, 0x81, 0x15, 0x46, 0x02, + 0x97, 0x44, 0x7d, 0x2f, 0x60, 0xb5, 0x03, 0xcc, 0x9f, 0xbd, 0xda, 0xc3, 0x6b, 0x5d, 0xc2, 0xf0, + 0xb5, 0xe4, 0x5c, 0x1d, 0x44, 0x21, 0x0b, 0xd1, 0xa6, 0x13, 0xd2, 0x7e, 0x48, 0xab, 0x89, 0x54, + 0x59, 0x95, 0xd6, 0x7b, 0x61, 0x2f, 0x14, 0x26, 0x35, 0xfe, 0x26, 0xad, 0x4b, 0x5b, 0xd2, 0xda, + 0x96, 0x0a, 0xe5, 0x2a, 0x55, 0x65, 0x79, 0xaa, 0x75, 0x31, 0x25, 0x93, 0x58, 0x4e, 0xe8, 0x05, + 0x4a, 0xaf, 0xf5, 0xc2, 0xb0, 0xe7, 0x93, 0x9a, 0x38, 0x75, 0x87, 0x07, 0x35, 0xe6, 0xf5, 0x09, + 0x65, 0xb8, 0x3f, 0x90, 0x06, 0xc6, 0xf1, 0x39, 0x38, 0xdf, 0xc6, 0x11, 0xee, 0x53, 0xf4, 0x02, + 0xc0, 0xad, 0x41, 0xe4, 0x3d, 0xc4, 0x8c, 0xd8, 0x03, 0x1f, 0x07, 0xb6, 0x13, 0x11, 0xcc, 0xbc, + 0x30, 0xb0, 0x0f, 0x08, 0x29, 0x02, 0xfd, 0x5c, 0x65, 0xf1, 0xfa, 0x56, 0x55, 0x85, 0xe7, 0x01, + 0x93, 0xb4, 0xab, 0xf5, 0xd0, 0x0b, 0xcc, 0xce, 0xcb, 0x58, 0xcb, 0x8c, 0x63, 0x4d, 0x1f, 0xe1, + 0xbe, 0xbf, 0x6d, 0x9c, 0x8a, 0x64, 0xbc, 0x78, 0xad, 0x55, 0x7a, 0x1e, 0xbb, 0x3f, 0xec, 0x56, + 0x9d, 0xb0, 0xaf, 0xea, 0x51, 0x8f, 0xab, 0xd4, 0x7d, 0x50, 0x63, 0xa3, 0x01, 0xa1, 0x02, 0x94, + 0x5a, 0x9b, 0x0a, 0xa7, 0xed, 0xe3, 0xa0, 0xae, 0x50, 0x9a, 0x84, 0x20, 0x13, 0xae, 0x04, 0xe4, + 0x31, 0xb3, 0xc9, 0x20, 0x74, 0xee, 0xdb, 0x2e, 0x1e, 0xd1, 0xe2, 0x9c, 0x0e, 0x2a, 0x4b, 0x66, + 0x69, 0x1c, 0x6b, 0x9b, 0x32, 0x85, 0x13, 0x06, 0x86, 0xb5, 0xc4, 0x25, 0xbb, 0x5c, 0xd0, 0xc0, + 0x23, 0x8a, 0x3a, 0x70, 0x43, 0x7d, 0x00, 0x9e, 0x97, 0xed, 0x84, 0xbe, 0x4f, 0x1c, 0x16, 0x46, + 0xc5, 0x73, 0x3a, 0xa8, 0xe4, 0x4d, 0x7d, 0x1c, 0x6b, 0x97, 0x24, 0xd2, 0x54, 0x33, 0xc3, 0x5a, + 0x53, 0xf2, 0x26, 0x21, 0xf5, 0x44, 0x8a, 0xbe, 0x01, 0xf0, 0x82, 0x4b, 0x7c, 0x3c, 0x22, 0xae, + 0x4d, 0x19, 0x7e, 0xc0, 0xfd, 0x7a, 0x98, 0x8a, 0x26, 0x66, 0x75, 0x50, 0xc9, 0x9a, 0x6d, 0xde, + 0xa9, 0x3f, 0x63, 0xed, 0x83, 0xb7, 0xe8, 0xc2, 0x1e, 0xa6, 0xe3, 0x58, 0x2b, 0xcb, 0x34, 0x4e, + 0x81, 0x35, 0xac, 0x75, 0xa5, 0xb9, 0x2b, 0x15, 0x7b, 0x98, 0x36, 0x09, 0xd9, 0xce, 0x3d, 0x79, + 0xae, 0x65, 0x7e, 0x78, 0xae, 0x65, 0x8c, 0x1f, 0x17, 0x60, 0xce, 0xc4, 0x54, 0x74, 0x11, 0x2d, + 0xc3, 0x39, 0xcf, 0x2d, 0x02, 0x9e, 0x8a, 0x35, 0xe7, 0xb9, 0x08, 0xc1, 0x6c, 0x80, 0xfb, 0x44, + 0xf4, 0x2f, 0x6f, 0x89, 0x77, 0xf4, 0x11, 0xcc, 0xf2, 0xf8, 0xa2, 0x13, 0xcb, 0xd7, 0xf5, 0xea, + 0xf4, 0x79, 0xad, 0x72, 0xbc, 0xce, 0x68, 0x40, 0x2c, 0x61, 0x8d, 0xee, 0xc0, 0xf5, 0xa4, 0x53, + 0x83, 0x30, 0xf4, 0x6d, 0xec, 0xba, 0x11, 0xa1, 0x54, 0x94, 0x9d, 0x37, 0xb5, 0x71, 0xac, 0x5d, + 0xfc, 0x77, 0x3f, 0xd3, 0x56, 0x86, 0x85, 0x94, 0xb8, 0x1d, 0x86, 0xfe, 0x8e, 0x14, 0xa2, 0xdb, + 0x70, 0x8d, 0x09, 0x4a, 0xc9, 0xf9, 0x49, 0x10, 0xcf, 0x0b, 0xc4, 0xf2, 0x38, 0xd6, 0x4a, 0x12, + 0x71, 0x8a, 0x91, 0x61, 0xa1, 0x94, 0x34, 0x01, 0xfc, 0x09, 0xc0, 0xf5, 0xa4, 0x7f, 0x9c, 0x28, + 0xf6, 0x23, 0xe2, 0xf5, 0xee, 0x33, 0x5a, 0x9c, 0x17, 0x03, 0x7e, 0x69, 0xea, 0x80, 0x37, 0x88, + 0x23, 0x66, 0xdc, 0x52, 0x33, 0xae, 0xca, 0x98, 0x86, 0xc3, 0xc7, 0xfb, 0xc3, 0xb7, 0xf8, 0xb0, + 0x0a, 0x92, 0x5a, 0x48, 0xa1, 0xf0, 0xd3, 0x3d, 0x89, 0x81, 0x3e, 0x83, 0x90, 0x32, 0x1c, 0x31, + 0x9b, 0xd3, 0xb5, 0xb8, 0xa0, 0x83, 0xca, 0xe2, 0xf5, 0x52, 0x55, 0x72, 0xb9, 0x9a, 0x70, 0xb9, + 0xda, 0x49, 0xb8, 0x6c, 0x5e, 0x56, 0x79, 0xad, 0x4e, 0xf2, 0x52, 0xbe, 0xc6, 0xb3, 0xd7, 0x1a, + 0xb0, 0xf2, 0x42, 0xc0, 0xcd, 0x91, 0x05, 0x73, 0x24, 0x70, 0x25, 0x6e, 0xee, 0x4c, 0xdc, 0x8b, + 0x0a, 0x77, 0x45, 0xe2, 0x26, 0x9e, 0x12, 0x75, 0x81, 0x04, 0xae, 0xc0, 0x2c, 0x43, 0x98, 0x34, + 0x9a, 0xb8, 0xc5, 0xbc, 0x0e, 0x2a, 0x39, 0x2b, 0x25, 0x41, 0x8f, 0xe0, 0xa6, 0x8f, 0x29, 0xb3, + 0x5d, 0x8f, 0xb2, 0xc8, 0xeb, 0x0e, 0xc5, 0x47, 0x12, 0x19, 0xc0, 0x33, 0x33, 0x78, 0x7f, 0x1c, + 0x6b, 0x97, 0x65, 0xf4, 0xe9, 0x18, 0x32, 0x97, 0x75, 0xae, 0x6c, 0xa4, 0x74, 0x22, 0xb1, 0xef, + 0x01, 0x5c, 0x9d, 0x38, 0x10, 0x57, 0x7c, 0x27, 0x5a, 0x5c, 0x3c, 0x6b, 0x93, 0xdd, 0x54, 0x55, + 0x17, 0x15, 0xeb, 0x4e, 0x22, 0xcc, 0xb6, 0xc1, 0x0a, 0x29, 0x7f, 0x21, 0xd9, 0x5e, 0x4d, 0x78, + 0xf9, 0xdb, 0xaf, 0x57, 0xcf, 0x73, 0x0a, 0xb5, 0x8c, 0xbf, 0x01, 0x5c, 0x69, 0x7a, 0x8f, 0x89, + 0xbb, 0xd3, 0x0f, 0x87, 0x01, 0x13, 0x3c, 0xbd, 0x07, 0xf3, 0x3c, 0x37, 0xb1, 0x41, 0x05, 0x5d, + 0x17, 0x4f, 0x27, 0x62, 0x42, 0x6e, 0xb3, 0xf8, 0x2a, 0xd6, 0xc0, 0x38, 0xd6, 0x0a, 0x32, 0xf7, + 0x09, 0x80, 0x61, 0xe5, 0xba, 0xc9, 0x02, 0xf8, 0x1a, 0xc0, 0xf7, 0xe4, 0x5a, 0xc4, 0x22, 0x5a, + 0x71, 0xee, 0xac, 0x8e, 0xec, 0xa9, 0x8e, 0xac, 0xa9, 0x39, 0x48, 0x39, 0xcf, 0xd6, 0x8c, 0x45, + 0xe1, 0x2a, 0x8b, 0x4c, 0xed, 0xa7, 0xdf, 0x01, 0xcc, 0x5b, 0x9c, 0xa6, 0xff, 0x6f, 0xe1, 0x04, + 0xca, 0xf8, 0x76, 0xc4, 0x63, 0xc9, 0x85, 0x67, 0x36, 0x66, 0xd8, 0xc6, 0x0d, 0xe2, 0x8c, 0x63, + 0x0d, 0xa5, 0xbb, 0x20, 0xa0, 0x0c, 0x0b, 0x8a, 0x93, 0xa8, 0x21, 0x55, 0xd7, 0x21, 0x80, 0x0b, + 0x6a, 0x27, 0xa3, 0x26, 0x9c, 0x57, 0xed, 0x06, 0x22, 0x6e, 0x75, 0x86, 0xb8, 0xad, 0x80, 0x59, + 0xca, 0x1b, 0x7d, 0x0c, 0x97, 0x05, 0x9d, 0xf9, 0xe2, 0x11, 0x41, 0x45, 0x1d, 0x59, 0x73, 0x6b, + 0x1c, 0x6b, 0x1b, 0x29, 0xfe, 0x4f, 0xf4, 0x86, 0xb5, 0x94, 0x08, 0xc4, 0xbf, 0x2f, 0x95, 0xdf, + 0x97, 0x70, 0xe9, 0xce, 0x90, 0x0c, 0x27, 0x3f, 0x8e, 0x77, 0x95, 0xe4, 0x76, 0xf6, 0x89, 0x82, + 0xef, 0x84, 0x0c, 0xfb, 0x0a, 0x9d, 0xbe, 0x63, 0xf8, 0x6f, 0xe7, 0xe0, 0xea, 0x27, 0x1e, 0x65, + 0x61, 0xe4, 0x39, 0xd8, 0xb7, 0xc8, 0x23, 0x1c, 0xb9, 0x14, 0xfd, 0x02, 0xe0, 0x05, 0x67, 0xd8, + 0x1f, 0xfa, 0x98, 0x79, 0x0f, 0x89, 0x3d, 0x0c, 0x3c, 0x66, 0x47, 0x52, 0xa7, 0x2e, 0x31, 0xff, + 0xbd, 0xe3, 0xf7, 0xd5, 0xac, 0xab, 0x7f, 0xee, 0x29, 0x50, 0x33, 0xaf, 0xf9, 0x8d, 0x37, 0x40, + 0xfb, 0x81, 0xc7, 0x92, 0x6c, 0xeb, 0x70, 0x25, 0x22, 0x07, 0x24, 0x22, 0x81, 0xc3, 0xaf, 0x16, + 0x92, 0x8d, 0x27, 0xee, 0x31, 0x27, 0x0c, 0x0c, 0x6b, 0x79, 0x22, 0xa9, 0xa7, 0xda, 0xf1, 0x15, + 0x80, 0xe8, 0xf6, 0x90, 0x51, 0x86, 0x03, 0xd7, 0x0b, 0x7a, 0x49, 0x84, 0x07, 0x70, 0x61, 0x96, + 0xf2, 0x6f, 0xf0, 0xf2, 0x67, 0x2d, 0x2e, 0x89, 0x70, 0xe5, 0x3b, 0x00, 0x73, 0xc9, 0xa5, 0x00, + 0x5d, 0x81, 0x1b, 0xed, 0x9b, 0x3b, 0xb7, 0xec, 0xce, 0xe7, 0xed, 0x5d, 0x7b, 0xff, 0xd6, 0xdd, + 0xf6, 0x6e, 0xbd, 0xd5, 0x6c, 0xed, 0x36, 0x0a, 0x99, 0xd2, 0xca, 0xd3, 0x43, 0x7d, 0x31, 0x31, + 0xbc, 0xe5, 0xf9, 0xa8, 0x02, 0x0b, 0x6f, 0x6c, 0xdb, 0xfb, 0xe6, 0xcd, 0x56, 0xbd, 0x00, 0x4a, + 0xe8, 0xe9, 0xa1, 0xbe, 0x9c, 0x98, 0xb5, 0x87, 0x5d, 0xdf, 0x73, 0xd0, 0x15, 0xb8, 0x9a, 0xb2, + 0xb4, 0x5a, 0x9f, 0xee, 0x74, 0x76, 0x0b, 0x73, 0xa5, 0xb5, 0xa7, 0x87, 0xfa, 0xca, 0xc4, 0x54, + 0x5e, 0x1a, 0x4b, 0xd9, 0x27, 0x3f, 0x97, 0x33, 0xe6, 0xde, 0xcb, 0xa3, 0x32, 0x78, 0x75, 0x54, + 0x06, 0x7f, 0x1d, 0x95, 0xc1, 0xb3, 0xe3, 0x72, 0xe6, 0xd5, 0x71, 0x39, 0xf3, 0xc7, 0x71, 0x39, + 0xf3, 0xc5, 0xd5, 0x54, 0x91, 0x53, 0x2e, 0xef, 0x8f, 0x27, 0x6f, 0xa2, 0xde, 0xee, 0xbc, 0xf8, + 0x41, 0xdd, 0xf8, 0x27, 0x00, 0x00, 0xff, 0xff, 0xc3, 0x41, 0x34, 0xdd, 0xe9, 0x0b, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -935,6 +937,11 @@ func (m *HistoricalRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ReferenceCount != 0 { + i = encodeVarintFarming(dAtA, i, uint64(m.ReferenceCount)) + i-- + dAtA[i] = 0x10 + } if len(m.CumulativeUnitRewards) > 0 { for iNdEx := len(m.CumulativeUnitRewards) - 1; iNdEx >= 0; iNdEx-- { { @@ -1157,6 +1164,9 @@ func (m *HistoricalRewards) Size() (n int) { n += 1 + l + sovFarming(uint64(l)) } } + if m.ReferenceCount != 0 { + n += 1 + sovFarming(uint64(m.ReferenceCount)) + } return n } @@ -2283,6 +2293,25 @@ func (m *HistoricalRewards) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ReferenceCount", wireType) + } + m.ReferenceCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFarming + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ReferenceCount |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipFarming(dAtA[iNdEx:]) From e909faa46a8b6768a61b1edded8e4f5c6c86769c Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Thu, 21 Oct 2021 16:47:09 +0900 Subject: [PATCH 2/9] feat: add reference counting; WIP --- x/farming/keeper/keeper_test.go | 22 +++++----- x/farming/keeper/reward.go | 73 +++++++++++++++++++++++++++----- x/farming/keeper/reward_test.go | 54 ++++++++++++++--------- x/farming/keeper/staking.go | 35 ++++++++++++++- x/farming/keeper/staking_test.go | 8 +--- x/farming/types/keys.go | 6 +++ x/farming/types/keys_test.go | 5 +++ 7 files changed, 152 insertions(+), 51 deletions(-) diff --git a/x/farming/keeper/keeper_test.go b/x/farming/keeper/keeper_test.go index 19f33277..e35b7d60 100644 --- a/x/farming/keeper/keeper_test.go +++ b/x/farming/keeper/keeper_test.go @@ -153,15 +153,15 @@ func (suite *KeeperTestSuite) AdvanceEpoch() { suite.Require().NoError(err) } -func (suite *KeeperTestSuite) SetFixedAmountPlan(id uint64, farmingPoolAcc sdk.AccAddress, stakingCoinWeightsMap map[string]string, epochAmountMap map[string]int64) { - stakingCoinWeights := sdk.NewDecCoins() - for denom, weight := range stakingCoinWeightsMap { - stakingCoinWeights = stakingCoinWeights.Add(sdk.NewDecCoinFromDec(denom, sdk.MustNewDecFromStr(weight))) +func (suite *KeeperTestSuite) SetFixedAmountPlan(id uint64, farmingPoolAcc sdk.AccAddress, stakingCoinWeightsStr, epochAmountStr string) { + stakingCoinWeights, err := sdk.ParseDecCoins(stakingCoinWeightsStr) + if err != nil { + panic(err) } - epochAmount := sdk.NewCoins() - for denom, amount := range epochAmountMap { - epochAmount = epochAmount.Add(sdk.NewInt64Coin(denom, amount)) + epochAmount, err := sdk.ParseCoinsNormalized(epochAmountStr) + if err != nil { + panic(err) } suite.keeper.SetPlan(suite.ctx, types.NewFixedAmountPlan( @@ -178,10 +178,10 @@ func (suite *KeeperTestSuite) SetFixedAmountPlan(id uint64, farmingPoolAcc sdk.A )) } -func (suite *KeeperTestSuite) SetRatioPlan(id uint64, farmingPoolAcc sdk.AccAddress, stakingCoinWeightsMap map[string]string, epochRatioStr string) { - stakingCoinWeights := sdk.NewDecCoins() - for denom, weight := range stakingCoinWeightsMap { - stakingCoinWeights = stakingCoinWeights.Add(sdk.NewDecCoinFromDec(denom, sdk.MustNewDecFromStr(weight))) +func (suite *KeeperTestSuite) SetRatioPlan(id uint64, farmingPoolAcc sdk.AccAddress, stakingCoinWeightsStr, epochRatioStr string) { + stakingCoinWeights, err := sdk.ParseDecCoins(stakingCoinWeightsStr) + if err != nil { + panic(err) } epochRatio := sdk.MustNewDecFromStr(epochRatioStr) diff --git a/x/farming/keeper/reward.go b/x/farming/keeper/reward.go index 898ede55..f276f611 100644 --- a/x/farming/keeper/reward.go +++ b/x/farming/keeper/reward.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "strconv" "strings" @@ -55,6 +56,51 @@ func (k Keeper) IterateHistoricalRewards(ctx sdk.Context, cb func(stakingCoinDen } } +// DeleteAllHistoricalRewards deletes all historical rewards for a given +// staking coin denom. +func (k Keeper) DeleteAllHistoricalRewards(ctx sdk.Context, stakingCoinDenom string) { + store := ctx.KVStore(k.storeKey) + iter := sdk.KVStorePrefixIterator(store, types.GetHistoricalRewardsPrefix(stakingCoinDenom)) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + store.Delete(iter.Key()) + } +} + +// incrementReferenceCount increments the reference count for a historical rewards. +func (k Keeper) incrementReferenceCount(ctx sdk.Context, stakingCoinDenom string, epoch uint64) { + fmt.Printf("incrementReferenceCount(%s, %d)\n", stakingCoinDenom, epoch) + historical, found := k.GetHistoricalRewards(ctx, stakingCoinDenom, epoch) + if !found { + panic("historical rewards not found") // TODO: choose correct error message + } + if historical.ReferenceCount > 2 { + panic("reference count should never exceed 2") + } + fmt.Printf(" %d -> %d\n", historical.ReferenceCount, historical.ReferenceCount+1) + historical.ReferenceCount++ + k.SetHistoricalRewards(ctx, stakingCoinDenom, epoch, historical) +} + +// decrementReferenceCount decrements the reference count for a historical rewards. +func (k Keeper) decrementReferenceCount(ctx sdk.Context, stakingCoinDenom string, epoch uint64) { + fmt.Printf("decrementReferenceCount(%s, %d)\n", stakingCoinDenom, epoch) + historical, found := k.GetHistoricalRewards(ctx, stakingCoinDenom, epoch) + if !found { + panic("historical rewards not found") // TODO: choose correct error message + } + if historical.ReferenceCount == 0 { + panic("cannot set negative reference count") + } + fmt.Printf(" %d -> %d\n", historical.ReferenceCount, historical.ReferenceCount-1) + historical.ReferenceCount-- + if historical.ReferenceCount == 0 { + k.DeleteHistoricalRewards(ctx, stakingCoinDenom, epoch) + } else { + k.SetHistoricalRewards(ctx, stakingCoinDenom, epoch, historical) + } +} + // GetCurrentEpoch returns the current epoch number for a given // staking coin denom. func (k Keeper) GetCurrentEpoch(ctx sdk.Context, stakingCoinDenom string) uint64 { @@ -91,16 +137,19 @@ func (k Keeper) IterateCurrentEpochs(ctx sdk.Context, cb func(stakingCoinDenom s } } +// DeleteCurrentEpoch deletes current epoch info for a given +// staking coin denom. +func (k Keeper) DeleteCurrentEpoch(ctx sdk.Context, stakingCoinDenom string) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.GetCurrentEpochKey(stakingCoinDenom)) +} + // GetOutstandingRewards returns outstanding rewards for a given // staking coin denom. -func (k Keeper) GetOutstandingRewards(ctx sdk.Context, stakingCoinDenom string) (rewards types.OutstandingRewards, found bool) { +func (k Keeper) GetOutstandingRewards(ctx sdk.Context, stakingCoinDenom string) (rewards types.OutstandingRewards) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.GetOutstandingRewardsKey(stakingCoinDenom)) - if bz == nil { - return - } k.cdc.MustUnmarshal(bz, &rewards) - found = true return } @@ -139,7 +188,7 @@ func (k Keeper) IterateOutstandingRewards(ctx sdk.Context, cb func(stakingCoinDe // IncreaseOutstandingRewards increases outstanding rewards for a given // staking coin denom by given amount. func (k Keeper) IncreaseOutstandingRewards(ctx sdk.Context, stakingCoinDenom string, amount sdk.DecCoins) { - outstanding, _ := k.GetOutstandingRewards(ctx, stakingCoinDenom) + outstanding := k.GetOutstandingRewards(ctx, stakingCoinDenom) outstanding.Rewards = outstanding.Rewards.Add(amount...) k.SetOutstandingRewards(ctx, stakingCoinDenom, outstanding) } @@ -149,10 +198,7 @@ func (k Keeper) IncreaseOutstandingRewards(ctx sdk.Context, stakingCoinDenom str // If the resulting outstanding rewards is zero, then the outstanding rewards // will be deleted, not updated. func (k Keeper) DecreaseOutstandingRewards(ctx sdk.Context, stakingCoinDenom string, amount sdk.DecCoins) { - outstanding, found := k.GetOutstandingRewards(ctx, stakingCoinDenom) - if !found { - panic("outstanding rewards not found") - } + outstanding := k.GetOutstandingRewards(ctx, stakingCoinDenom) if outstanding.Rewards.IsEqual(amount) { k.DeleteOutstandingRewards(ctx, stakingCoinDenom) } else { @@ -209,7 +255,7 @@ func (k Keeper) WithdrawRewards(ctx sdk.Context, farmerAcc sdk.AccAddress, staki } currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) - // TODO: handle if currentEpoch is 0 + fmt.Printf("WithdrawRewards(%s) - CalculateRewards(%s, %d)\n", stakingCoinDenom, stakingCoinDenom, currentEpoch - 1) rewards := k.CalculateRewards(ctx, farmerAcc, stakingCoinDenom, currentEpoch-1) truncatedRewards, _ := rewards.TruncateDecimal() @@ -234,6 +280,7 @@ func (k Keeper) WithdrawRewards(ctx sdk.Context, farmerAcc sdk.AccAddress, staki staking.StartingEpoch = currentEpoch k.SetStaking(ctx, stakingCoinDenom, farmerAcc, staking) + k.decrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) return truncatedRewards, nil } @@ -415,11 +462,15 @@ func (k Keeper) AllocateRewards(ctx sdk.Context) error { for stakingCoinDenom, unitRewards := range unitRewardsByDenom { currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) + fmt.Printf("AllocateRewards :: Setting HistoricalRewards for %d\n", currentEpoch) + fmt.Printf(" Updating CurrentEpoch %d -> %d\n", currentEpoch, currentEpoch+1) historical, _ := k.GetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch-1) k.SetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch, types.HistoricalRewards{ CumulativeUnitRewards: historical.CumulativeUnitRewards.Add(unitRewards...), + ReferenceCount: 1, }) k.SetCurrentEpoch(ctx, stakingCoinDenom, currentEpoch+1) + k.decrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) } return nil diff --git a/x/farming/keeper/reward_test.go b/x/farming/keeper/reward_test.go index e54cadc8..bffff206 100644 --- a/x/farming/keeper/reward_test.go +++ b/x/farming/keeper/reward_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "fmt" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -179,8 +180,8 @@ func (suite *KeeperTestSuite) TestAllocateRewards_FixedAmountPlanAllBalances() { suite.Require().NoError(err) // The sum of epoch ratios is exactly 1. - suite.SetFixedAmountPlan(1, farmingPoolAcc, map[string]string{denom1: "1.0"}, map[string]int64{denom3: 600000}) - suite.SetFixedAmountPlan(2, farmingPoolAcc, map[string]string{denom2: "1.0"}, map[string]int64{denom3: 400000}) + suite.SetFixedAmountPlan(1, farmingPoolAcc, "1denom1", "600000denom3") + suite.SetFixedAmountPlan(2, farmingPoolAcc, "1denom2", "400000denom3") suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000), sdk.NewInt64Coin(denom2, 1000000))) @@ -197,8 +198,8 @@ func (suite *KeeperTestSuite) TestAllocateRewards_RatioPlanAllBalances() { suite.Require().NoError(err) // The sum of epoch ratios is exactly 1. - suite.SetRatioPlan(1, farmingPoolAcc, map[string]string{denom1: "1.0"}, "0.5") - suite.SetRatioPlan(2, farmingPoolAcc, map[string]string{denom2: "1.0"}, "0.5") + suite.SetRatioPlan(1, farmingPoolAcc, "1denom1", "0.5") + suite.SetRatioPlan(2, farmingPoolAcc, "1denom2", "0.5") suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000), sdk.NewInt64Coin(denom2, 1000000))) @@ -216,8 +217,8 @@ func (suite *KeeperTestSuite) TestAllocateRewards_FixedAmountPlanOverBalances() // The sum of epoch amounts is over the balances the farming pool has, // so the reward allocation should never happen. - suite.SetFixedAmountPlan(1, farmingPoolAcc, map[string]string{denom1: "1.0"}, map[string]int64{denom3: 700000}) - suite.SetFixedAmountPlan(2, farmingPoolAcc, map[string]string{denom2: "1.0"}, map[string]int64{denom3: 400000}) + suite.SetFixedAmountPlan(1, farmingPoolAcc, "1denom1", "700000denom3") + suite.SetFixedAmountPlan(2, farmingPoolAcc, "1denom2", "400000denom3") suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000), sdk.NewInt64Coin(denom2, 1000000))) @@ -234,8 +235,8 @@ func (suite *KeeperTestSuite) TestAllocateRewards_RatioPlanOverBalances() { suite.Require().NoError(err) // The sum of epoch ratios is over 1, so the reward allocation should never happen. - suite.SetRatioPlan(1, farmingPoolAcc, map[string]string{denom1: "1.0"}, "0.8") - suite.SetRatioPlan(2, farmingPoolAcc, map[string]string{denom2: "1.0"}, "0.5") + suite.SetRatioPlan(1, farmingPoolAcc, "1denom1", "0.8") + suite.SetRatioPlan(2, farmingPoolAcc, "1denom2", "0.5") suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000), sdk.NewInt64Coin(denom2, 1000000))) @@ -250,27 +251,22 @@ func (suite *KeeperTestSuite) TestOutstandingRewards() { // The block time here is not important, and has chosen randomly. suite.ctx = suite.ctx.WithBlockTime(types.ParseTime("2021-09-01T00:00:00Z")) - suite.SetFixedAmountPlan(1, suite.addrs[4], map[string]string{ - denom1: "1", - }, map[string]int64{ - denom3: 1000, - }) + suite.SetFixedAmountPlan(1, suite.addrs[4], "1denom1", "1000denom3") // Three farmers stake same amount of coins. suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) suite.Stake(suite.addrs[1], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) suite.Stake(suite.addrs[2], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) - // At first, the outstanding rewards shouldn't exist. - _, found := suite.keeper.GetOutstandingRewards(suite.ctx, denom1) - suite.Require().False(found) + // At first, the outstanding rewards should be zero. + outstanding := suite.keeper.GetOutstandingRewards(suite.ctx, denom1) + suite.Require().True(decCoinsEq(sdk.DecCoins{}, outstanding.Rewards)) suite.AdvanceEpoch() // Queued staking coins have now staked. suite.AdvanceEpoch() // Allocate rewards for staked coins. // After the first allocation of rewards, the outstanding rewards should be 1000denom3. - outstanding, found := suite.keeper.GetOutstandingRewards(suite.ctx, denom1) - suite.Require().True(found) + outstanding = suite.keeper.GetOutstandingRewards(suite.ctx, denom1) suite.Require().True(decCoinsEq(sdk.NewDecCoins(sdk.NewInt64DecCoin(denom3, 1000)), outstanding.Rewards)) // All farmers harvest rewards, so the outstanding rewards should be (approximately)0. @@ -278,7 +274,7 @@ func (suite *KeeperTestSuite) TestOutstandingRewards() { suite.Harvest(suite.addrs[1], []string{denom1}) suite.Harvest(suite.addrs[2], []string{denom1}) - outstanding, _ = suite.keeper.GetOutstandingRewards(suite.ctx, denom1) + outstanding = suite.keeper.GetOutstandingRewards(suite.ctx, denom1) truncatedOutstanding, _ := outstanding.Rewards.TruncateDecimal() suite.Require().True(truncatedOutstanding.IsZero()) } @@ -318,8 +314,8 @@ func (suite *KeeperTestSuite) TestHistoricalRewards() { suite.ctx = suite.ctx.WithBlockTime(types.ParseTime("2021-08-06T00:00:00Z")) // Create two plans that share same staking coin denom in their staking coin weights. - suite.SetFixedAmountPlan(1, suite.addrs[4], map[string]string{denom1: "1"}, map[string]int64{denom3: 1000000}) - suite.SetFixedAmountPlan(2, suite.addrs[4], map[string]string{denom1: "1"}, map[string]int64{denom3: 1000000}) + suite.SetFixedAmountPlan(1, suite.addrs[4], "1denom1", "1000000denom3") + suite.SetFixedAmountPlan(2, suite.addrs[4], "1denom1", "1000000denom3") // Advancing epoch(s) before any staking is made doesn't create any historical rewards records. suite.AdvanceEpoch() @@ -356,3 +352,19 @@ func (suite *KeeperTestSuite) TestHistoricalRewards() { suite.Require().True(decCoinsEq(sdk.NewDecCoins(sdk.NewInt64DecCoin(denom3, int64((i+1)*2))), historical.CumulativeUnitRewards)) } } + +func (suite *KeeperTestSuite) TestHistoricalRewardsPruning() { + suite.SetFixedAmountPlan(1, suite.addrs[4], "1denom1", "1000000denom3") + + suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) + + fmt.Println("AdvanceEpoch()") + suite.AdvanceEpoch() + fmt.Println("AdvanceEpoch()") + suite.AdvanceEpoch() + + fmt.Println("Stake()") + suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) + fmt.Println("AdvanceEpoch()") + suite.AdvanceEpoch() +} diff --git a/x/farming/keeper/staking.go b/x/farming/keeper/staking.go index 9f42a8eb..c80975a2 100644 --- a/x/farming/keeper/staking.go +++ b/x/farming/keeper/staking.go @@ -182,6 +182,9 @@ func (k Keeper) IncreaseTotalStakings(ctx sdk.Context, stakingCoinDenom string, totalStaking, found := k.GetTotalStakings(ctx, stakingCoinDenom) if !found { totalStaking.Amount = sdk.ZeroInt() + if err := k.afterStakingCoinAdded(ctx, stakingCoinDenom); err != nil { + panic(err) + } } totalStaking.Amount = totalStaking.Amount.Add(amount) k.SetTotalStakings(ctx, stakingCoinDenom, totalStaking) @@ -195,6 +198,9 @@ func (k Keeper) DecreaseTotalStakings(ctx sdk.Context, stakingCoinDenom string, panic("total stakings not found") } if totalStaking.Amount.Equal(amount) { + if err := k.afterStakingCoinRemoved(ctx, stakingCoinDenom); err != nil { + panic(err) + } k.DeleteTotalStakings(ctx, stakingCoinDenom) } else { totalStaking.Amount = totalStaking.Amount.Sub(amount) @@ -202,6 +208,28 @@ func (k Keeper) DecreaseTotalStakings(ctx sdk.Context, stakingCoinDenom string, } } +func (k Keeper) afterStakingCoinAdded(ctx sdk.Context, stakingCoinDenom string) error { + // Set initial historical rewards with reference count of 1. + k.SetHistoricalRewards(ctx, stakingCoinDenom, 0, types.HistoricalRewards{CumulativeUnitRewards: sdk.DecCoins{}, ReferenceCount: 1}) + // Set current epoch as 1. + k.SetCurrentEpoch(ctx, stakingCoinDenom, 1) + k.SetOutstandingRewards(ctx, stakingCoinDenom, types.OutstandingRewards{Rewards: sdk.DecCoins{}}) + return nil +} + +func (k Keeper) afterStakingCoinRemoved(ctx sdk.Context, stakingCoinDenom string) error { + outstanding := k.GetOutstandingRewards(ctx, stakingCoinDenom) + + if !outstanding.Rewards.IsZero() { + // TODO: send to fee pool + } + + k.DeleteOutstandingRewards(ctx, stakingCoinDenom) + k.DeleteAllHistoricalRewards(ctx, stakingCoinDenom) + k.DeleteCurrentEpoch(ctx, stakingCoinDenom) + return nil +} + // ReserveStakingCoins sends staking coins to the staking reserve account. func (k Keeper) ReserveStakingCoins(ctx sdk.Context, farmerAcc sdk.AccAddress, stakingCoins sdk.Coins) error { if err := k.bankKeeper.SendCoins(ctx, farmerAcc, k.GetStakingReservePoolAcc(ctx), stakingCoins); err != nil { @@ -333,12 +361,15 @@ func (k Keeper) ProcessQueuedCoins(ctx sdk.Context) { } k.DeleteQueuedStaking(ctx, stakingCoinDenom, farmerAcc) + k.IncreaseTotalStakings(ctx, stakingCoinDenom, queuedStaking.Amount) + + currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) k.SetStaking(ctx, stakingCoinDenom, farmerAcc, types.Staking{ Amount: staking.Amount.Add(queuedStaking.Amount), - StartingEpoch: k.GetCurrentEpoch(ctx, stakingCoinDenom), + StartingEpoch: currentEpoch, }) - k.IncreaseTotalStakings(ctx, stakingCoinDenom, queuedStaking.Amount) + k.incrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) return false }) diff --git a/x/farming/keeper/staking_test.go b/x/farming/keeper/staking_test.go index ee18bbc3..8bc9e9d9 100644 --- a/x/farming/keeper/staking_test.go +++ b/x/farming/keeper/staking_test.go @@ -59,11 +59,7 @@ func (suite *KeeperTestSuite) TestStakeInAdvance() { suite.AdvanceEpoch() suite.AdvanceEpoch() - suite.SetFixedAmountPlan(1, suite.addrs[4], map[string]string{ - denom1: "1.0", - }, map[string]int64{ - denom3: 1000000, - }) + suite.SetFixedAmountPlan(1, suite.addrs[4], "1denom1", "1000000denom3") suite.Require().True(coinsEq(sdk.NewCoins(), suite.AllRewards(suite.addrs[0]))) suite.AdvanceEpoch() suite.Require().True(coinsEq(sdk.NewCoins(sdk.NewInt64Coin(denom3, 1000000)), suite.AllRewards(suite.addrs[0]))) @@ -184,7 +180,7 @@ func (suite *KeeperTestSuite) TestUnstakeNotAlwaysWithdraw() { // Unstaking from queued staking coins should not trigger // reward withdrawal. - suite.SetRatioPlan(1, suite.addrs[4], map[string]string{denom1: "1.0"}, "0.1") + suite.SetRatioPlan(1, suite.addrs[4], "1denom1", "0.1") suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) suite.AdvanceEpoch() diff --git a/x/farming/types/keys.go b/x/farming/types/keys.go index 8ab0872b..82cb7d8a 100644 --- a/x/farming/types/keys.go +++ b/x/farming/types/keys.go @@ -87,6 +87,12 @@ func GetHistoricalRewardsKey(stakingCoinDenom string, epoch uint64) []byte { return append(append(HistoricalRewardsKeyPrefix, LengthPrefixString(stakingCoinDenom)...), sdk.Uint64ToBigEndian(epoch)...) } +// GetHistoricalRewardsPrefix returns a key prefix used to iterate +// historical rewards for a staking coin denom. +func GetHistoricalRewardsPrefix(stakingCoinDenom string) []byte { + return append(HistoricalRewardsKeyPrefix, LengthPrefixString(stakingCoinDenom)...) +} + // GetCurrentEpochKey returns a key for a current epoch info. func GetCurrentEpochKey(stakingCoinDenom string) []byte { return append(CurrentEpochKeyPrefix, []byte(stakingCoinDenom)...) diff --git a/x/farming/types/keys_test.go b/x/farming/types/keys_test.go index 07e0bbd4..73e64e52 100644 --- a/x/farming/types/keys_test.go +++ b/x/farming/types/keys_test.go @@ -237,6 +237,11 @@ func (s *keysTestSuite) TestGetHistoricalRewardsKey() { } } +func (s *keysTestSuite) TestGetHistoricalRewardsPrefix() { + s.Require().Equal([]byte{0x31, 0x5, 0x73, 0x74, 0x61, 0x6b, 0x65}, types.GetHistoricalRewardsPrefix(sdk.DefaultBondDenom)) + s.Require().Equal([]byte{0x31, 0x6, 0x64, 0x65, 0x6e, 0x6f, 0x6d, 0x31}, types.GetHistoricalRewardsPrefix("denom1")) +} + func (s *keysTestSuite) TestGetCurrentEpochKey() { // key0 stakingCoinDenom0 := "" From e4035eaf6b06145f48825ac26195ef89b1d9c36e Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Tue, 26 Oct 2021 13:26:49 +0900 Subject: [PATCH 3/9] chore: WIP --- x/farming/keeper/reward.go | 4 +++- x/farming/keeper/staking.go | 13 +++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/x/farming/keeper/reward.go b/x/farming/keeper/reward.go index f276f611..9f746398 100644 --- a/x/farming/keeper/reward.go +++ b/x/farming/keeper/reward.go @@ -249,6 +249,9 @@ func (k Keeper) AllRewards(ctx sdk.Context, farmerAcc sdk.AccAddress) sdk.Coins // It decreases outstanding rewards and set the starting epoch of a // staking. func (k Keeper) WithdrawRewards(ctx sdk.Context, farmerAcc sdk.AccAddress, stakingCoinDenom string) (sdk.Coins, error) { + // TODO: IncrementValidatorPeriod + // TODO: decrementReferenceCount + staking, found := k.GetStaking(ctx, stakingCoinDenom, farmerAcc) if !found { return nil, types.ErrStakingNotExists @@ -470,7 +473,6 @@ func (k Keeper) AllocateRewards(ctx sdk.Context) error { ReferenceCount: 1, }) k.SetCurrentEpoch(ctx, stakingCoinDenom, currentEpoch+1) - k.decrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) } return nil diff --git a/x/farming/keeper/staking.go b/x/farming/keeper/staking.go index c80975a2..f5f43639 100644 --- a/x/farming/keeper/staking.go +++ b/x/farming/keeper/staking.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -209,6 +211,7 @@ func (k Keeper) DecreaseTotalStakings(ctx sdk.Context, stakingCoinDenom string, } func (k Keeper) afterStakingCoinAdded(ctx sdk.Context, stakingCoinDenom string) error { + fmt.Printf("afterStakingCoinAdded(%s)\n", stakingCoinDenom) // Set initial historical rewards with reference count of 1. k.SetHistoricalRewards(ctx, stakingCoinDenom, 0, types.HistoricalRewards{CumulativeUnitRewards: sdk.DecCoins{}, ReferenceCount: 1}) // Set current epoch as 1. @@ -218,6 +221,7 @@ func (k Keeper) afterStakingCoinAdded(ctx sdk.Context, stakingCoinDenom string) } func (k Keeper) afterStakingCoinRemoved(ctx sdk.Context, stakingCoinDenom string) error { + fmt.Printf("afterStakingCoinRemoved(%s)\n", stakingCoinDenom) outstanding := k.GetOutstandingRewards(ctx, stakingCoinDenom) if !outstanding.Rewards.IsZero() { @@ -351,6 +355,8 @@ func (k Keeper) Unstake(ctx sdk.Context, farmerAcc sdk.AccAddress, amount sdk.Co // It causes accumulated rewards to be withdrawn to the farmer. func (k Keeper) ProcessQueuedCoins(ctx sdk.Context) { k.IterateQueuedStakings(ctx, func(stakingCoinDenom string, farmerAcc sdk.AccAddress, queuedStaking types.QueuedStaking) (stop bool) { + k.DeleteQueuedStaking(ctx, stakingCoinDenom, farmerAcc) + staking, found := k.GetStaking(ctx, stakingCoinDenom, farmerAcc) if found { if _, err := k.WithdrawRewards(ctx, farmerAcc, stakingCoinDenom); err != nil { @@ -358,19 +364,18 @@ func (k Keeper) ProcessQueuedCoins(ctx sdk.Context) { } } else { staking.Amount = sdk.ZeroInt() + // TODO: IncrementValidatorPeriod } - k.DeleteQueuedStaking(ctx, stakingCoinDenom, farmerAcc) - k.IncreaseTotalStakings(ctx, stakingCoinDenom, queuedStaking.Amount) - currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) k.SetStaking(ctx, stakingCoinDenom, farmerAcc, types.Staking{ Amount: staking.Amount.Add(queuedStaking.Amount), StartingEpoch: currentEpoch, }) - k.incrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) + k.IncreaseTotalStakings(ctx, stakingCoinDenom, queuedStaking.Amount) + return false }) } From dec17f9081eda61cb9fa4c236f4e7c77e72055b9 Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Wed, 10 Nov 2021 11:44:42 +0900 Subject: [PATCH 4/9] fix: set initial ref count as 1 --- x/farming/keeper/staking.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x/farming/keeper/staking.go b/x/farming/keeper/staking.go index fc2e8d52..4f1859d7 100644 --- a/x/farming/keeper/staking.go +++ b/x/farming/keeper/staking.go @@ -246,7 +246,7 @@ func (k Keeper) ReleaseStakingCoins(ctx sdk.Context, farmerAcc sdk.AccAddress, u // afterStakingCoinAdded is called after a new staking coin denom appeared // during ProcessQueuedCoins. func (k Keeper) afterStakingCoinAdded(ctx sdk.Context, stakingCoinDenom string) error { - k.SetHistoricalRewards(ctx, stakingCoinDenom, 0, types.HistoricalRewards{CumulativeUnitRewards: sdk.DecCoins{}}) + k.SetHistoricalRewards(ctx, stakingCoinDenom, 0, types.HistoricalRewards{CumulativeUnitRewards: sdk.DecCoins{}, ReferenceCount: 1}) k.SetCurrentEpoch(ctx, stakingCoinDenom, 1) k.SetOutstandingRewards(ctx, stakingCoinDenom, types.OutstandingRewards{Rewards: sdk.DecCoins{}}) return nil @@ -386,7 +386,6 @@ func (k Keeper) ProcessQueuedCoins(ctx sdk.Context) { } } else { staking.Amount = sdk.ZeroInt() - // TODO: IncrementValidatorPeriod } k.DeleteQueuedStaking(ctx, stakingCoinDenom, farmerAcc) From 7655863de7da870e7a294aa0dd0175ff7968193e Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Wed, 10 Nov 2021 14:41:26 +0900 Subject: [PATCH 5/9] fix: fix reference counting --- x/farming/keeper/reward.go | 24 +++++++--------------- x/farming/keeper/reward_test.go | 35 ++++++++++++++++++++++++++++++++ x/farming/keeper/staking.go | 7 ++++--- x/farming/keeper/staking_test.go | 20 ++++++++++++++++++ 4 files changed, 66 insertions(+), 20 deletions(-) diff --git a/x/farming/keeper/reward.go b/x/farming/keeper/reward.go index 30d2209a..b371563a 100644 --- a/x/farming/keeper/reward.go +++ b/x/farming/keeper/reward.go @@ -1,7 +1,6 @@ package keeper import ( - "fmt" "strconv" "strings" @@ -69,30 +68,23 @@ func (k Keeper) IterateHistoricalRewards(ctx sdk.Context, cb func(stakingCoinDen // incrementReferenceCount increments the reference count for a historical rewards. func (k Keeper) incrementReferenceCount(ctx sdk.Context, stakingCoinDenom string, epoch uint64) { - fmt.Printf("incrementReferenceCount(%s, %d)\n", stakingCoinDenom, epoch) historical, found := k.GetHistoricalRewards(ctx, stakingCoinDenom, epoch) if !found { - panic("historical rewards not found") // TODO: choose correct error message + panic("historical rewards not found") } - if historical.ReferenceCount > 2 { - panic("reference count should never exceed 2") - } - fmt.Printf(" %d -> %d\n", historical.ReferenceCount, historical.ReferenceCount+1) historical.ReferenceCount++ k.SetHistoricalRewards(ctx, stakingCoinDenom, epoch, historical) } // decrementReferenceCount decrements the reference count for a historical rewards. func (k Keeper) decrementReferenceCount(ctx sdk.Context, stakingCoinDenom string, epoch uint64) { - fmt.Printf("decrementReferenceCount(%s, %d)\n", stakingCoinDenom, epoch) historical, found := k.GetHistoricalRewards(ctx, stakingCoinDenom, epoch) if !found { - panic("historical rewards not found") // TODO: choose correct error message + panic("historical rewards not found") } if historical.ReferenceCount == 0 { panic("cannot set negative reference count") } - fmt.Printf(" %d -> %d\n", historical.ReferenceCount, historical.ReferenceCount-1) historical.ReferenceCount-- if historical.ReferenceCount == 0 { k.DeleteHistoricalRewards(ctx, stakingCoinDenom, epoch) @@ -255,16 +247,15 @@ func (k Keeper) AllRewards(ctx sdk.Context, farmerAcc sdk.AccAddress) sdk.Coins // It decreases outstanding rewards and set the starting epoch of a // staking. func (k Keeper) WithdrawRewards(ctx sdk.Context, farmerAcc sdk.AccAddress, stakingCoinDenom string) (sdk.Coins, error) { - // TODO: IncrementValidatorPeriod - // TODO: decrementReferenceCount - staking, found := k.GetStaking(ctx, stakingCoinDenom, farmerAcc) if !found { return nil, types.ErrStakingNotExists } currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) - fmt.Printf("WithdrawRewards(%s) - CalculateRewards(%s, %d)\n", stakingCoinDenom, stakingCoinDenom, currentEpoch-1) + if currentEpoch == staking.StartingEpoch { + return sdk.Coins{}, nil + } rewards := k.CalculateRewards(ctx, farmerAcc, stakingCoinDenom, currentEpoch-1) truncatedRewards, _ := rewards.TruncateDecimal() @@ -287,9 +278,9 @@ func (k Keeper) WithdrawRewards(ctx sdk.Context, farmerAcc sdk.AccAddress, staki k.DecreaseOutstandingRewards(ctx, stakingCoinDenom, rewards) } + k.decrementReferenceCount(ctx, stakingCoinDenom, staking.StartingEpoch-1) staking.StartingEpoch = currentEpoch k.SetStaking(ctx, stakingCoinDenom, farmerAcc, staking) - k.decrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) return truncatedRewards, nil } @@ -471,9 +462,8 @@ func (k Keeper) AllocateRewards(ctx sdk.Context) error { for stakingCoinDenom, unitRewards := range unitRewardsByDenom { currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) - fmt.Printf("AllocateRewards :: Setting HistoricalRewards for %d\n", currentEpoch) - fmt.Printf(" Updating CurrentEpoch %d -> %d\n", currentEpoch, currentEpoch+1) historical, _ := k.GetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch-1) + // TODO: decrement ref count? k.SetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch, types.HistoricalRewards{ CumulativeUnitRewards: historical.CumulativeUnitRewards.Add(unitRewards...), ReferenceCount: 1, diff --git a/x/farming/keeper/reward_test.go b/x/farming/keeper/reward_test.go index 5b26b71e..3f640692 100644 --- a/x/farming/keeper/reward_test.go +++ b/x/farming/keeper/reward_test.go @@ -425,3 +425,38 @@ func (suite *KeeperTestSuite) TestInitializeAndPruneStakingCoinInfo() { _, found = suite.keeper.GetOutstandingRewards(suite.ctx, denom1) suite.Require().False(found) } + +func (suite *KeeperTestSuite) TestPruneHistoricalRewards() { + suite.SetFixedAmountPlan(1, suite.addrs[4], "1denom1", "1000000denom3") + + for i := 0; i < 3; i++ { + suite.AdvanceEpoch() + } + + for _, addr := range suite.addrs[:4] { + suite.Stake(addr, sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) + } + + for i := 0; i < 3; i++ { + suite.AdvanceEpoch() + } + + for _, addr := range suite.addrs[:4] { + suite.Stake(addr, sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) + } + + for i := 0; i < 3; i++ { + suite.AdvanceEpoch() + } + + for _, addr := range suite.addrs[:4] { + suite.Unstake(addr, sdk.NewCoins(sdk.NewInt64Coin(denom1, 2000000))) + } + + cnt := 0 + suite.keeper.IterateHistoricalRewards(suite.ctx, func(stakingCoinDenom string, epoch uint64, rewards types.HistoricalRewards) (stop bool) { + cnt++ + return false + }) + suite.Require().Zero(cnt) +} diff --git a/x/farming/keeper/staking.go b/x/farming/keeper/staking.go index 4f1859d7..df8445ee 100644 --- a/x/farming/keeper/staking.go +++ b/x/farming/keeper/staking.go @@ -377,8 +377,6 @@ func (k Keeper) Unstake(ctx sdk.Context, farmerAcc sdk.AccAddress, amount sdk.Co // It causes accumulated rewards to be withdrawn to the farmer. func (k Keeper) ProcessQueuedCoins(ctx sdk.Context) { k.IterateQueuedStakings(ctx, func(stakingCoinDenom string, farmerAcc sdk.AccAddress, queuedStaking types.QueuedStaking) (stop bool) { - k.DeleteQueuedStaking(ctx, stakingCoinDenom, farmerAcc) - staking, found := k.GetStaking(ctx, stakingCoinDenom, farmerAcc) if found { if _, err := k.WithdrawRewards(ctx, farmerAcc, stakingCoinDenom); err != nil { @@ -391,12 +389,15 @@ func (k Keeper) ProcessQueuedCoins(ctx sdk.Context) { k.DeleteQueuedStaking(ctx, stakingCoinDenom, farmerAcc) k.IncreaseTotalStakings(ctx, stakingCoinDenom, queuedStaking.Amount) + startingEpoch := staking.StartingEpoch currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) k.SetStaking(ctx, stakingCoinDenom, farmerAcc, types.Staking{ Amount: staking.Amount.Add(queuedStaking.Amount), StartingEpoch: currentEpoch, }) - k.incrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) + if startingEpoch != currentEpoch { + k.incrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) + } return false }) diff --git a/x/farming/keeper/staking_test.go b/x/farming/keeper/staking_test.go index 9d81050c..48cced76 100644 --- a/x/farming/keeper/staking_test.go +++ b/x/farming/keeper/staking_test.go @@ -6,6 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" _ "github.com/stretchr/testify/suite" + + "github.com/tendermint/farming/x/farming/types" ) func (suite *KeeperTestSuite) TestStake() { @@ -316,3 +318,21 @@ func (suite *KeeperTestSuite) TestDelayedStakingGasFee() { suite.Require().GreaterOrEqual(gasConsumedWithStaking, params.DelayedStakingGasFee) suite.Require().Greater(gasConsumedWithStaking, gasConsumedNormal) } + +func (suite *KeeperTestSuite) TestPruneStatesWithoutRewards() { + for i := 0; i < 10; i++ { + suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) + suite.AdvanceEpoch() + } + + suite.Unstake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 10000000))) + + cnt := 0 + suite.keeper.IterateHistoricalRewards(suite.ctx, func(stakingCoinDenom string, epoch uint64, rewards types.HistoricalRewards) (stop bool) { + if stakingCoinDenom == denom1 { + cnt++ + } + return false + }) + suite.Require().Zero(cnt) +} From b080d3ceaf39a338abfd20ec643ca6eec886b8eb Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Wed, 10 Nov 2021 14:47:33 +0900 Subject: [PATCH 6/9] chore: remove outdated TODO comment --- x/farming/keeper/reward.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/farming/keeper/reward.go b/x/farming/keeper/reward.go index b371563a..b1c3fd6a 100644 --- a/x/farming/keeper/reward.go +++ b/x/farming/keeper/reward.go @@ -463,7 +463,6 @@ func (k Keeper) AllocateRewards(ctx sdk.Context) error { for stakingCoinDenom, unitRewards := range unitRewardsByDenom { currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) historical, _ := k.GetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch-1) - // TODO: decrement ref count? k.SetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch, types.HistoricalRewards{ CumulativeUnitRewards: historical.CumulativeUnitRewards.Add(unitRewards...), ReferenceCount: 1, From 0ff803f8e282a566c6f0f3da71f980b43a536697 Mon Sep 17 00:00:00 2001 From: dongsam Date: Fri, 12 Nov 2021 17:33:31 +0900 Subject: [PATCH 7/9] fix: merge conflicts --- x/farming/keeper/proposal_handler_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/farming/keeper/proposal_handler_test.go b/x/farming/keeper/proposal_handler_test.go index 4254a406..df67d661 100644 --- a/x/farming/keeper/proposal_handler_test.go +++ b/x/farming/keeper/proposal_handler_test.go @@ -185,7 +185,7 @@ func (suite *KeeperTestSuite) TestDeletePlanRequest() { suite.Require().Empty(plans) // Test for private plan cannot be deleted. - suite.CreateFixedAmountPlan(suite.addrs[4], map[string]string{denom1: "1"}, map[string]int64{denom3: 1000000}) + suite.CreateFixedAmountPlan(suite.addrs[4], "1denom1", "1000000denom3") plans = suite.keeper.GetPlans(suite.ctx) suite.Require().Equal(plans[0].GetId(), uint64(2)) From 1d36fee912557dd0d795342e2733332ab7322e96 Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Wed, 24 Nov 2021 18:28:12 +0900 Subject: [PATCH 8/9] fix: fix state pruning logic --- x/farming/keeper/reward.go | 2 ++ x/farming/keeper/reward_test.go | 17 ++++++++++------- x/farming/keeper/staking.go | 10 +++++++--- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/x/farming/keeper/reward.go b/x/farming/keeper/reward.go index 2aa28665..59ab57c9 100644 --- a/x/farming/keeper/reward.go +++ b/x/farming/keeper/reward.go @@ -279,6 +279,7 @@ func (k Keeper) WithdrawRewards(ctx sdk.Context, farmerAcc sdk.AccAddress, staki } k.decrementReferenceCount(ctx, stakingCoinDenom, staking.StartingEpoch-1) + k.incrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) staking.StartingEpoch = currentEpoch k.SetStaking(ctx, stakingCoinDenom, farmerAcc, staking) @@ -492,6 +493,7 @@ func (k Keeper) AllocateRewards(ctx sdk.Context) error { for stakingCoinDenom, unitRewards := range unitRewardsByDenom { currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) historical, _ := k.GetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch-1) + k.decrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) k.SetHistoricalRewards(ctx, stakingCoinDenom, currentEpoch, types.HistoricalRewards{ CumulativeUnitRewards: historical.CumulativeUnitRewards.Add(unitRewards...), ReferenceCount: 1, diff --git a/x/farming/keeper/reward_test.go b/x/farming/keeper/reward_test.go index 6c4b5c5d..fd9c1cf5 100644 --- a/x/farming/keeper/reward_test.go +++ b/x/farming/keeper/reward_test.go @@ -430,20 +430,23 @@ func (suite *KeeperTestSuite) TestHistoricalRewards() { suite.AdvanceEpoch() suite.AdvanceEpoch() - // First, ensure that we have only 3 entries in the store. + // First, ensure that we have only two entries in the store. + // One is for the epoch 0, and other one is for epoch 3. count = 0 suite.keeper.IterateHistoricalRewards(suite.ctx, func(stakingCoinDenom string, epoch uint64, rewards types.HistoricalRewards) (stop bool) { count++ return false }) - suite.Require().Equal(4, count) + suite.Require().Equal(2, count) // Next, check if cumulative unit rewards is correct. - for i := uint64(1); i <= 3; i++ { - historical, found := suite.keeper.GetHistoricalRewards(suite.ctx, denom1, i) - suite.Require().True(found) - suite.Require().True(decCoinsEq(sdk.NewDecCoins(sdk.NewInt64DecCoin(denom3, int64(i*2))), historical.CumulativeUnitRewards)) - } + historical, found := suite.keeper.GetHistoricalRewards(suite.ctx, denom1, 0) + suite.Require().True(found) + suite.Require().True(decCoinsEq(sdk.DecCoins{}, historical.CumulativeUnitRewards)) + + historical, found = suite.keeper.GetHistoricalRewards(suite.ctx, denom1, 3) + suite.Require().True(found) + suite.Require().True(decCoinsEq(sdk.NewDecCoins(sdk.NewInt64DecCoin(denom3, 6)), historical.CumulativeUnitRewards)) } // Test if initialization and pruning of staking coin info work properly. diff --git a/x/farming/keeper/staking.go b/x/farming/keeper/staking.go index a1f25975..a5474052 100644 --- a/x/farming/keeper/staking.go +++ b/x/farming/keeper/staking.go @@ -337,13 +337,15 @@ func (k Keeper) Unstake(ctx sdk.Context, farmerAcc sdk.AccAddress, amount sdk.Co return err } + currentEpoch := k.GetCurrentEpoch(ctx, coin.Denom) + removedFromStaking := queuedStaking.Amount.Neg() // Make negative a positive staking.Amount = staking.Amount.Sub(removedFromStaking) if staking.Amount.IsPositive() { - currentEpoch := k.GetCurrentEpoch(ctx, coin.Denom) staking.StartingEpoch = currentEpoch k.SetStaking(ctx, coin.Denom, farmerAcc, staking) } else { + k.decrementReferenceCount(ctx, coin.Denom, currentEpoch-1) k.DeleteStaking(ctx, coin.Denom, farmerAcc) } @@ -375,11 +377,14 @@ func (k Keeper) Unstake(ctx sdk.Context, farmerAcc sdk.AccAddress, amount sdk.Co // It causes accumulated rewards to be withdrawn to the farmer. func (k Keeper) ProcessQueuedCoins(ctx sdk.Context) { k.IterateQueuedStakings(ctx, func(stakingCoinDenom string, farmerAcc sdk.AccAddress, queuedStaking types.QueuedStaking) (stop bool) { + incremented := false + staking, found := k.GetStaking(ctx, stakingCoinDenom, farmerAcc) if found { if _, err := k.WithdrawRewards(ctx, farmerAcc, stakingCoinDenom); err != nil { panic(err) } + incremented = true } else { staking.Amount = sdk.ZeroInt() } @@ -387,13 +392,12 @@ func (k Keeper) ProcessQueuedCoins(ctx sdk.Context) { k.DeleteQueuedStaking(ctx, stakingCoinDenom, farmerAcc) k.IncreaseTotalStakings(ctx, stakingCoinDenom, queuedStaking.Amount) - startingEpoch := staking.StartingEpoch currentEpoch := k.GetCurrentEpoch(ctx, stakingCoinDenom) k.SetStaking(ctx, stakingCoinDenom, farmerAcc, types.Staking{ Amount: staking.Amount.Add(queuedStaking.Amount), StartingEpoch: currentEpoch, }) - if startingEpoch != currentEpoch { + if !incremented { k.incrementReferenceCount(ctx, stakingCoinDenom, currentEpoch-1) } From f291650307b812c3b3423cad8739f6fb5525f0e0 Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Thu, 25 Nov 2021 18:52:37 +0900 Subject: [PATCH 9/9] test: add tests --- x/farming/keeper/reward_test.go | 146 +++++++++++++++++++++++++++++++ x/farming/keeper/staking_test.go | 2 +- 2 files changed, 147 insertions(+), 1 deletion(-) diff --git a/x/farming/keeper/reward_test.go b/x/farming/keeper/reward_test.go index fd9c1cf5..b4008780 100644 --- a/x/farming/keeper/reward_test.go +++ b/x/farming/keeper/reward_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "math/rand" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -540,3 +541,148 @@ func (suite *KeeperTestSuite) TestPruneHistoricalRewards() { }) suite.Require().Zero(cnt) } + +func (suite *KeeperTestSuite) TestReferenceCounting() { + // Staking coins before any plan has created will create a historical + // rewards record at epoch 0 for that denom. + suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000))) + suite.Stake(suite.addrs[1], sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000))) + suite.AdvanceEpoch() + + // Even for multiple stakings, it does not increment the denom's current epoch. + suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000))) + suite.Stake(suite.addrs[1], sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000))) + suite.AdvanceEpoch() + + historical, found := suite.keeper.GetHistoricalRewards(suite.ctx, sdk.DefaultBondDenom, 0) + suite.Require().True(found) + suite.Require().True(decCoinsEq(sdk.DecCoins{}, historical.CumulativeUnitRewards)) + suite.Require().Equal(uint32(3), historical.ReferenceCount) + + // Next, create two plans. + suite.CreateFixedAmountPlan(suite.addrs[4], "1denom1", "1000000denom3") + suite.CreateRatioPlan(suite.addrs[5], "1denom1", "0.01") + + // Farmers stake. + suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) + suite.Stake(suite.addrs[1], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) + + suite.AdvanceEpoch() + suite.AdvanceEpoch() // Rewards allocated. + suite.AdvanceEpoch() + suite.AdvanceEpoch() + + // Ensure there are only two historical rewards records found, and check + // reference counts. + cnt := 0 + refCnt := uint32(0) + suite.keeper.IterateHistoricalRewards(suite.ctx, func(stakingCoinDenom string, epoch uint64, rewards types.HistoricalRewards) (stop bool) { + if stakingCoinDenom == denom1 { + cnt++ + refCnt += rewards.ReferenceCount + } + return false + }) + suite.Require().Equal(2, cnt) + suite.Require().Equal(uint32(3), refCnt) + + // After a farmer harvests, check historical rewards records again. + suite.Harvest(suite.addrs[0], []string{denom1}) + + cnt = 0 + suite.keeper.IterateHistoricalRewards(suite.ctx, func(stakingCoinDenom string, epoch uint64, rewards types.HistoricalRewards) (stop bool) { + if stakingCoinDenom == denom1 { + cnt++ + } + return false + }) + suite.Require().Equal(2, cnt) + historical, found = suite.keeper.GetHistoricalRewards(suite.ctx, denom1, 0) + suite.Require().True(found) + suite.Require().Equal(uint32(1), historical.ReferenceCount) + historical, found = suite.keeper.GetHistoricalRewards(suite.ctx, denom1, 3) + suite.Require().True(found) + suite.Require().Equal(uint32(2), historical.ReferenceCount) + + suite.AdvanceEpoch() + suite.AdvanceEpoch() + + suite.Unstake(suite.addrs[1], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) + refCnt = 0 + suite.keeper.IterateHistoricalRewards(suite.ctx, func(stakingCoinDenom string, epoch uint64, rewards types.HistoricalRewards) (stop bool) { + if stakingCoinDenom == denom1 { + refCnt += rewards.ReferenceCount + } + return false + }) + suite.Require().Equal(uint32(2), refCnt) + _, found = suite.keeper.GetHistoricalRewards(suite.ctx, denom1, 0) + suite.Require().False(found) + historical, found = suite.keeper.GetHistoricalRewards(suite.ctx, denom1, 3) + suite.Require().True(found) + suite.Require().Equal(uint32(1), historical.ReferenceCount) + historical, found = suite.keeper.GetHistoricalRewards(suite.ctx, denom1, 5) + suite.Require().True(found) + suite.Require().Equal(uint32(1), historical.ReferenceCount) +} + +func (suite *KeeperTestSuite) TestReferenceCountingFuzz() { + for seed := int64(0); seed < 100; seed++ { + r := rand.New(rand.NewSource(seed)) + + suite.SetupTest() + suite.CreateFixedAmountPlan(suite.addrs[4], "1denom1", "1000000denom3") + suite.CreateRatioPlan(suite.addrs[5], "1denom1", "0.0001") + + staked := map[int]sdk.Coins{} + queued := map[int]sdk.Coins{} + for epoch := 0; epoch < 100; epoch++ { + for i, addr := range suite.addrs[:5] { + if r.Intn(5) == 0 { // Unstake with a 20% chance. + amount, ok := staked[i] + if ok { + if r.Intn(5) == 0 { + // Unstake all(staked) coins. + suite.Unstake(addr, amount) + delete(staked, i) + } else { + // Unstake staked - (1 ~ (staked - 1)) coins. + if amount.AmountOf(denom1).GT(sdk.OneInt()) { + subAmount := sdk.NewCoins(sdk.NewInt64Coin(denom1, 1+r.Int63n(amount.AmountOf(denom1).Int64()-1))) + suite.Unstake(addr, subAmount) + staked[i] = amount.Sub(subAmount) + } + } + } + } + if r.Intn(5) == 0 { // Stake with a 20% chance. + amount := sdk.NewCoins(sdk.NewInt64Coin(denom1, 1+r.Int63n(50))) + suite.Stake(addr, amount) + queued[i] = amount + } + if r.Intn(5) == 0 { + _, ok := staked[i] + if ok { + suite.Harvest(addr, []string{denom1}) + } + } + } + suite.AdvanceEpoch() + for i, amount := range queued { + staked[i] = staked[i].Add(amount...) + delete(queued, i) + } + + refCnt := uint32(0) + suite.keeper.IterateHistoricalRewards(suite.ctx, func(stakingCoinDenom string, epoch uint64, rewards types.HistoricalRewards) (stop bool) { + refCnt += rewards.ReferenceCount + return false + }) + if len(staked) > 0 { + suite.Require().Equal(uint32(len(staked))+1, refCnt) + } else { + suite.Require().Equal(uint32(0), refCnt) + } + } + } +} diff --git a/x/farming/keeper/staking_test.go b/x/farming/keeper/staking_test.go index c10c7aaf..134f6164 100644 --- a/x/farming/keeper/staking_test.go +++ b/x/farming/keeper/staking_test.go @@ -320,7 +320,7 @@ func (suite *KeeperTestSuite) TestDelayedStakingGasFee() { suite.Require().Greater(gasConsumedWithStaking, gasConsumedNormal) } -func (suite *KeeperTestSuite) TestPruneStatesWithoutRewards() { +func (suite *KeeperTestSuite) TestPruneStateWithoutRewards() { for i := 0; i < 10; i++ { suite.Stake(suite.addrs[0], sdk.NewCoins(sdk.NewInt64Coin(denom1, 1000000))) suite.AdvanceEpoch()