mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-23 17:28:23 +00:00
fix: rewards message test flakiness (#377)
## Summary This PR removes sources of flakiness in the rewards message E2E test by: 1. Selecting a validator whose Ethereum key is not shared with the relayers 2. Using specific block numbers for balance reads to avoid stale RPC data ## Changes - Select a non-relayer validator from rewardPoints.individual when claiming rewards - Remove the conditional updateSolochainAddressForValidator block (mapping is set during registration) - Read balances at specific block numbers to ensure deterministic comparisons --------- Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
This commit is contained in:
parent
ae03649a4f
commit
72c092acfa
1 changed files with 36 additions and 33 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { beforeAll, describe, expect, it } from "bun:test";
|
||||
import { CROSS_CHAIN_TIMEOUTS, logger } from "utils";
|
||||
import { ANVIL_FUNDED_ACCOUNTS, CROSS_CHAIN_TIMEOUTS, logger } from "utils";
|
||||
import { type Address, decodeEventLog, type Hex, isAddressEqual, padHex } from "viem";
|
||||
import validatorSet from "../configs/validator-set.json";
|
||||
import { BaseTestSuite } from "../framework";
|
||||
|
|
@ -135,7 +135,22 @@ describe("Rewards Message Flow", () => {
|
|||
expect(rewardPoints).toBeDefined();
|
||||
expect(rewardPoints.total).toBeGreaterThan(0);
|
||||
|
||||
const [validatorAccount, points] = rewardPoints.individual[0];
|
||||
const relayerEthAccount = ANVIL_FUNDED_ACCOUNTS[1].publicKey.toLowerCase();
|
||||
const pick = rewardPoints.individual.find(([account]: [any, any]) => {
|
||||
const v = validatorSet.validators.find(
|
||||
(cfg) => cfg.solochainAddress.toLowerCase() === String(account).toLowerCase()
|
||||
);
|
||||
return v && v.publicKey.toLowerCase() !== relayerEthAccount;
|
||||
});
|
||||
const [validatorAccount, points] = (pick ?? rewardPoints.individual[0]) as [any, any];
|
||||
const match = validatorSet.validators.find(
|
||||
(v) => v.solochainAddress.toLowerCase() === String(validatorAccount).toLowerCase()
|
||||
);
|
||||
if (!match) {
|
||||
throw new Error(
|
||||
`Validator config not found for solochain address ${String(validatorAccount)}`
|
||||
);
|
||||
}
|
||||
|
||||
// Generate merkle proof via runtime API
|
||||
const merkleProof = await dhApi.apis.ExternalValidatorsRewardsApi.generate_rewards_merkle_proof(
|
||||
|
|
@ -146,33 +161,9 @@ describe("Rewards Message Flow", () => {
|
|||
|
||||
// Get validator credentials and create operator wallet
|
||||
const factory = suite.getConnectorFactory();
|
||||
const match = validatorSet.validators.find(
|
||||
(v) => v.solochainAddress.toLowerCase() === String(validatorAccount).toLowerCase()
|
||||
);
|
||||
const operatorWallet = factory.createWalletClient(match!.privateKey as `0x${string}`);
|
||||
const resolvedOperator: Address = operatorWallet.account.address;
|
||||
|
||||
// Ensure the ServiceManager maps the operator ETH address to the solochain address
|
||||
const expectedSolochain = String(validatorAccount) as Address;
|
||||
const mappedSolochain = (await publicClient.readContract({
|
||||
address: serviceManager.address as Address,
|
||||
abi: serviceManager.abi,
|
||||
functionName: "validatorEthAddressToSolochainAddress",
|
||||
args: [resolvedOperator]
|
||||
})) as Address;
|
||||
|
||||
if (mappedSolochain.toLowerCase() !== expectedSolochain.toLowerCase()) {
|
||||
const updateTx = await operatorWallet.writeContract({
|
||||
address: serviceManager.address as Address,
|
||||
abi: serviceManager.abi,
|
||||
functionName: "updateSolochainAddressForValidator",
|
||||
args: [expectedSolochain],
|
||||
chain: null
|
||||
});
|
||||
const updateReceipt = await publicClient.waitForTransactionReceipt({ hash: updateTx });
|
||||
expect(updateReceipt.status).toBe("success");
|
||||
}
|
||||
|
||||
// Ensure claim not already recorded
|
||||
const claimedBefore = (await publicClient.readContract({
|
||||
address: rewardsRegistry.address,
|
||||
|
|
@ -182,10 +173,17 @@ describe("Rewards Message Flow", () => {
|
|||
})) as boolean;
|
||||
expect(claimedBefore).toBe(false);
|
||||
|
||||
// Record balances for validation
|
||||
const operatorBalanceBefore = await publicClient.getBalance({ address: resolvedOperator });
|
||||
// Record balances at a specific block to avoid stale RPC reads
|
||||
const balanceBlockNumber = Number(await publicClient.getBlockNumber());
|
||||
const operatorBalanceBefore = await publicClient.getBalance({
|
||||
address: resolvedOperator,
|
||||
blockNumber: balanceBlockNumber
|
||||
});
|
||||
const registryBalanceBefore = BigInt(
|
||||
await publicClient.getBalance({ address: rewardsRegistry.address as Address })
|
||||
await publicClient.getBalance({
|
||||
address: rewardsRegistry.address as Address,
|
||||
blockNumber: balanceBlockNumber
|
||||
})
|
||||
);
|
||||
|
||||
// Submit claim transaction
|
||||
|
|
@ -238,14 +236,19 @@ describe("Rewards Message Flow", () => {
|
|||
expect(claimedAfter).toBe(true);
|
||||
|
||||
// Validate RewardsRegistry balance decrease matches claimed rewards
|
||||
const registryBalanceAfter = BigInt(
|
||||
await publicClient.getBalance({ address: rewardsRegistry.address as Address })
|
||||
);
|
||||
const claimBlockNumber = Number(claimReceipt.blockNumber);
|
||||
const registryBalanceAfter = await publicClient.getBalance({
|
||||
address: rewardsRegistry.address as Address,
|
||||
blockNumber: claimBlockNumber
|
||||
});
|
||||
expect(registryBalanceBefore - registryBalanceAfter).toEqual(claimArgs.rewardsAmount);
|
||||
expect(claimArgs.rewardsAmount).toEqual(BigInt(points));
|
||||
|
||||
// Validate operator received rewards (accounting for gas)
|
||||
const operatorBalanceAfter = await publicClient.getBalance({ address: resolvedOperator });
|
||||
const operatorBalanceAfter = await publicClient.getBalance({
|
||||
address: resolvedOperator,
|
||||
blockNumber: claimBlockNumber
|
||||
});
|
||||
const gasCost = BigInt(claimReceipt.gasUsed) * BigInt(claimReceipt.effectiveGasPrice);
|
||||
const netBalanceChange = BigInt(operatorBalanceAfter) - BigInt(operatorBalanceBefore);
|
||||
// Operator balance should have changed by: rewards - gasCost
|
||||
|
|
|
|||
Loading…
Reference in a new issue