77import pytest
88import subprocess
99import logging
10+ import struct
1011from program_admin import ProgramAdmin
1112from program_admin .parsing import (
1213 parse_permissions_json ,
2021from solana .keypair import Keypair
2122from solders .system_program import ID as SYSTEM_PROGRAM_ID
2223from solana .rpc .async_api import AsyncClient
24+ from solana .rpc import commitment
2325from solana .transaction import AccountMeta , Transaction , TransactionInstruction
2426from anchorpy import Provider , Wallet
2527from construct import Bytes , Int32sl , Int32ul , Struct
2628from solana .publickey import PublicKey
2729from message_buffer_client_codegen .instructions import initialize , set_allowed_programs , create_buffer
30+ from message_buffer_client_codegen .accounts .message_buffer import MessageBuffer
2831from jsonrpc_websocket import Server
2932
3033LOGGER = logging .getLogger (__name__ )
8083asyncio .set_event_loop (asyncio .new_event_loop ())
8184
8285
86+ # Useful derivations of the constants above
87+ oracle_pubkey = PublicKey (ORACLE_PROGRAM )
88+ msg_buf_pubkey = PublicKey (MESSAGE_BUFFER_PROGRAM )
89+ oracle_auth_pda , _ = PublicKey .find_program_address (
90+ [b"upd_price_write" , bytes (msg_buf_pubkey )],
91+ oracle_pubkey
92+ )
93+
94+ def get_buffer_pubkey (base_account : PublicKey ) -> PublicKey :
95+ pubkey , _ = PublicKey .find_program_address (
96+ [bytes (oracle_auth_pda ), b"message" , bytes (base_account )],
97+ msg_buf_pubkey
98+ )
99+ return pubkey
100+
83101class PythAgentClient :
84102
85103 def __init__ (self , address : str ) -> None :
@@ -326,13 +344,6 @@ async def initialize_message_buffer_program(self, funding_keypair, sync_key_path
326344
327345 tx = Transaction ().add (init_ix )
328346
329- oracle_pubkey = PublicKey (ORACLE_PROGRAM )
330- msg_buf_pubkey = PublicKey (MESSAGE_BUFFER_PROGRAM )
331- oracle_auth_pda , _ = PublicKey .find_program_address (
332- [b"upd_price_write" , bytes (msg_buf_pubkey )],
333- oracle_pubkey
334- )
335-
336347 LOGGER .info (f"Oracle Auth PDA: { oracle_auth_pda } " )
337348
338349 set_allowed_ix = set_allowed_programs ({
@@ -350,10 +361,7 @@ async def initialize_message_buffer_program(self, funding_keypair, sync_key_path
350361 LOGGER .info (f"{ jump_symbol } price account: { address_string } " )
351362 address = PublicKey (address_string )
352363
353- message_buffer_pda , _ = PublicKey .find_program_address (
354- [bytes (oracle_auth_pda ), b"message" , bytes (address )],
355- msg_buf_pubkey
356- )
364+ message_buffer_pda = get_buffer_pubkey (address )
357365
358366 ix = create_buffer ({
359367 "allowed_program_auth" : oracle_auth_pda ,
@@ -466,6 +474,35 @@ async def test_update_price_simple(self, client: PythAgentClient):
466474 assert final_price_account ["conf" ] == 2
467475 assert final_price_account ["status" ] == "trading"
468476
477+ if USE_ACCUMULATOR :
478+ # Confirm that message buffer has been updated with the values from the BTC/USD price update
479+
480+ btc_usd_message_buffer_pubkey = get_buffer_pubkey (PublicKey (price_account ))
481+ sol_client = AsyncClient ("http://localhost:8899" , commitment = commitment .Confirmed )
482+ buffer = (await sol_client .get_account_info (btc_usd_message_buffer_pubkey )).value
483+
484+ assert buffer is not None
485+
486+ # MessageBuffer class only contains the header of the data
487+ # the rest of the data is not structured and is just a byte array
488+ # separated by end_offsets.
489+ message_buffer_header = MessageBuffer .decode (buffer .data )
490+ header_len = message_buffer_header .header_len
491+ first_message = buffer .data [header_len : header_len + message_buffer_header .end_offsets [0 ]]
492+
493+ # Confirm that the first message in the buffer is the expected one
494+ message_type = first_message [0 ]
495+ assert message_type == 0 # Type 0 is PriceFeed
496+
497+ price_id = first_message [1 :33 ]
498+ assert PublicKey (price_id ) == PublicKey (price_account )
499+
500+ # > means big endian, q means i64, Q means u64
501+ price , conf = struct .unpack_from (">qQ" , first_message , 33 )
502+
503+ assert price == 42
504+ assert conf == 2
505+
469506 @pytest .mark .asyncio
470507 async def test_update_price_simple_with_keypair_hotload (self , client_hotload : PythAgentClient ):
471508 # Hotload the keypair into running agent
0 commit comments