diff --git a/.changeset/better-masks-tease.md b/.changeset/better-masks-tease.md new file mode 100644 index 000000000..345ff9ff5 --- /dev/null +++ b/.changeset/better-masks-tease.md @@ -0,0 +1,5 @@ +--- +'@solana/sysvars': patch +--- + +The `SysvarEpochRewards` encoder/decoder no longer produces malformed data diff --git a/packages/sysvars/src/__tests__/epoch-rewards-test.ts b/packages/sysvars/src/__tests__/epoch-rewards-test.ts index 1253e4e38..b5e89fd62 100644 --- a/packages/sysvars/src/__tests__/epoch-rewards-test.ts +++ b/packages/sysvars/src/__tests__/epoch-rewards-test.ts @@ -4,14 +4,29 @@ describe('epoch rewards', () => { it('decode', () => { // prettier-ignore const epochRewardsState = new Uint8Array([ - 0, 45, 49, 1, 0, 0, 0, 0, // distributionCompleteBlockHeight - 134, 74, 2, 0, 0, 0, 0, 0, // distributedRewards - 0, 132, 215, 23, 0, 0, 0, 0, // totalRewards + // distributionStartingBlockHeight + 0xab, 0xa8, 0x87, 0x12, 0x00, 0x00, 0x00, 0x00, + // numPartitions + 0x3a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // parentBlockhash + 0x67, 0x8b, 0xd4, 0xe4, 0xc8, 0x5c, 0x10, 0x87, 0xa8, 0x0a, 0xfb, 0x2f, 0x0d, 0xbb, 0x13, 0x27, 0x16, 0x11, 0x3a, 0xc7, 0xc7, 0xb0, 0xc7, 0xe4, 0x99, 0x51, 0x4d, 0x42, 0xdb, 0x43, 0xd7, 0x1c, + // totalPoints + 0x10, 0xbe, 0x90, 0x99, 0x7a, 0x16, 0x9e, 0xa5, 0xc2, 0x2d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + // totalRewards + 0x00, 0xb3, 0x04, 0x4e, 0xd0, 0x20, 0x89, 0x00, + // distributedRewards + 0x00, 0xb8, 0xea, 0x37, 0xd0, 0x20, 0x89, 0x00, + // active + 0x00, ]); - expect(getSysvarEpochRewardsCodec().decode(epochRewardsState)).toMatchObject({ - distributedRewards: 150_150n, - distributionCompleteBlockHeight: 20_000_000n, - totalRewards: 400_000_000n, + expect(getSysvarEpochRewardsCodec().decode(epochRewardsState)).toStrictEqual({ + active: false, + distributedRewards: 38598150472775680n, + distributionStartingBlockHeight: 310880427n, + numPartitions: 314n, + parentBlockhash: '7yCfKTaamnrmkAfefSgsonQ6rtwCfVaxQJircWb9K4Qj', + totalPoints: 2633948733309470433656336n, + totalRewards: 38598150843577088n, }); }); // TODO: This account does not seem to exist on-chain yet. diff --git a/packages/sysvars/src/epoch-rewards.ts b/packages/sysvars/src/epoch-rewards.ts index c43d5324a..d5743b5d2 100644 --- a/packages/sysvars/src/epoch-rewards.ts +++ b/packages/sysvars/src/epoch-rewards.ts @@ -4,17 +4,29 @@ import { type FixedSizeCodec, type FixedSizeDecoder, type FixedSizeEncoder, + getBooleanDecoder, + getBooleanEncoder, getStructDecoder, getStructEncoder, getU64Decoder, getU64Encoder, + getU128Decoder, + getU128Encoder, } from '@solana/codecs'; import type { GetAccountInfoApi } from '@solana/rpc-api'; import type { Rpc } from '@solana/rpc-spec'; +import { + Blockhash, + getBlockhashDecoder, + getBlockhashEncoder, + getDefaultLamportsDecoder, + getDefaultLamportsEncoder, + Lamports, +} from '@solana/rpc-types'; import { fetchEncodedSysvarAccount, SYSVAR_EPOCH_REWARDS_ADDRESS } from './sysvar'; -type SysvarEpochRewardsSize = 24; +type SysvarEpochRewardsSize = 81; /** * The `EpochRewards` sysvar. @@ -30,24 +42,36 @@ type SysvarEpochRewardsSize = 24; * See https://github.com/anza-xyz/agave/blob/e0203f22dc83cb792fa97f91dbe6e924cbd08af1/docs/src/runtime/sysvars.md?plain=1#L155-L168 */ export type SysvarEpochRewards = Readonly<{ - distributedRewards: bigint; - distributionCompleteBlockHeight: bigint; - totalRewards: bigint; + active: boolean; + distributedRewards: Lamports; + distributionStartingBlockHeight: bigint; + numPartitions: bigint; + parentBlockhash: Blockhash; + totalPoints: bigint; + totalRewards: Lamports; }>; export function getSysvarEpochRewardsEncoder(): FixedSizeEncoder { return getStructEncoder([ - ['distributionCompleteBlockHeight', getU64Encoder()], - ['distributedRewards', getU64Encoder()], - ['totalRewards', getU64Encoder()], + ['distributionStartingBlockHeight', getU64Encoder()], + ['numPartitions', getU64Encoder()], + ['parentBlockhash', getBlockhashEncoder()], + ['totalPoints', getU128Encoder()], + ['totalRewards', getDefaultLamportsEncoder()], + ['distributedRewards', getDefaultLamportsEncoder()], + ['active', getBooleanEncoder()], ]) as FixedSizeEncoder; } export function getSysvarEpochRewardsDecoder(): FixedSizeDecoder { return getStructDecoder([ - ['distributionCompleteBlockHeight', getU64Decoder()], - ['distributedRewards', getU64Decoder()], - ['totalRewards', getU64Decoder()], + ['distributionStartingBlockHeight', getU64Decoder()], + ['numPartitions', getU64Decoder()], + ['parentBlockhash', getBlockhashDecoder()], + ['totalPoints', getU128Decoder()], + ['totalRewards', getDefaultLamportsDecoder()], + ['distributedRewards', getDefaultLamportsDecoder()], + ['active', getBooleanDecoder()], ]) as FixedSizeDecoder; }