7
7
import pytest
8
8
import subprocess
9
9
import logging
10
+ import struct
10
11
from program_admin import ProgramAdmin
11
12
from program_admin .parsing import (
12
13
parse_permissions_json ,
20
21
from solana .keypair import Keypair
21
22
from solders .system_program import ID as SYSTEM_PROGRAM_ID
22
23
from solana .rpc .async_api import AsyncClient
24
+ from solana .rpc import commitment
23
25
from solana .transaction import AccountMeta , Transaction , TransactionInstruction
24
26
from anchorpy import Provider , Wallet
25
27
from construct import Bytes , Int32sl , Int32ul , Struct
26
28
from solana .publickey import PublicKey
27
29
from message_buffer_client_codegen .instructions import initialize , set_allowed_programs , create_buffer
30
+ from message_buffer_client_codegen .accounts .message_buffer import MessageBuffer
28
31
from jsonrpc_websocket import Server
29
32
30
33
LOGGER = logging .getLogger (__name__ )
80
83
asyncio .set_event_loop (asyncio .new_event_loop ())
81
84
82
85
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
+
83
101
class PythAgentClient :
84
102
85
103
def __init__ (self , address : str ) -> None :
@@ -326,13 +344,6 @@ async def initialize_message_buffer_program(self, funding_keypair, sync_key_path
326
344
327
345
tx = Transaction ().add (init_ix )
328
346
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
-
336
347
LOGGER .info (f"Oracle Auth PDA: { oracle_auth_pda } " )
337
348
338
349
set_allowed_ix = set_allowed_programs ({
@@ -350,10 +361,7 @@ async def initialize_message_buffer_program(self, funding_keypair, sync_key_path
350
361
LOGGER .info (f"{ jump_symbol } price account: { address_string } " )
351
362
address = PublicKey (address_string )
352
363
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 )
357
365
358
366
ix = create_buffer ({
359
367
"allowed_program_auth" : oracle_auth_pda ,
@@ -466,6 +474,35 @@ async def test_update_price_simple(self, client: PythAgentClient):
466
474
assert final_price_account ["conf" ] == 2
467
475
assert final_price_account ["status" ] == "trading"
468
476
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
+
469
506
@pytest .mark .asyncio
470
507
async def test_update_price_simple_with_keypair_hotload (self , client_hotload : PythAgentClient ):
471
508
# Hotload the keypair into running agent
0 commit comments