Преглед изворни кода

pyth2wormhole: Add compatible metadata, handle EVM fwd-compat

commit-id:d92b42b5
Stan Drozd пре 3 година
родитељ
комит
3270024ed3

+ 72 - 50
ethereum/contracts/pyth/Pyth.sol

@@ -106,65 +106,87 @@ contract Pyth is PythGetters, PythSetters, AbstractPyth {
 
         // Deserialize each attestation
         for (uint j=0; j < bpa.nAttestations; j++) {
+	    // NOTE: We don't advance the global index immediately.
+	    // attestationIndex is an attestation-local offset used
+	    // for readability and easier debugging.
+	    uint attestationIndex = 0;
+
             // Header
-            bpa.attestations[j].header.magic = encoded.toUint32(index);
-            index += 4;
+            bpa.attestations[j].header.magic = encoded.toUint32(index + attestationIndex);
+            attestationIndex += 4;
             require(bpa.attestations[j].header.magic == 0x50325748, "invalid magic value");
 
-            bpa.attestations[j].header.version = encoded.toUint16(index);
-            index += 2;
+            bpa.attestations[j].header.version = encoded.toUint16(index + attestationIndex);
+            attestationIndex += 2;
             require(bpa.attestations[j].header.version == 2, "invalid version");
 
-            bpa.attestations[j].header.payloadId = encoded.toUint8(index);
-            index += 1;
+            bpa.attestations[j].header.payloadId = encoded.toUint8(index + attestationIndex);
+            attestationIndex += 1;
             // Payload ID of 1 required for individual attestation
             require(bpa.attestations[j].header.payloadId == 1, "invalid payload ID");
 
             // Attestation
-            bpa.attestations[j].productId = encoded.toBytes32(index);
-            index += 32;
-
-            bpa.attestations[j].priceId = encoded.toBytes32(index);
-            index += 32;
-            bpa.attestations[j].priceType = encoded.toUint8(index);
-            index += 1;
-
-            bpa.attestations[j].price = int64(encoded.toUint64(index));
-            index += 8;
-
-            bpa.attestations[j].exponent = int32(encoded.toUint32(index));
-            index += 4;
-
-            bpa.attestations[j].emaPrice.value = int64(encoded.toUint64(index));
-            index += 8;
-            bpa.attestations[j].emaPrice.numerator = int64(encoded.toUint64(index));
-            index += 8;
-            bpa.attestations[j].emaPrice.denominator = int64(encoded.toUint64(index));
-            index += 8;
-
-            bpa.attestations[j].emaConf.value = int64(encoded.toUint64(index));
-            index += 8;
-            bpa.attestations[j].emaConf.numerator = int64(encoded.toUint64(index));
-            index += 8;
-            bpa.attestations[j].emaConf.denominator = int64(encoded.toUint64(index));
-            index += 8;
-
-            bpa.attestations[j].confidenceInterval = encoded.toUint64(index);
-            index += 8;
-
-            bpa.attestations[j].status = encoded.toUint8(index);
-            index += 1;
-            bpa.attestations[j].corpAct = encoded.toUint8(index);
-            index += 1;
-
-            bpa.attestations[j].timestamp = encoded.toUint64(index);
-            index += 8;
-
-            bpa.attestations[j].num_publishers = encoded.toUint32(index);
-            index += 4;
-
-            bpa.attestations[j].max_num_publishers = encoded.toUint32(index);
-            index += 4;
+            bpa.attestations[j].productId = encoded.toBytes32(index + attestationIndex);
+            attestationIndex += 32;
+
+            bpa.attestations[j].priceId = encoded.toBytes32(index + attestationIndex);
+            attestationIndex += 32;
+            bpa.attestations[j].priceType = encoded.toUint8(index + attestationIndex);
+            attestationIndex += 1;
+
+            bpa.attestations[j].price = int64(encoded.toUint64(index + attestationIndex));
+            attestationIndex += 8;
+
+            bpa.attestations[j].exponent = int32(encoded.toUint32(index + attestationIndex));
+            attestationIndex += 4;
+
+            bpa.attestations[j].emaPrice.value = int64(encoded.toUint64(index + attestationIndex));
+            attestationIndex += 8;
+            bpa.attestations[j].emaPrice.numerator = int64(encoded.toUint64(index + attestationIndex));
+            attestationIndex += 8;
+            bpa.attestations[j].emaPrice.denominator = int64(encoded.toUint64(index + attestationIndex));
+            attestationIndex += 8;
+
+            bpa.attestations[j].emaConf.value = int64(encoded.toUint64(index + attestationIndex));
+            attestationIndex += 8;
+            bpa.attestations[j].emaConf.numerator = int64(encoded.toUint64(index + attestationIndex));
+            attestationIndex += 8;
+            bpa.attestations[j].emaConf.denominator = int64(encoded.toUint64(index + attestationIndex));
+            attestationIndex += 8;
+
+            bpa.attestations[j].confidenceInterval = encoded.toUint64(index + attestationIndex);
+            attestationIndex += 8;
+
+            bpa.attestations[j].status = encoded.toUint8(index + attestationIndex);
+            attestationIndex += 1;
+            bpa.attestations[j].corpAct = encoded.toUint8(index + attestationIndex);
+            attestationIndex += 1;
+
+            bpa.attestations[j].timestamp = encoded.toUint64(index + attestationIndex);
+            attestationIndex += 8;
+
+            bpa.attestations[j].num_publishers = encoded.toUint32(index + attestationIndex);
+            attestationIndex += 4;
+
+            bpa.attestations[j].max_num_publishers = encoded.toUint32(index + attestationIndex);
+            attestationIndex += 4;
+
+            bpa.attestations[j].publish_time = encoded.toUint64(index + attestationIndex);
+            attestationIndex += 8;
+
+            bpa.attestations[j].prev_publish_time = encoded.toUint64(index + attestationIndex);
+            attestationIndex += 8;
+
+            bpa.attestations[j].prev_price = int64(encoded.toUint64(index + attestationIndex));
+            attestationIndex += 8;
+
+            bpa.attestations[j].prev_conf = encoded.toUint64(index + attestationIndex);
+            attestationIndex += 8;
+
+	    require(attestationIndex <= bpa.attestationSize, "INTERNAL: Consumed more than `attestationSize` bytes");
+
+	    // Respect specified attestation size for forward-compat
+	    index += bpa.attestationSize;
         }
     }
 

+ 4 - 0
ethereum/contracts/pyth/PythInternalStructs.sol

@@ -44,6 +44,10 @@ contract PythInternalStructs {
         uint64 timestamp;
 	uint32 num_publishers;
 	uint32 max_num_publishers;
+	uint64 publish_time;
+	uint64 prev_publish_time;
+	int64 prev_price;
+	uint64 prev_conf;
     }
 
     struct Rational {

Разлика између датотеке није приказан због своје велике величине
+ 1 - 0
ethereum/test/pyth.js


+ 4 - 4
terra/Cargo.lock

@@ -1378,9 +1378,9 @@ dependencies = [
 
 [[package]]
 name = "pyth-sdk"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c610102a39fc4bae29a3b5a628ee134d25afb3dca3937692f5e634f1287fe0b4"
+checksum = "cb06993b8c8ad7f50042e8b6b6ae4ed2a98722495845b12efc9a12f4301b901b"
 dependencies = [
  "borsh",
  "borsh-derive",
@@ -1390,9 +1390,9 @@ dependencies = [
 
 [[package]]
 name = "pyth-sdk-solana"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1fdc94592a28fa829b0d6fa619392b1a1744048e5b78a74a4ba93cf541eddae"
+checksum = "b83f33cbdeccc350e021f6b4bc714655aa38352fac80a93b16b1902863aedb62"
 dependencies = [
  "borsh",
  "borsh-derive",

+ 1 - 1
terra/contracts/pyth-bridge/Cargo.toml

@@ -33,7 +33,7 @@ lazy_static = "1.4.0"
 bigint = "4"
 p2w-sdk = { path = "../../../third_party/pyth/p2w-sdk/rust" }
 solana-program = "=1.8.16"
-pyth-sdk = { version = "0.2.0" }
+pyth-sdk = "0.3.0"
 
 [dev-dependencies]
 cosmwasm-vm = { version = "0.16.0", default-features = false }

+ 4 - 0
terra/contracts/pyth-bridge/src/contract.rs

@@ -130,6 +130,7 @@ fn process_batch_attestation(
         let price_feed = PriceFeed::new(
             price_attestation.price_id.to_bytes(),
             price_attestation.status,
+	    price_attestation.publish_time,
             price_attestation.expo,
             price_attestation.max_num_publishers, // max_num_publishers data is currently unavailable
             price_attestation.num_publishers, // num_publishers data is currently unavailable
@@ -138,6 +139,9 @@ fn process_batch_attestation(
             price_attestation.confidence_interval,
             price_attestation.ema_price.val,
             price_attestation.ema_conf.val as u64,
+	    price_attestation.prev_price,
+	    price_attestation.prev_conf,
+	    price_attestation.prev_publish_time,
         );
 
         let attestation_time = Timestamp::from_seconds(price_attestation.timestamp as u64);

+ 1 - 1
third_party/pyth/Dockerfile.pyth

@@ -1,6 +1,6 @@
 # syntax=docker/dockerfile:1.2
 # Wormhole-specific setup for pyth
-FROM pythfoundation/pyth-client:devnet-v2.10.1
+FROM pythfoundation/pyth-client:devnet-v2.11.1
 
 USER root
 

+ 4 - 4
third_party/pyth/p2w-sdk/rust/Cargo.lock

@@ -631,9 +631,9 @@ dependencies = [
 
 [[package]]
 name = "pyth-sdk"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c610102a39fc4bae29a3b5a628ee134d25afb3dca3937692f5e634f1287fe0b4"
+checksum = "cb06993b8c8ad7f50042e8b6b6ae4ed2a98722495845b12efc9a12f4301b901b"
 dependencies = [
  "borsh",
  "borsh-derive",
@@ -643,9 +643,9 @@ dependencies = [
 
 [[package]]
 name = "pyth-sdk-solana"
-version = "0.2.0"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1fdc94592a28fa829b0d6fa619392b1a1744048e5b78a74a4ba93cf541eddae"
+checksum = "b83f33cbdeccc350e021f6b4bc714655aa38352fac80a93b16b1902863aedb62"
 dependencies = [
  "borsh",
  "borsh-derive",

+ 1 - 1
third_party/pyth/p2w-sdk/rust/Cargo.toml

@@ -15,7 +15,7 @@ wasm = ["wasm-bindgen", "solana"]
 
 [dependencies]
 serde = { version = "1.0.103", default-features = false, features = ["derive"] }
-pyth-sdk-solana = { version = "0.2.0" }
+pyth-sdk-solana = "0.3.0"
 wasm-bindgen = { version = "0.2.74", features = ["serde-serialize"], optional = true}
 solitaire = { path = "../../../../solana/solitaire/program", optional = true }
 solana-program = "1.8.16"

+ 57 - 6
third_party/pyth/p2w-sdk/rust/src/lib.rs

@@ -32,7 +32,6 @@ use solana_program::pubkey::Pubkey;
 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
 pub mod wasm;
 
-/// Quality of life type alias for wrapping up boxed errors.
 pub type ErrBox = Box<dyn std::error::Error>;
 
 /// Precedes every message implementing the p2w serialization format
@@ -73,9 +72,17 @@ pub struct PriceAttestation {
     pub confidence_interval: u64,
     pub status:              PriceStatus,
     pub corp_act:            CorpAction,
+    // TODO(2022-04-07) format v3: Rename this aptly named timestamp
+    // field to attestation_time (it's a grey area in terms of
+    // compatibility and v3 is due very soon either way)
+    /// NOTE: SOL on-chain time of attestation
     pub timestamp:           UnixTimestamp,
     pub num_publishers:      u32,
     pub max_num_publishers:  u32,
+    pub publish_time:        UnixTimestamp,
+    pub prev_publish_time:   UnixTimestamp,
+    pub prev_price:          i64,
+    pub prev_conf:           u64, 
 }
 
 #[derive(Clone, Default, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
@@ -236,7 +243,7 @@ pub fn deserialize_rational(mut bytes: impl Read) -> Result<Rational, ErrBox> {
 impl PriceAttestation {
     pub fn from_pyth_price_bytes(
         price_id: Pubkey,
-        timestamp: UnixTimestamp,
+        attestation_time: UnixTimestamp,
         value: &[u8],
     ) -> Result<Self, ErrBox> {
         let price = pyth_sdk_solana::state::load_price_account(value)?;
@@ -252,9 +259,13 @@ impl PriceAttestation {
             confidence_interval: price.agg.conf,
             status: price.agg.status,
             corp_act: price.agg.corp_act,
-            timestamp: timestamp,
+            timestamp: attestation_time,
             num_publishers: price.num_qt,
-	    max_num_publishers: price.num,
+            max_num_publishers: price.num,
+	    publish_time: price.timestamp,
+	    prev_publish_time: price.prev_timestamp,
+	    prev_price: price.prev_price,
+	    prev_conf: price.prev_conf,
         })
     }
 
@@ -276,6 +287,10 @@ impl PriceAttestation {
             timestamp,
             num_publishers,
             max_num_publishers,
+	    publish_time,
+	    prev_publish_time,
+	    prev_price,
+	    prev_conf
         } = self;
 
         // magic
@@ -326,6 +341,18 @@ impl PriceAttestation {
         // max_num_publishers
         buf.extend_from_slice(&max_num_publishers.to_be_bytes()[..]);
 
+	// publish_time
+        buf.extend_from_slice(&publish_time.to_be_bytes()[..]);
+
+	// prev_publish_time
+        buf.extend_from_slice(&prev_publish_time.to_be_bytes()[..]);
+
+        // prev_price
+        buf.extend_from_slice(&prev_price.to_be_bytes()[..]);
+
+	// prev_conf
+        buf.extend_from_slice(&prev_conf.to_be_bytes()[..]);
+
         buf
     }
     pub fn deserialize(mut bytes: impl Read) -> Result<Self, ErrBox> {
@@ -433,6 +460,22 @@ impl PriceAttestation {
         bytes.read_exact(max_num_publishers_vec.as_mut_slice())?;
         let max_num_publishers = u32::from_be_bytes(max_num_publishers_vec.as_slice().try_into()?);
 
+        let mut publish_time_vec = vec![0u8; mem::size_of::<UnixTimestamp>()];
+        bytes.read_exact(publish_time_vec.as_mut_slice())?;
+        let publish_time = UnixTimestamp::from_be_bytes(publish_time_vec.as_slice().try_into()?);
+
+        let mut prev_publish_time_vec = vec![0u8; mem::size_of::<UnixTimestamp>()];
+        bytes.read_exact(prev_publish_time_vec.as_mut_slice())?;
+        let prev_publish_time = UnixTimestamp::from_be_bytes(prev_publish_time_vec.as_slice().try_into()?);
+
+        let mut prev_price_vec = vec![0u8; mem::size_of::<i64>()];
+        bytes.read_exact(prev_price_vec.as_mut_slice())?;
+        let prev_price = i64::from_be_bytes(prev_price_vec.as_slice().try_into()?);
+
+        let mut prev_conf_vec = vec![0u8; mem::size_of::<u64>()];
+        bytes.read_exact(prev_conf_vec.as_mut_slice())?;
+        let prev_conf = u64::from_be_bytes(prev_conf_vec.as_slice().try_into()?);
+
         Ok(Self {
             product_id,
             price_id,
@@ -446,7 +489,11 @@ impl PriceAttestation {
             corp_act,
             timestamp,
             num_publishers,
-	    max_num_publishers,
+            max_num_publishers,
+	    publish_time,
+	    prev_publish_time,
+	    prev_price,
+	    prev_conf,
         })
     }
 }
@@ -487,7 +534,11 @@ mod tests {
             corp_act:            CorpAction::NoCorpAct,
             timestamp:           (0xdeadbeeffadedeedu64) as i64,
 	    num_publishers: 123212u32,
-	    max_num_publishers: 321232u32
+	    max_num_publishers: 321232u32,
+	    publish_time: 0xdeadbeefi64,
+	    prev_publish_time: 0xdeadbabei64,
+	    prev_price: 0xdeadfacebeefi64,
+	    prev_conf: 0xbadbadbeefu64, // I could do this all day -SD
         }
     }
 

Неке датотеке нису приказане због велике количине промена