Skip to content

Commit 90c7934

Browse files
committed
Merge branch 'main' into testnet
2 parents 8525612 + b958865 commit 90c7934

File tree

10 files changed

+178
-23
lines changed

10 files changed

+178
-23
lines changed

.github/workflows/docker.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ jobs:
2020
- run: docker build -f docker/Dockerfile --build-arg SOLANA_VERSION=${{ env.SOLANA_VERSION }} --tag ${{ env.DOCKER_IMAGE }} .
2121
# publish to docker.io
2222
- run: echo "${{ secrets.DOCKER_IO_PASS }}" | docker login docker.io -u ${{ secrets.DOCKER_IO_USER }} --password-stdin
23+
if: startsWith( github.ref, 'refs/tags/' )
2324
- run: docker image tag ${DOCKER_IMAGE} docker.io/pythfoundation/pyth-client:${DOCKER_TAG}
25+
if: startsWith( github.ref, 'refs/tags/' )
2426
- run: docker image push docker.io/pythfoundation/pyth-client:${DOCKER_TAG}
2527
if: startsWith( github.ref, 'refs/tags/' )

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ target_link_libraries( pyth_tx ${PC_DEP} )
8181
#
8282

8383
install( TARGETS pc DESTINATION lib )
84-
install( TARGETS pyth pythd pyth_csv DESTINATION bin )
84+
install( TARGETS pyth pythd pyth_csv pyth_tx DESTINATION bin )
8585
install( FILES ${PC_HDR} DESTINATION include/pc )
8686
install( FILES program/src/oracle/oracle.h DESTINATION include/oracle )
8787

docker/Dockerfile

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ ARG SOLANA_VERSION
33
FROM solanalabs/solana:v${SOLANA_VERSION}
44

55
RUN apt-get update
6-
RUN apt-get install -y cmake curl g++ git libzstd1 libzstd-dev zlib1g zlib1g-dev
6+
RUN apt-get install -y cmake curl g++ git libzstd1 libzstd-dev sudo zlib1g zlib1g-dev
7+
8+
# Grant sudo access to pyth user
9+
RUN echo "pyth ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
710

811
RUN useradd -m pyth
912
USER pyth

pc/manager.cpp

+33-9
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ manager::manager()
6262
do_cap_( false ),
6363
do_tx_( true ),
6464
is_pub_( false ),
65-
cmt_( commitment::e_confirmed )
65+
cmt_( commitment::e_confirmed ),
66+
sreq_{ { commitment::e_processed } }
6667
{
6768
tconn_.set_sub( this );
6869
breq_->set_sub( this );
@@ -433,6 +434,15 @@ void manager::poll( bool do_wait )
433434
// get current time
434435
curr_ts_ = get_now();
435436

437+
// get current slot
438+
if ( curr_ts_ - slot_ts_ > 200 * PC_NSECS_IN_MSEC ) {
439+
if ( sreq_->get_is_recv() ) {
440+
if ( has_status( PC_PYTH_RPC_CONNECTED ) ) {
441+
clnt_.send( sreq_ );
442+
}
443+
}
444+
}
445+
436446
// try to (re)connect to tx proxy
437447
if ( do_tx_ && ( !tconn_.get_is_connect() || tconn_.get_is_err() ) ) {
438448
tconn_.reconnect();
@@ -489,8 +499,9 @@ void manager::reconnect_rpc()
489499
kidx_ = 0;
490500
ctimeout_ = PC_NSECS_IN_SEC;
491501
pub_ts_ = 0L;
492-
slot_cnt_ = 0UL;
493502
slot_ = 0L;
503+
slot_cnt_ = 0UL;
504+
slot_ts_ = 0L;
494505
num_sub_ = 0;
495506
clnt_.reset();
496507
for(;;) {
@@ -507,9 +518,15 @@ void manager::reconnect_rpc()
507518
clnt_.send( sreq_ );
508519

509520
// subscribe to program updates
510-
preq_->set_commitment( get_commitment() );
511-
preq_->set_program( get_program_pub_key() );
512-
clnt_.send( preq_ );
521+
pub_key *gpub = get_program_pub_key();
522+
if ( !gpub ) {
523+
set_err_msg( "missing or invalid program public key [" +
524+
get_program_pub_key_file() + "]" );
525+
} else {
526+
preq_->set_commitment( get_commitment() );
527+
preq_->set_program( gpub );
528+
clnt_.send( preq_ );
529+
}
513530

514531
// gather latest info on mapping accounts
515532
for( get_mapping *mptr: mvec_ ) {
@@ -634,23 +651,30 @@ void manager::schedule( price_sched *kptr )
634651
}
635652
}
636653

637-
void manager::on_response( rpc::slot_subscribe *res )
654+
void manager::on_response( rpc::get_slot *res )
638655
{
639656
// check error
640657
if ( PC_UNLIKELY( res->get_is_err() ) ) {
641-
set_err_msg( "failed to slot_subscribe ["
658+
set_err_msg( "failed to get slot ["
642659
+ res->get_err_msg() + "]" );
643660
return;
644661
}
645662

646663
// ignore slots that go back in time
647-
uint64_t slot = res->get_slot();
664+
uint64_t slot = res->get_current_slot();
648665
int64_t ts = res->get_recv_time();
649666
if ( slot <= slot_ ) {
650667
return;
651668
}
652669
slot_ = slot;
653-
PC_LOG_DBG( "receive slot" ).add( "slot", slot_ ).end();
670+
slot_ts_ = ts;
671+
672+
int64_t ack_ts = res->get_recv_time() - res->get_sent_time();
673+
674+
PC_LOG_DBG( "received get_slot" )
675+
.add( "slot", slot_ )
676+
.add( "rount_trip_time(ms)", 1e-6*ack_ts )
677+
.end();
654678

655679
// submit block hash every N slots
656680
if ( slot_cnt_++ % PC_BLOCKHASH_TIMEOUT == 0 ) {

pc/manager.hpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ namespace pc
4848
public net_accept,
4949
public tx_sub,
5050
public rpc_sub,
51-
public rpc_sub_i<rpc::slot_subscribe>,
51+
public rpc_sub_i<rpc::get_slot>,
5252
public rpc_sub_i<rpc::get_recent_block_hash>,
5353
public rpc_sub_i<rpc::program_subscribe>
5454
{
@@ -164,7 +164,7 @@ namespace pc
164164
bool get_is_tx_send() const;
165165

166166
// rpc callbacks
167-
void on_response( rpc::slot_subscribe * ) override;
167+
void on_response( rpc::get_slot * ) override;
168168
void on_response( rpc::get_recent_block_hash * ) override;
169169
void on_response( rpc::program_subscribe * ) override;
170170
void set_status( int );
@@ -228,6 +228,7 @@ namespace pc
228228
int64_t ctimeout_; // connection timeout
229229
uint64_t slot_; // current slot
230230
uint64_t slot_cnt_; // slot count
231+
int64_t slot_ts_; // current slot time
231232
int64_t curr_ts_; // current time
232233
int64_t pub_ts_; // start publish time
233234
int64_t pub_int_; // publish interval
@@ -241,7 +242,7 @@ namespace pc
241242
commitment cmt_; // account get/subscribe commitment
242243

243244
// requests
244-
rpc::slot_subscribe sreq_[1]; // slot subscription
245+
rpc::get_slot sreq_[1]; // slot subscription
245246
rpc::get_recent_block_hash breq_[1]; // block hash request
246247
rpc::program_subscribe preq_[1]; // program account subscription
247248
};

pc/request.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -2145,10 +2145,12 @@ void price::update_pub()
21452145
// update publishing index
21462146
pub_idx_ = (unsigned)-1;
21472147
pub_key *pkey = get_manager()->get_publish_pub_key();
2148-
for( unsigned i=0; i != pptr_->num_; ++i ) {
2149-
if ( pc_pub_key_equal( &pptr_->comp_[i].pub_, (pc_pub_key_t*)pkey ) ) {
2150-
pub_idx_ = i;
2151-
break;
2148+
if ( pkey ) {
2149+
for( unsigned i=0; i != pptr_->num_; ++i ) {
2150+
if ( pc_pub_key_equal( &pptr_->comp_[i].pub_, (pc_pub_key_t*)pkey ) ) {
2151+
pub_idx_ = i;
2152+
break;
2153+
}
21522154
}
21532155
}
21542156
}

pc/rpc_client.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,38 @@ void rpc::get_cluster_nodes::response( const jtree& jt )
637637
on_response( this );
638638
}
639639

640+
///////////////////////////////////////////////////////////////////////////
641+
// get_slot
642+
643+
rpc::get_slot::get_slot( commitment const cmt )
644+
: cmt_{ cmt }
645+
, cslot_( 0UL )
646+
{
647+
}
648+
649+
uint64_t rpc::get_slot::get_current_slot() const
650+
{
651+
return cslot_;
652+
}
653+
654+
void rpc::get_slot::request( json_wtr& msg )
655+
{
656+
msg.add_key( "method", "getSlot" );
657+
msg.add_key( "params", json_wtr::e_arr );
658+
msg.add_val( json_wtr::e_obj );
659+
msg.add_key( "commitment", commitment_to_str( cmt_ ) );
660+
msg.pop();
661+
msg.pop();
662+
}
663+
664+
void rpc::get_slot::response( const jtree& jt )
665+
{
666+
if ( on_error( jt, this ) ) return;
667+
uint32_t rtok = jt.find_val( 1, "result" );
668+
cslot_ = jt.get_uint( rtok );
669+
on_response( this );
670+
}
671+
640672
///////////////////////////////////////////////////////////////////////////
641673
// get_slot_leaders
642674

pc/rpc_client.hpp

+14-1
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,19 @@ namespace pc
366366
node_map_t nmap_;
367367
};
368368

369+
// get current slot
370+
class get_slot : public rpc_request
371+
{
372+
public:
373+
get_slot( commitment = e_finalized );
374+
uint64_t get_current_slot() const;
375+
void request( json_wtr& ) override;
376+
void response( const jtree& ) override;
377+
private:
378+
commitment const cmt_; // param
379+
uint64_t cslot_; // result
380+
};
381+
369382
// get id of leader node by slot
370383
class get_slot_leaders : public rpc_request
371384
{
@@ -376,7 +389,7 @@ namespace pc
376389
pub_key *get_leader( uint64_t );
377390
uint64_t get_last_slot() const;
378391
void request( json_wtr& ) override;
379-
void response( const jtree&p) override;
392+
void response( const jtree& ) override;
380393
private:
381394
typedef std::vector<pub_key> ldr_vec_t;
382395
uint64_t rslot_;

pcapps/pyth.cpp

+79-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ int usage()
5555
std::cerr << " get_block <slot_number> [options]" << std::endl;
5656
std::cerr << " get_product <prod_key> [options]" << std::endl;
5757
std::cerr << " get_product_list [options]" << std::endl;
58+
std::cerr << " get_all_products [options]" << std::endl;
5859
std::cerr << " get_pub_key <key_pair_file>" << std::endl;
5960
std::cerr << " version" << std::endl;
6061
std::cerr << std::endl;
@@ -74,6 +75,8 @@ int usage()
7475
std::cerr << " -j\n"
7576
<< " Output results in json format where applicable\n"
7677
<< std::endl;
78+
std::cerr << " -d" << std::endl;
79+
std::cerr << " Turn on debug logging\n" << std::endl;
7780
return 1;
7881
}
7982

@@ -311,12 +314,13 @@ int on_get_balance( int argc, char **argv )
311314
commitment cmt = commitment::e_confirmed;
312315
std::string rpc_host = get_rpc_host();
313316
std::string key_dir = get_key_store();
314-
while( (opt = ::getopt(argc,argv, "r:k:p:c:h" )) != -1 ) {
317+
while( (opt = ::getopt(argc,argv, "r:k:p:c:dh" )) != -1 ) {
315318
switch(opt) {
316319
case 'r': rpc_host = optarg; break;
317320
case 'k': key_dir = optarg; break;
318321
case 'p': knm = optarg; break;
319322
case 'c': cmt = str_to_commitment(optarg); break;
323+
case 'd': log::set_level( PC_LOG_DBG_LVL ); break;
320324
default: return usage();
321325
}
322326
}
@@ -1011,6 +1015,11 @@ int on_get_product_list( int argc, char **argv )
10111015
std::cerr << "pyth: " << mgr.get_err_msg() << std::endl;
10121016
return 1;
10131017
}
1018+
if ( !mgr.has_status( PC_PYTH_HAS_MAPPING ) ) {
1019+
std::cerr << "pyth: mapping not ready, check mapping key ["
1020+
<< mgr.get_mapping_pub_key_file() << "]" << std::endl;
1021+
return 1;
1022+
}
10141023
// list key/symbol pairs
10151024
if ( !do_json ) {
10161025
std::string astr;
@@ -1203,6 +1212,11 @@ int on_get_product( int argc, char **argv )
12031212
std::cerr << "pyth: " << mgr.get_err_msg() << std::endl;
12041213
return 1;
12051214
}
1215+
if ( !mgr.has_status( PC_PYTH_HAS_MAPPING ) ) {
1216+
std::cerr << "pyth: mapping not ready, check mapping key ["
1217+
<< mgr.get_mapping_pub_key_file() << "]" << std::endl;
1218+
return 1;
1219+
}
12061220
// get product and serialize to stdout
12071221
product *prod = mgr.get_product( pub );
12081222
if ( !prod ) {
@@ -1217,6 +1231,68 @@ int on_get_product( int argc, char **argv )
12171231
return 0;
12181232
}
12191233

1234+
int on_get_all_products( int argc, char **argv )
1235+
{
1236+
int opt = 0;
1237+
bool do_json = false;
1238+
commitment cmt = commitment::e_confirmed;
1239+
std::string rpc_host = get_rpc_host();
1240+
std::string key_dir = get_key_store();
1241+
while( (opt = ::getopt(argc,argv, "r:k:c:djh" )) != -1 ) {
1242+
switch(opt) {
1243+
case 'r': rpc_host = optarg; break;
1244+
case 'k': key_dir = optarg; break;
1245+
case 'd': log::set_level( PC_LOG_DBG_LVL ); break;
1246+
case 'j': do_json = true; break;
1247+
case 'c': cmt = str_to_commitment(optarg); break;
1248+
default: return usage();
1249+
}
1250+
}
1251+
if ( cmt == commitment::e_unknown ) {
1252+
std::cerr << "pyth: unknown commitment level" << std::endl;
1253+
return usage();
1254+
}
1255+
1256+
// initialize connection to block-chain
1257+
manager mgr;
1258+
mgr.set_rpc_host( rpc_host );
1259+
mgr.set_dir( key_dir );
1260+
mgr.set_do_tx( false );
1261+
mgr.set_commitment( cmt );
1262+
if ( !mgr.init() || !mgr.bootstrap() ) {
1263+
std::cerr << "pyth: " << mgr.get_err_msg() << std::endl;
1264+
return 1;
1265+
}
1266+
if ( !mgr.has_status( PC_PYTH_HAS_MAPPING ) ) {
1267+
std::cerr << "pyth: mapping not ready, check mapping key ["
1268+
<< mgr.get_mapping_pub_key_file() << "]" << std::endl;
1269+
return 1;
1270+
}
1271+
1272+
// get all products and serialize to stdout
1273+
if ( !do_json ) {
1274+
for (unsigned i=0; i != mgr.get_num_product(); ++i ) {
1275+
product *prod = mgr.get_product(i);
1276+
print_product( prod );
1277+
std::cout << std::endl;
1278+
}
1279+
} else {
1280+
std::cout << "[";
1281+
bool first = true;
1282+
for (unsigned i=0; i != mgr.get_num_product(); ++i ) {
1283+
product *prod = mgr.get_product(i);
1284+
if ( !first ) {
1285+
std::cout << ",";
1286+
}
1287+
print_product_json( prod );
1288+
first = false;
1289+
}
1290+
std::cout << "]";
1291+
}
1292+
1293+
return 0;
1294+
}
1295+
12201296
class get_block_print : public get_block
12211297
{
12221298
public:
@@ -1434,6 +1510,8 @@ int main(int argc, char **argv)
14341510
rc = on_get_product( argc, argv );
14351511
} else if ( cmd == "get_product_list" ) {
14361512
rc = on_get_product_list( argc, argv );
1513+
} else if ( cmd == "get_all_products" ) {
1514+
rc = on_get_all_products( argc, argv );
14371515
} else if ( cmd == "get_block" ) {
14381516
rc = on_get_block( argc, argv );
14391517
} else if ( cmd == "version" ) {

pctest/slots_info.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class manager_slot : public manager,
1313
{
1414
public:
1515
manager_slot();
16-
void on_response( rpc::slot_subscribe * ) override;
16+
void on_response( rpc::get_slot * ) override;
1717
void on_response( rpc::get_slot_leaders * ) override;
1818
private:
1919
rpc::get_slot_leaders ldr_[1];
@@ -27,10 +27,10 @@ manager_slot::manager_slot()
2727
ldr_->set_limit( PC_LEADER_MAX );
2828
}
2929

30-
void manager_slot::on_response( rpc::slot_subscribe *res )
30+
void manager_slot::on_response( rpc::get_slot *res )
3131
{
3232
manager::on_response( res );
33-
uint64_t slot = get_slot();
33+
uint64_t const slot = get_slot();
3434
if ( slot != last_ ) {
3535
// request next slot leader schedule
3636
if ( PC_UNLIKELY( ldr_->get_is_recv() &&

0 commit comments

Comments
 (0)