Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 41 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
# pyth-client
client API for on-chain pyth programs

Pyth oracle program and off-chain client API.

## Oracle Program

The Pyth oracle program lives in the `program/` directory.
It consists of both C and Rust code, but everything can be built and tested using `cargo`.

### Build Instructions

First, make sure you have the [solana tool suite](https://docs.solana.com/cli/install-solana-cli-tools#use-solanas-install-tool)
installed on your machine. (The build depends on some C makefiles that are in the tool suite.)

Then, simply run `cargo build` to compile the oracle program as a native binary, or `cargo build-bpf` to build a BPF binary
that can be uploaded to the blockchain. This step will produce a program binary `target/deploy/pyth_oracle.so`.

### Testing

Simply run `cargo test`. This command will run several sets of tests:

- Unit tests of individual functions
- Simulated transaction tests against the BPF binary running on a solana simulator
- Exhaustive / randomized test batteries for core oracle functionality

Rust tests live in the `tests/` module of the rust code, and C tests are named something like `test_*.c`.
The C tests are linked into the rust binary so they run as part of `cargo test` as well (see `tests/test_c_code.rs`).

You can also run `cargo test-bpf`, which runs the same tests as `cargo test`, though it's slightly slower and the UX is worse.

### pre-commit hooks
pre-commit is a tool that checks and fixes simple issues (formatting, ...) before each commit. You can install it by following [their website](https://pre-commit.com/). In order to enable checks for this repo run `pre-commit install` from command-line in the root of this repo.

The checks are also performed in the CI to ensure the code follows consistent formatting. Formatting is only currently enforced in the `program/` directory.
You might also need to install the nightly toolchain to run the formatting by running `rustup toolchain install nightly`.

## pythd (off-chain client API)

> :warning: pythd is deprecated and has been replaced by [pyth-agent](https://github.com/pyth-network/pyth-agent).
> This new client is backward compatible with pythd, but more stable and configurable.

`pythd` provides exposes a web API for interacting with the on-chain oracle program.

### Build Instructions

Expand Down Expand Up @@ -44,30 +84,6 @@ This command runs a recent pyth-client docker image that already has the necessa
Therefore, once the container is running, all you have to do is run `cd pyth-client && ./scripts/build.sh`.
Note that updates to the `pyth-client` directory made inside the docker container will be persisted to the host filesystem (which is probably desirable).

### Local development

First, make sure you're building on the x86_64 architecture.
On a mac, this command will switch your shell to x86_64:

`env /usr/bin/arch -x86_64 /bin/bash --login`

then in the `program/c` directory, run:

```
make
make cpyth-bpf
make cpyth-native
```

then in the `program/rust` directory, run:

```
cargo build-bpf
cargo test
```

Note that the tests depend on the bpf build!

### Fuzzing

Build a docker image for running fuzz tests:
Expand Down Expand Up @@ -130,8 +146,3 @@ root@pyth-dev# usermod -u 1002 -g 1004 -s /bin/bash pyth

Finally, in docker extension inside VS Code click right and choose "Attach VS Code". If you're using a remote host in VS Code make sure to let this connection be open.

### pre-commit hooks
pre-commit is a tool that checks and fixes simple issues (formatting, ...) before each commit. You can install it by following [their website](https://pre-commit.com/). In order to enable checks for this repo run `pre-commit install` from command-line in the root of this repo.

The checks are also performed in the CI to ensure the code follows consistent formatting. Formatting is only currently enforced in the `program/` directory.
You might also need to install the nightly toolchain to run the formatting by running `rustup toolchain install nightly`.
2 changes: 0 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ RUN ./pyth-client/scripts/patch-solana.sh
# Build and test the oracle program.
RUN cd pyth-client && ./scripts/build-bpf.sh .
RUN cd pyth-client && ./scripts/check-size.sh
# Run aggregation logic tests
RUN cd pyth-client && ./scripts/run-aggregation-tests.sh
Copy link
Contributor Author

@jayantk jayantk Apr 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that build-bpf.sh above runs cargo test-bpf, which now runs all of these tests.

RUN cd pyth-client/pyth && poetry install && poetry run python -m pytest

ENTRYPOINT []
Expand Down
17 changes: 16 additions & 1 deletion program/c/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ endif
# The all target is defined by the solana makefile included above and generates the needed .o file.
.PHONY: cpyth-bpf
cpyth-bpf: all
bash -c "ar rcs $(OUT_DIR)/libcpyth-bpf.a $(OUT_DIR)/**/*.o"
bash -c "ar rcs $(OUT_DIR)/libcpyth-bpf.a $(OUT_DIR)/oracle/*.o"


# 2-Stage Contract Build
Expand All @@ -27,3 +27,18 @@ cpyth-bpf: all
cpyth-native:
gcc -c ./src/oracle/native/upd_aggregate.c -o $(OUT_DIR)/cpyth-native.o -fPIC
ar rcs $(OUT_DIR)/libcpyth-native.a $(OUT_DIR)/cpyth-native.o


# Note: there's probably a smart way to do this with wildcards but I (jayant) can't figure it out
.PHONY: test
test:
mkdir -p $(OUT_DIR)/test/
gcc -c ./src/oracle/model/test_price_model.c -o $(OUT_DIR)/test/test_price_model.o -fPIC
gcc -c ./src/oracle/sort/test_sort_stable.c -o $(OUT_DIR)/test/test_sort_stable.o -fPIC
gcc -c ./src/oracle/util/test_align.c -o $(OUT_DIR)/test/test_align.o -fPIC
gcc -c ./src/oracle/util/test_avg.c -o $(OUT_DIR)/test/test_avg.o -fPIC
gcc -c ./src/oracle/util/test_hash.c -o $(OUT_DIR)/test/test_hash.o -fPIC
gcc -c ./src/oracle/util/test_prng.c -o $(OUT_DIR)/test/test_prng.o -fPIC
gcc -c ./src/oracle/util/test_round.c -o $(OUT_DIR)/test/test_round.o -fPIC
gcc -c ./src/oracle/util/test_sar.c -o $(OUT_DIR)/test/test_sar.o -fPIC
ar rcs $(OUT_DIR)/libcpyth-test.a $(OUT_DIR)/test/*.o
2 changes: 0 additions & 2 deletions program/c/src/oracle/model/clean

This file was deleted.

14 changes: 0 additions & 14 deletions program/c/src/oracle/model/run_tests

This file was deleted.

9 changes: 1 addition & 8 deletions program/c/src/oracle/model/test_price_model.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ qcmp( void const * _p,
return 0;
}

int
main( int argc,
char ** argv ) {
(void)argc; (void)argv;
int test_price_model() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes in the C test files are:

  1. export a function name so we can call them from rust (instead of main)
  2. delete the noisy printf statements
  3. I reduced the iteration counts on a couple of the randomized tests, because they took several minutes to run.


prng_t _prng[1];
prng_t * prng = prng_join( prng_new( _prng, (uint32_t)0, (uint64_t)0 ) );
Expand All @@ -29,10 +26,7 @@ main( int argc,
int64_t val [3];
int64_t scratch[N];

int ctr = 0;
for( int iter=0; iter<10000000; iter++ ) {
if( !ctr ) { printf( "Completed %u iterations\n", iter ); ctr = 100000; }
ctr--;

/* Generate a random test */

Expand Down Expand Up @@ -63,6 +57,5 @@ main( int argc,

prng_delete( prng_leave( prng ) );

printf( "pass\n" );
return 0;
}
2 changes: 0 additions & 2 deletions program/c/src/oracle/sort/clean

This file was deleted.

14 changes: 0 additions & 14 deletions program/c/src/oracle/sort/run_tests

This file was deleted.

11 changes: 1 addition & 10 deletions program/c/src/oracle/sort/test_sort_stable.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
#define SORT_BEFORE(i,j) BEFORE(i,j)
#include "tmpl/sort_stable.c"

int
main( int argc,
char ** argv ) {
(void)argc; (void)argv;
int test_sort_stable() {

# define N 96
int x[N];
Expand All @@ -23,7 +20,6 @@ main( int argc,
additional information in the keys to validate stability as well). */

for( int n=0; n<=24; n++ ) {
printf( "Zero-One: Testing n=%i\n", n );
for( long b=0L; b<(1L<<n); b++ ) {
for( int i=0; i<n; i++ ) x[i] = (((int)((b>>i) & 1L))<<16) | i;
for( int i=0; i<n; i++ ) w[i] = x[i];
Expand All @@ -49,10 +45,7 @@ main( int argc,
prng_t _prng[1];
prng_t * prng = prng_join( prng_new( _prng, (uint32_t)0, (uint64_t)0 ) );

int ctr = 0;
for( int iter=0; iter<10000000; iter++ ) {
if( !ctr ) { printf( "Randomized: Completed %i iterations\n", iter ); ctr = 100000; }
ctr--;

int n = (int)(prng_uint32( prng ) % (uint32_t)(N+1)); /* In [0,N], approx uniform IID */
for( int i=0; i<n; i++ ) x[i] = (int)((prng_uint32( prng ) & UINT32_C( 0x00ff0000 )) | (uint32_t)i);
Expand All @@ -74,8 +67,6 @@ main( int argc,
}

prng_delete( prng_leave( prng ) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to delete this prng_delete( prng_leave( prng ) );


printf( "pass\n" );
return 0;
}

Expand Down
2 changes: 0 additions & 2 deletions program/c/src/oracle/util/clean

This file was deleted.

51 changes: 0 additions & 51 deletions program/c/src/oracle/util/run_tests

This file was deleted.

9 changes: 1 addition & 8 deletions program/c/src/oracle/util/test_align.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
#include "util.h"

int
main( int argc,
char ** argv ) {
(void)argc; (void)argv;
test_align() {

uint32_t shift_mask = (uint32_t)(sizeof(uintptr_t)*(size_t)CHAR_BIT);
if( !align_ispow2( (uintptr_t)shift_mask ) ) {
Expand All @@ -17,10 +15,7 @@ main( int argc,
prng_t _prng[1];
prng_t * prng = prng_join( prng_new( _prng, (uint32_t)0, (uint64_t)0 ) );

int ctr = 0;
for( int i=0; i<1000000000; i++ ) {
if( !ctr ) { printf( "Completed %i iterations\n", i ); ctr = 10000000; }
ctr--;

/* Test align_ispow2 */

Expand Down Expand Up @@ -70,7 +65,5 @@ main( int argc,

prng_delete( prng_leave( prng ) );

printf( "pass\n" );

return 0;
}
27 changes: 7 additions & 20 deletions program/c/src/oracle/util/test_avg.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,11 @@
#include "util.h"

int
main( int argc,
char ** argv ) {
(void)argc; (void)argv;

test_avg() {
prng_t _prng[1];
prng_t * prng = prng_join( prng_new( _prng, (uint32_t)0, (uint64_t)0 ) );

int ctr;

ctr = 0;
for( int i=0; i<1000000000; i++ ) {
if( !ctr ) { printf( "reg: Completed %i iterations\n", i ); ctr = 10000000; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can delete ctr from every test since it was just used for printing

ctr--;
for( int i=0; i<100000000; i++ ) {

# define TEST(w) do { \
uint##w##_t x = prng_uint##w( prng ); \
Expand Down Expand Up @@ -75,18 +67,15 @@ main( int argc,

# define N 512

ctr = 0;
for( int i=0; i<10000000; i++ ) {
Copy link
Contributor

@guibescos guibescos Apr 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's another variable called i inside the loop, can you fix that for clarity? For example by renaming this i to iter

if( !ctr ) { printf( "mem: Completed %i iterations\n", i ); ctr = 100000; }
ctr--;
for( int i=0; i<1000000; i++ ) {

# define TEST(w) do { \
uint##w##_t x[N]; \
uint32_t n = prng_uint32( prng ) & (uint32_t)(N-1); \
uint64_t a = (uint64_t)0; \
for( uint32_t i=(uint32_t)0; i<n; i++ ) { \
for( uint32_t j=(uint32_t)0; j<n; j++ ) { \
uint##w##_t xi = prng_uint##w( prng ); \
x[i] = xi; \
x[j] = xi; \
a += (uint64_t)xi; \
} \
if( n ) a /= (uint64_t)n; \
Expand All @@ -109,9 +98,9 @@ main( int argc,
int##w##_t x[N]; \
uint32_t n = prng_uint32( prng ) & (uint32_t)(N-1); \
int64_t a = (int64_t)0; \
for( uint32_t i=(uint32_t)0; i<n; i++ ) { \
for( uint32_t j=(uint32_t)0; j<n; j++ ) { \
int##w##_t xi = (int##w##_t)prng_uint##w( prng ); \
x[i] = xi; \
x[j] = xi; \
a += (int64_t)xi; \
} \
if( n ) a /= (int64_t)n; /* Assumes round to zero signed int div on platform */ \
Expand All @@ -136,7 +125,5 @@ main( int argc,

prng_delete( prng_leave( prng ) );

printf( "pass\n" );

return 0;
}
7 changes: 1 addition & 6 deletions program/c/src/oracle/util/test_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ uint64_t ref64[10] = {
UINT64_C( 0x91209a1ff7f4f1d5 )
};

int
main( int argc,
char ** argv ) {
(void)argc; (void)argv;
int test_hash() {

for( int i=0; i<10; i++ ) {
uint32_t x = (uint32_t)i;
Expand All @@ -52,7 +49,5 @@ main( int argc,
}

/* FIXME: MEASURE AVALANCHE PROPERTIES? */

printf( "pass\n" );
return 0;
}
Loading