diff --git a/changelog.md b/changelog.md index 091479dea1..9609ca7bd7 100644 --- a/changelog.md +++ b/changelog.md @@ -26,6 +26,7 @@ * [2725](https://github.com/zeta-chain/node/pull/2725) - refactor SetCctxAndNonceToCctxAndInboundHashToCctx to receive tsspubkey as an argument * [2802](https://github.com/zeta-chain/node/pull/2802) - set default liquidity cap for new ZRC20s * [2826](https://github.com/zeta-chain/node/pull/2826) - remove unused code from emissions module and add new parameter for fixed block reward amount +* [2863](https://github.com/zeta-chain/node/pull/2863) - delete ballots after they mature ### Tests diff --git a/typescript/zetachain/zetacore/observer/ballot_pb.d.ts b/typescript/zetachain/zetacore/observer/ballot_pb.d.ts index 286d51d5aa..5867a3c604 100644 --- a/typescript/zetachain/zetacore/observer/ballot_pb.d.ts +++ b/typescript/zetachain/zetacore/observer/ballot_pb.d.ts @@ -142,3 +142,32 @@ export declare class BallotListForHeight extends Message { static equals(a: BallotListForHeight | PlainMessage | undefined, b: BallotListForHeight | PlainMessage | undefined): boolean; } +/** + * @generated from message zetachain.zetacore.observer.VoterList + */ +export declare class VoterList extends Message { + /** + * @generated from field: string voter_address = 1; + */ + voterAddress: string; + + /** + * @generated from field: zetachain.zetacore.observer.VoteType vote_type = 2; + */ + voteType: VoteType; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.observer.VoterList"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): VoterList; + + static fromJson(jsonValue: JsonValue, options?: Partial): VoterList; + + static fromJsonString(jsonString: string, options?: Partial): VoterList; + + static equals(a: VoterList | PlainMessage | undefined, b: VoterList | PlainMessage | undefined): boolean; +} + diff --git a/typescript/zetachain/zetacore/observer/events_pb.d.ts b/typescript/zetachain/zetacore/observer/events_pb.d.ts index 61987af05d..cd9824a0d6 100644 --- a/typescript/zetachain/zetacore/observer/events_pb.d.ts +++ b/typescript/zetachain/zetacore/observer/events_pb.d.ts @@ -5,6 +5,7 @@ import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; import { Message, proto3 } from "@bufbuild/protobuf"; +import type { VoterList } from "./ballot_pb.js"; import type { GasPriceIncreaseFlags } from "./crosschain_flags_pb.js"; /** @@ -71,9 +72,9 @@ export declare class EventBallotDeleted extends Message { ballotType: string; /** - * @generated from field: string votes_collected = 4; + * @generated from field: repeated zetachain.zetacore.observer.VoterList voters = 4; */ - votesCollected: string; + voters: VoterList[]; constructor(data?: PartialMessage); diff --git a/typescript/zetachain/zetacore/observer/query_pb.d.ts b/typescript/zetachain/zetacore/observer/query_pb.d.ts index 65f151c3be..7ce071ea83 100644 --- a/typescript/zetachain/zetacore/observer/query_pb.d.ts +++ b/typescript/zetachain/zetacore/observer/query_pb.d.ts @@ -10,7 +10,7 @@ import type { ChainNonces } from "./chain_nonces_pb.js"; import type { PageRequest, PageResponse } from "../../../cosmos/base/query/v1beta1/pagination_pb.js"; import type { PendingNonces } from "./pending_nonces_pb.js"; import type { TSS } from "./tss_pb.js"; -import type { BallotStatus, VoteType } from "./ballot_pb.js"; +import type { BallotStatus, VoterList } from "./ballot_pb.js"; import type { LastObserverCount, ObservationType } from "./observer_pb.js"; import type { Chain } from "../pkg/chains/chains_pb.js"; import type { ChainParams, ChainParamsList } from "./params_pb.js"; @@ -596,35 +596,6 @@ export declare class QueryBallotByIdentifierRequest extends Message | undefined, b: QueryBallotByIdentifierRequest | PlainMessage | undefined): boolean; } -/** - * @generated from message zetachain.zetacore.observer.VoterList - */ -export declare class VoterList extends Message { - /** - * @generated from field: string voter_address = 1; - */ - voterAddress: string; - - /** - * @generated from field: zetachain.zetacore.observer.VoteType vote_type = 2; - */ - voteType: VoteType; - - constructor(data?: PartialMessage); - - static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.observer.VoterList"; - static readonly fields: FieldList; - - static fromBinary(bytes: Uint8Array, options?: Partial): VoterList; - - static fromJson(jsonValue: JsonValue, options?: Partial): VoterList; - - static fromJsonString(jsonString: string, options?: Partial): VoterList; - - static equals(a: VoterList | PlainMessage | undefined, b: VoterList | PlainMessage | undefined): boolean; -} - /** * @generated from message zetachain.zetacore.observer.QueryBallotByIdentifierResponse */ diff --git a/x/emissions/abci.go b/x/emissions/abci.go index 7909793027..4ab0e4da24 100644 --- a/x/emissions/abci.go +++ b/x/emissions/abci.go @@ -6,11 +6,11 @@ import ( sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - observertypes "github.com/zeta-chain/node/x/observer/types" "github.com/zeta-chain/node/cmd/zetacored/config" "github.com/zeta-chain/node/x/emissions/keeper" "github.com/zeta-chain/node/x/emissions/types" + observertypes "github.com/zeta-chain/node/x/observer/types" ) func BeginBlocker(ctx sdk.Context, keeper keeper.Keeper) { diff --git a/x/emissions/abci_test.go b/x/emissions/abci_test.go index 2ef62ed7b5..95bd9b45ac 100644 --- a/x/emissions/abci_test.go +++ b/x/emissions/abci_test.go @@ -203,7 +203,8 @@ func TestBeginBlocker(t *testing.T) { }) t.Run("successfully distribute rewards", func(t *testing.T) { - numberOfTestBlocks := 100 + //Arrange + numberOfTestBlocks := 10 k, ctx, sk, zk := keepertest.EmissionsKeeper(t) observerSet := sample.ObserverSet(10) zk.ObserverKeeper.SetObserverSet(ctx, observerSet) @@ -238,6 +239,9 @@ func TestBeginBlocker(t *testing.T) { params, found := k.GetParams(ctx) require.True(t, found) + // Set the ballot maturity blocks to numberOfTestBlocks so that the ballot mature at the end of the for loop which produces blocks + params.BallotMaturityBlocks = int64(numberOfTestBlocks) + err = k.SetParams(ctx, params) // Get the rewards distribution, this is a fixed amount based on total block rewards and distribution percentages validatorRewardsForABlock, observerRewardsForABlock, tssSignerRewardsForABlock := emissionstypes.GetRewardsDistributions( @@ -247,6 +251,11 @@ func TestBeginBlocker(t *testing.T) { distributedRewards := observerRewardsForABlock.Add(validatorRewardsForABlock).Add(tssSignerRewardsForABlock) require.True(t, blockRewards.TruncateInt().GT(distributedRewards)) + require.Len(t, zk.ObserverKeeper.GetAllBallots(ctx), len(ballotList)) + _, found = zk.ObserverKeeper.GetBallotList(ctx, 0) + require.True(t, found) + + // Act for i := 0; i < numberOfTestBlocks; i++ { emissionPoolBeforeBlockDistribution := sk.BankKeeper.GetBalance(ctx, emissionPool, config.BaseDenom).Amount // produce a block @@ -277,12 +286,23 @@ func TestBeginBlocker(t *testing.T) { ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) } + // Assert + + // 1. Assert Observer rewards, these are distributed at the block in which the ballots mature. + // numberOfTestBlocks is the same maturity blocks for the ballots + // We can simplify the calculation as the rewards are distributed equally among all the observers rewardPerUnit := observerRewardsForABlock.Quo( sdk.NewInt(int64(len(ballotList) * len(observerSet.ObserverList))), ) emissionAmount := rewardPerUnit.Mul(sdk.NewInt(int64(len(ballotList)))) + // 2 . Assert ballots and ballot list are deleted on maturity + require.Len(t, zk.ObserverKeeper.GetAllBallots(ctx), 0) + _, found = zk.ObserverKeeper.GetBallotList(ctx, 0) + require.False(t, found) + + //3. Assert amounts in undistributed pools // Check if the rewards are distributed equally among all the observers for _, observer := range observerSet.ObserverList { observerEmission, found := k.GetWithdrawableEmission(ctx, observer) diff --git a/x/observer/keeper/events_test.go b/x/observer/keeper/events_test.go index 6f286e141e..2fcda72609 100644 --- a/x/observer/keeper/events_test.go +++ b/x/observer/keeper/events_test.go @@ -56,7 +56,11 @@ func TestEmitEventBallotDeleted(t *testing.T) { if attr.Key == "voters" { expectedString := "" for _, voter := range ballot.GenerateVoterList() { - st := fmt.Sprintf("{\"voter_address\":\"%s\",\"vote_type\":\"%s\"}", voter.VoterAddress, voter.VoteType) + st := fmt.Sprintf( + "{\"voter_address\":\"%s\",\"vote_type\":\"%s\"}", + voter.VoterAddress, + voter.VoteType, + ) expectedString += st expectedString += "," }