Skip to content

Commit a7383a3

Browse files
authored
[sui 11/x] - pyth merkle accumulator (#910)
* merkle tree impl * - take leftmost 20 bytes in hash - don't assign output of cursor::take_rest to _, instead just drop it * push PREFIXes (MERKLE_LEAF_PREFIX, MERKLE_NODE_PREFIX) to front instead of back * delete testXOR * test construct merkle tree depth exceeded error * invalid merkle proof test cases * comments * rename failure tests * simplification for initializing a vector * fix leafHash bug, add tests for hashLeaf and hashNode * pyth accumulator start, extract_price_info_from_merkle_proof, parse_price_feed_message * parse_price_feed_message, parse_and_verify_accumulator_updates * implementation + debugging for merkle pyth accumulator * edit merkle tree * testNodehash * test hash * delete prints * test case for parse and verify TEST_ACCUMULATOR_3_MSGS * hot potato vector -> authenticated price infos * refactor - move tests from pyth_accumulator to pyth to avoid dependency cycle * remove _ from deserializing unused vaa * add sui-contract.yml for github actions * AuthenticatedPriceInfos -> AuthenticatedVector * charge base update fee per call to update_single_price_feed * add back multiple tests, including test_create_and_update_price_feeds_insufficient_fee, update cache, update cache old update * test multiple price feed creation and update accumulator * authenticated_price_infos.move -> authenticated_vector.move * 5 * single_update_fee * delete some comments, add accumulator test info * don't make TEST_VAAS test_only in pyth.move * remove #[test_only]s * assert price info object contains correct price feed info * factor out some constants from accumulator test cases to reduce duplicate code * add sui-contract.yml file for github actions CI * more refactor and clean-up * assert price_info_object_1 is correct in test_create_and_update_price_feeds_with_batch_attestation_success * removed the parse_and_verify_accumulator_message_with_worm_state entirely, and instead added the helper parse_vaa_bytes_from_accumulator_message * edit comment * update comment * edit sui github ci * fix for sui-contract.yml * MINIMUM_SUPPORTED_MINOR_VERSION and MAJOR_VERSION * remove test_get_price_feed_updates_from_accumulator and parse_vaa_bytes_from_accumulator_message from pyth_accumulator.move * test_parse_and_verify_accumulator_updates_with_extra_bytes_at_end_of_message * sui contract yml update * use rev to cargo install sui in github actions ci * cargo install --locked for github CI
1 parent 96cb221 commit a7383a3

File tree

8 files changed

+1183
-557
lines changed

8 files changed

+1183
-557
lines changed

.github/workflows/sui-contract.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
on:
2+
pull_request:
3+
paths:
4+
- target_chains/sui/contracts/**
5+
push:
6+
branches:
7+
- main
8+
paths:
9+
- target_chains/sui/contracts/**
10+
11+
name: Sui Contracts
12+
13+
jobs:
14+
sui-tests:
15+
name: Sui tests
16+
runs-on: ubuntu-latest
17+
defaults:
18+
run:
19+
working-directory: target_chains/sui/contracts/
20+
steps:
21+
- uses: actions/checkout@v3
22+
23+
- name: Update rust
24+
run: rustup update stable
25+
26+
- name: Install Sui CLI
27+
run: cargo install --locked --git https://github.com/MystenLabs/sui.git --rev 09b2081498366df936abae26eea4b2d5cafb2788 sui
28+
29+
- name: Run tests
30+
run: sui move test
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/// This class represents a collection of objects wrapped inside of a struct
2+
/// called AuthenticatedVector. Its constructor is non-public and can only be called
3+
/// by friend modules, making the creation of new AuthenticatedVector protected.
4+
module pyth::authenticated_vector {
5+
use std::vector;
6+
7+
friend pyth::pyth;
8+
9+
// A vector of elements
10+
struct AuthenticatedVector<T: copy + drop> has drop {
11+
contents: vector<T>
12+
}
13+
14+
// A public destroy function.
15+
public fun destroy<T: copy + drop>(vec: AuthenticatedVector<T>){
16+
let AuthenticatedVector {contents: _} = vec;
17+
}
18+
19+
// Only certain on-chain functions are allowed to create a new hot potato vector.
20+
public(friend) fun new<T: copy + drop>(vec: vector<T>): AuthenticatedVector<T>{
21+
AuthenticatedVector {
22+
contents: vec
23+
}
24+
}
25+
26+
public fun length<T: copy + drop>(vec: &AuthenticatedVector<T>): u64 {
27+
vector::length(&vec.contents)
28+
}
29+
30+
public fun is_empty<T: copy + drop>(vec: &AuthenticatedVector<T>): bool {
31+
vector::is_empty(&vec.contents)
32+
}
33+
34+
public fun borrow<T: copy + drop>(vec: &AuthenticatedVector<T>, i: u64): &T {
35+
vector::borrow<T>(&vec.contents, i)
36+
}
37+
38+
public(friend) fun pop_back<T: copy + drop>(vec: AuthenticatedVector<T>): (T, AuthenticatedVector<T>){
39+
let elem = vector::pop_back<T>(&mut vec.contents);
40+
return (elem, vec)
41+
}
42+
43+
#[test_only]
44+
struct A has copy, drop {
45+
a : u64
46+
}
47+
48+
#[test]
49+
fun test_authenticated_vector(){
50+
let vec_of_a = vector::empty<A>();
51+
vector::push_back(&mut vec_of_a, A{a:5});
52+
vector::push_back(&mut vec_of_a, A{a:11});
53+
vector::push_back(&mut vec_of_a, A{a:23});
54+
55+
let vec = new<A>(vec_of_a);
56+
let (b, vec) = pop_back<A>(vec);
57+
assert!(b.a==23, 0);
58+
(b, vec) = pop_back<A>(vec);
59+
assert!(b.a==11, 0);
60+
let (b, vec) = pop_back<A>(vec);
61+
assert!(b.a==5, 0);
62+
63+
destroy<A>(vec);
64+
}
65+
}

target_chains/sui/contracts/sources/hot_potato_vector.move

Lines changed: 0 additions & 65 deletions
This file was deleted.

target_chains/sui/contracts/sources/merkle_tree.move

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,14 @@ module pyth::merkle_tree {
8080
}
8181

8282
// isProofValid returns whether a merkle proof is valid
83-
fun isProofValid(
83+
public fun isProofValid(
8484
encodedProof: &mut Cursor<u8>,
8585
root: Bytes20,
8686
leafData: vector<u8>,
8787
): bool {
88-
8988
let currentDigest: Bytes20 = leafHash(&leafData);
9089
let proofSize: u8 = deserialize::deserialize_u8(encodedProof);
91-
let i: u8 = 0;
92-
while (i < proofSize){
90+
while (proofSize > 0){
9391
let siblingDigest: Bytes20 = bytes20::new(
9492
deserialize::deserialize_vector(encodedProof, 20)
9593
);
@@ -98,14 +96,14 @@ module pyth::merkle_tree {
9896
currentDigest,
9997
siblingDigest
10098
);
101-
i = i + 1;
99+
proofSize = proofSize - 1;
102100
};
103101
bytes20::data(&currentDigest) == bytes20::data(&root)
104102
}
105103

106104
// constructProofs constructs a merkle tree and returns the root of the tree as
107105
// a Bytes20 as well as the vector of encoded proofs
108-
fun constructProofs(
106+
public fun constructProofs(
109107
messages: &vector<vector<u8>>,
110108
depth: u8
111109
) : (Bytes20, vector<u8>) {

target_chains/sui/contracts/sources/price_status.move

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module pyth::price_status {
1313
}
1414

1515
public fun from_u64(status: u64): PriceStatus {
16-
assert!(status <= TRADING, 0); // error::invalid_price_status()
16+
assert!(status <= TRADING, 0);
1717
PriceStatus {
1818
status: status
1919
}

0 commit comments

Comments
 (0)