Skip to content

Commit fe4e4a1

Browse files
committed
Merge branch 'main' into reisen/pyth-oracle-build
2 parents f09d42d + 590f9d0 commit fe4e4a1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+152
-112
lines changed

CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,16 @@ target_link_libraries( test_net ${PC_DEP} )
108108
# add_executable( test_publish_websocket pctest/test_publish_websocket.cpp )
109109
# target_link_libraries( test_publish_websocket Qt5::Core Qt5::Network Qt5::WebSockets /usr/local/lib/libjcon.so)
110110

111-
add_executable( test_qset pctest/test_qset.cpp )
112-
target_link_libraries( test_qset ${PC_DEP} )
111+
add_executable( test_pd pctest/test_pd.cpp )
112+
target_link_libraries( test_pd ${PC_DEP} )
113113
add_executable( test_twap pctest/test_twap.cpp )
114114
target_link_libraries( test_twap ${PC_DEP} )
115115
add_executable( leader_stats pctest/leader_stats.cpp )
116116
target_link_libraries( leader_stats ${PC_DEP} )
117117

118118
add_test( test_unit test_unit )
119119
add_test( test_net test_net )
120+
add_test( test_pd test_pd )
120121

121122

122123
#

README.md

Lines changed: 24 additions & 0 deletions

pctest/test_qset.cpp renamed to pctest/test_pd.cpp

Lines changed: 1 addition & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -99,91 +99,10 @@ void test_pd()
9999
PC_TEST_CHECK( pd_gt( n2, n1, dec_fact ) );
100100
}
101101

102-
void test_qs()
102+
int main(int,char**)
103103
{
104104
PC_TEST_START
105105
test_pd();
106106
PC_TEST_END
107-
}
108-
109-
int main( int argc,char** argv )
110-
{
111-
if ( argc < 2 ) {
112-
return usage();
113-
}
114-
// unit test piece first
115-
test_qs();
116-
117-
// construct quotes
118-
mem_map mf;
119-
std::string file = argv[1];
120-
mf.set_file(file );
121-
if ( !mf.init() ) {
122-
std::cerr << "test_qset: failed to read file[" << file << "]"
123-
<< std::endl;
124-
return 1;
125-
}
126-
jtree pt;
127-
pt.parse( mf.data(), mf.size() );
128-
if ( !pt.is_valid() ) {
129-
std::cerr << "test_qset: failed to parse file[" << file << "]"
130-
<< std::endl;
131-
return 1;
132-
}
133-
pc_price_t px[1];
134-
__builtin_memset( px, 0, sizeof( pc_price_t ) );
135-
uint64_t slot = 1000UL;
136-
px->last_slot_ = slot;
137-
px->agg_.pub_slot_ = slot;
138-
px->expo_ = pt.get_int( pt.find_val( 1, "exponent" ) );
139-
px->num_ = 0;
140-
uint32_t qt =pt.find_val( 1, "quotes" );
141-
for( uint32_t it = pt.get_first( qt ); it; it = pt.get_next( it ) ) {
142-
pc_price_comp_t *ptr = &px->comp_[px->num_++];
143-
ptr->latest_.status_ = pt.get_int( pt.find_val( it, "status" ) );
144-
ptr->latest_.price_ = pt.get_int( pt.find_val( it, "price" ) );
145-
int64_t conf = pt.get_int( pt.find_val( it, "conf" ) );
146-
assert( conf >= 0 );
147-
ptr->latest_.conf_ = static_cast< uint64_t >( conf );
148-
int64_t pub_slot = pt.get_int( pt.find_val( it, "slot_diff" ) );
149-
ptr->latest_.pub_slot_ =
150-
static_cast< uint64_t >( static_cast< int64_t >( slot ) + pub_slot );
151-
}
152-
upd_aggregate( px, slot+1, 1234 );
153-
154-
char const* status = "invalid value";
155-
switch ( px->agg_.status_ ) {
156-
case PC_STATUS_UNKNOWN:
157-
status = "unknown";
158-
break;
159-
case PC_STATUS_TRADING:
160-
status = "trading";
161-
break;
162-
case PC_STATUS_HALTED:
163-
status = "halted";
164-
break;
165-
case PC_STATUS_AUCTION:
166-
status = "auction";
167-
break;
168-
}
169-
170-
// generate result
171-
json_wtr jw;
172-
jw.add_val( json_wtr::e_obj );
173-
jw.add_key( "exponent", (int64_t)px->expo_ );
174-
jw.add_key( "price", px->agg_.price_ );
175-
jw.add_key( "conf", px->agg_.conf_ );
176-
jw.add_key( "status", status );
177-
jw.pop();
178-
net_buf *hd, *tl;
179-
jw.detach( hd, tl );
180-
while( hd ) {
181-
net_buf *nxt = hd->next_;
182-
std::cout.write( hd->buf_, hd->size_ );
183-
hd->dealloc();
184-
hd = nxt;
185-
}
186-
std::cout << std::endl;
187-
188107
return 0;
189108
}

program/c/makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22
# default to ./target
33
OUT_DIR := $(if $(OUT_DIR),$(OUT_DIR),./target)
44
SOLANA := $(shell dirname $(shell which cargo-build-bpf))
5-
include $(SOLANA)/sdk/bpf/c/bpf.mk
5+
6+
ifneq ("$(wildcard $(SOLANA)/sdk/bpf/c/bpf.mk)","")
7+
$(info using Solana BPF SDK)
8+
include $(SOLANA)/sdk/bpf/c/bpf.mk
9+
else
10+
$(info using Solana SBF SDK)
11+
include $(SOLANA)/sdk/sbf/c/sbf.mk
12+
endif
613

714

815
# Bundle C code compiled to bpf for use by rust

program/rust/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ hex = "0.3.1"
2323
quickcheck = "1"
2424
quickcheck_macros = "1"
2525
bincode = "1.3.3"
26+
serde = { version = "1.0", features = ["derive"] }
27+
serde_json = "1.0"
28+
test-generator = "0.3.1"
2629

2730
[features]
2831
debug = []

program/rust/build.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ fn get_solana_inc_path() -> PathBuf {
5757
let mut path = PathBuf::new();
5858
path.push(std::str::from_utf8(&which_stdout).unwrap());
5959
path.pop(); //
60-
path.push("sdk/bpf/c/inc/");
61-
path
60+
let mut bpf_path = path.clone();
61+
// Older solana version have the SDK in the bpf/ folder, while newer version have
62+
// it in the sbf/ folder
63+
bpf_path.push("sdk/bpf/c/inc/");
64+
if bpf_path.exists() {
65+
bpf_path
66+
} else {
67+
path.push("sdk/sbf/c/inc/");
68+
path
69+
}
6270
}

program/rust/src/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod test_add_mapping;
33
mod test_add_price;
44
mod test_add_product;
55
mod test_add_publisher;
6+
mod test_aggregation;
67
mod test_del_price;
78
mod test_del_product;
89
mod test_del_publisher;
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use {
2+
crate::{
3+
accounts::PriceAccount,
4+
processor::c_upd_aggregate,
5+
},
6+
bytemuck::Zeroable,
7+
serde::{
8+
Deserialize,
9+
Serialize,
10+
},
11+
std::fs::File,
12+
};
13+
extern crate test_generator;
14+
15+
use test_generator::test_resources;
16+
17+
#[test_resources("program/rust/test_data/aggregation/*.json")]
18+
fn test_quote_set(input_path_raw: &str) {
19+
// For some reason these tests have a different working directory than the macro.
20+
let input_path = input_path_raw.replace("program/rust/", "");
21+
let result_path = input_path.replace(".json", ".result");
22+
23+
let file = File::open(input_path).expect("Test file not found");
24+
let quote_set: QuoteSet = serde_json::from_reader(&file).expect("Unable to parse JSON");
25+
26+
let result_file = File::open(result_path).expect("Test file not found");
27+
let expected_result: QuoteSetResult =
28+
serde_json::from_reader(&result_file).expect("Unable to parse JSON");
29+
30+
let current_slot = 1000; // arbitrary
31+
let current_timestamp = 1234; // also arbitrary
32+
let mut price_account: PriceAccount = PriceAccount::zeroed();
33+
34+
price_account.last_slot_ = current_slot;
35+
price_account.agg_.pub_slot_ = current_slot;
36+
price_account.exponent = quote_set.exponent;
37+
price_account.num_ = quote_set.quotes.len() as u32;
38+
for quote_idx in 0..quote_set.quotes.len() {
39+
let mut current_component = &mut price_account.comp_[quote_idx];
40+
let quote = &quote_set.quotes[quote_idx];
41+
current_component.latest_.status_ = quote.status;
42+
current_component.latest_.price_ = quote.price;
43+
current_component.latest_.conf_ = quote.conf;
44+
let slot_diff = quote.slot_diff.unwrap_or(0);
45+
assert!(slot_diff > -(current_slot as i64));
46+
current_component.latest_.pub_slot_ = ((current_slot as i64) + slot_diff) as u64;
47+
}
48+
49+
unsafe {
50+
c_upd_aggregate(
51+
(&mut price_account as *mut PriceAccount) as *mut u8,
52+
current_slot + 1,
53+
current_timestamp,
54+
);
55+
}
56+
57+
// For some idiotic reason the status in the input is a number and the output is a string.
58+
let result_status: String = match price_account.agg_.status_ {
59+
0 => "unknown",
60+
1 => "trading",
61+
2 => "halted",
62+
3 => "auction",
63+
4 => "ignored",
64+
_ => "invalid status",
65+
}
66+
.into();
67+
68+
let actual_result = QuoteSetResult {
69+
exponent: price_account.exponent,
70+
price: price_account.agg_.price_,
71+
conf: price_account.agg_.conf_,
72+
status: result_status,
73+
};
74+
75+
assert_eq!(expected_result, actual_result);
76+
}
77+
78+
#[derive(Serialize, Deserialize, Debug)]
79+
struct Quote {
80+
price: i64,
81+
conf: u64,
82+
status: u32,
83+
slot_diff: Option<i64>,
84+
}
85+
86+
#[derive(Serialize, Deserialize, Debug)]
87+
struct QuoteSet {
88+
exponent: i32,
89+
quotes: Vec<Quote>,
90+
}
91+
92+
#[derive(Serialize, Deserialize, Debug, PartialEq)]
93+
struct QuoteSetResult {
94+
exponent: i32,
95+
price: i64,
96+
conf: u64,
97+
status: String,
98+
}

pyth/tests/qset/1.json renamed to program/rust/test_data/aggregation/1.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
{
55
"price": 10000,
66
"conf": 1000,
7-
"status": 1,
7+
"status": 1
88
},
99
{
1010
"price": 10000,
1111
"conf": 1000,
12-
"status": 1,
12+
"status": 1
1313
},
1414
{
1515
"price": 10000,
1616
"conf": 1000,
17-
"status": 1,
17+
"status": 1
1818
}
1919
]
2020
}

0 commit comments

Comments
 (0)