Skip to content

Commit 4d1b0d3

Browse files
committed
feat(lazer): add governance instructions protocol
1 parent 3c32ca2 commit 4d1b0d3

File tree

6 files changed

+295
-3
lines changed

6 files changed

+295
-3
lines changed

lazer/Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
syntax = "proto3";
2+
3+
import "google/protobuf/timestamp.proto";
4+
import "google/protobuf/duration.proto";
5+
6+
package pyth_lazer_transaction;
7+
8+
/// ABCDEF
9+
message DynamicValue {
10+
// ABC
11+
message List {
12+
repeated DynamicValue items = 1;
13+
}
14+
message MapItem {
15+
// [required] Must be unique.
16+
optional string key = 1;
17+
// [required]
18+
optional DynamicValue value = 2;
19+
}
20+
message Map {
21+
repeated MapItem items = 1;
22+
}
23+
24+
oneof value {
25+
string string_value = 1;
26+
double double_value = 2;
27+
uint64 uint_value = 3;
28+
sint64 int_value = 4;
29+
bool bool_value = 5;
30+
bytes bytes_value = 6;
31+
google.protobuf.Duration duration_value = 7;
32+
google.protobuf.Timestamp timestamp_value = 8;
33+
List list = 9;
34+
Map map = 10;
35+
}
36+
}
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
syntax = "proto3";
2+
3+
import "google/protobuf/timestamp.proto";
4+
import "google/protobuf/duration.proto";
5+
import "google/protobuf/empty.proto";
6+
7+
import "dynamic_value.proto";
8+
9+
// If any field documented as `[required]` is not present in the instruction,
10+
// the instruction will be rejected.
11+
12+
package pyth_lazer_transaction;
13+
14+
// Representation of a complete governance instruction. This value will be signed
15+
// by a governance source.
16+
message GovernanceInstruction {
17+
// Action requested by this instruction. For the instruction to be accepted, all directives
18+
// must be successfully applied. In case of any failure, the whole instruction is reverted.
19+
// However, note that if the instruction targets multiple (or all) shards, each shard will
20+
// accept or reject the instruction independently of other shards.
21+
repeated GovernanceDirective directives = 1;
22+
// [optional] If specified, the instruction will be rejected if the current timestamp
23+
// is less than the specified value. In case of rejection, the same instruction can be resubmitted
24+
// and executed later once the time requirement is met.
25+
optional google.protobuf.Timestamp min_execution_timestamp = 2;
26+
// [optional] If specified, the instruction will be rejected if the current timestamp
27+
// is greater than the specified value. After `max_execution_timestamp` is in the past,
28+
// it will no longer be possible to execute this instruction.
29+
optional google.protobuf.Timestamp max_execution_timestamp = 3;
30+
// [required] Sequence number of this instruction. It must be greater than 0.
31+
// It must always be increasing, but not required to be
32+
// strictly sequential (i.e. gaps are allowed). Each shard separately keeps track of the last executed
33+
// governance instruction and will reject instructions with the same or smaller sequence no.
34+
// Note that if instructions are received out of order, some of them may become permanently
35+
// rejected (e.g. if instruction #3 has been successfully processed before instruction #2 was observed,
36+
// #2 will always be rejected).
37+
// Sequence numbers are assigned and tracked separately for each governance source.
38+
optional uint32 governance_sequence_no = 4;
39+
}
40+
41+
// An item of a governance instruction.
42+
message GovernanceDirective {
43+
// Shard name this directive applies to. If empty,
44+
// this directive will apply to all shards.
45+
repeated string shard_names = 1;
46+
// [required]
47+
oneof action {
48+
AddGovernanceSource add_governance_source = 101;
49+
UpdateGovernanceSource update_governance_source = 102;
50+
SetShardName set_shard_name = 103;
51+
AddPublisher add_publisher = 104;
52+
UpdatePublisher update_publisher = 105;
53+
AddFeed add_feed = 106;
54+
UpdateFeed update_feed = 107;
55+
}
56+
}
57+
58+
// Permissions granted to a governance source.
59+
// bool fields in this message are optional and default to false (no permission).
60+
message Permissions {
61+
// All operations, including operations added in the future.
62+
optional bool all = 1;
63+
optional bool add_governance_source = 2;
64+
// All operations under `UpdateGovernanceSource` (update and delete),
65+
// including operations added in the future.
66+
optional bool update_governance_source_all = 3;
67+
optional bool update_governance_source_permissions = 4;
68+
optional bool remove_governance_source = 5;
69+
optional bool set_shard_name = 6;
70+
optional bool add_publisher = 7;
71+
// All operations under `UpdatePublisher` (update and delete),
72+
// including operations added in the future.
73+
optional bool update_publisher_all = 8;
74+
optional bool set_publisher_name = 9;
75+
optional bool add_publisher_public_keys = 10;
76+
optional bool remove_publisher_public_keys = 11;
77+
optional bool set_publisher_public_keys = 12;
78+
optional bool set_publisher_active = 13;
79+
optional bool remove_publisher = 14;
80+
optional bool add_feed = 15;
81+
// All operations under `UpdateFeed` (update and delete),
82+
// including operations added in the future.
83+
optional bool update_feed_all = 16;
84+
optional bool update_feed_metadata = 17;
85+
optional bool activate_feed = 18;
86+
optional bool deactivate_feed = 19;
87+
optional bool remove_feed = 20;
88+
}
89+
90+
// Specifies the way governance transactions are signed and verified.
91+
message GovernanceSource {
92+
// Governance transactions are signed by a single Ed25519 signature.
93+
message SingleEd25519 {
94+
// [required] Ed25519 public key that signs governance transactions.
95+
optional bytes public_key = 1;
96+
}
97+
98+
// [required]
99+
oneof source {
100+
SingleEd25519 single_ed25519 = 1;
101+
// TODO: wormhole source goes here.
102+
}
103+
}
104+
105+
message AddGovernanceSource {
106+
// [required] Governance source that should be added.
107+
optional GovernanceSource new_source = 1;
108+
// [required] Permissions granted to this source.
109+
optional Permissions permissions = 2;
110+
}
111+
112+
message UpdateGovernanceSource {
113+
// [required] Governance source that should be updated.
114+
optional GovernanceSource source = 1;
115+
// [required]
116+
oneof action {
117+
SetGovernanceSourcePermissions set_governance_source_permissions = 2;
118+
// Removes a governance source. Note that the last sequence number associated with this source
119+
// will be retained in the state to prevent repeated execution of instructions in case
120+
// the same source is re-added later.
121+
google.protobuf.Empty remove_governance_source = 3;
122+
}
123+
}
124+
125+
message SetGovernanceSourcePermissions {
126+
// [required] Permissions granted to this source. Replaces all previous permissions.
127+
optional Permissions permissions = 2;
128+
}
129+
130+
// Set shard name. This action will be rejected if `GovernanceDirective.shard_names` is empty or contains
131+
// more than one item.
132+
message SetShardName {
133+
// [required] New shard name. Must be unique across all shards in all environments.
134+
// (Warning: it's not possible to enforce this rule within a shard!)
135+
optional string shard_name = 1;
136+
}
137+
138+
message AddPublisher {
139+
// [required] Publisher ID. Restricted to uint16. Must be different from existing ids.
140+
optional uint32 publisher_id = 1;
141+
// [required] Publisher name (only for debug/monitoring/management purposes).
142+
// Must be different from existing publisher names.
143+
optional string name = 2;
144+
// Public keys used to sign publisher update transactions.
145+
repeated bytes public_keys = 3;
146+
// [required] If true, the publisher is active, i.e. it's allowed to publish updates.
147+
optional bool is_active = 4;
148+
}
149+
150+
message UpdatePublisher {
151+
// [required] ID of the publisher that is being updated. Rejects if there is no such publisher.
152+
optional uint32 publisher_id = 1;
153+
// [required]
154+
oneof action {
155+
SetPublisherName set_publisher_name = 2;
156+
AddPublisherPublicKeys add_publisher_public_keys = 3;
157+
RemovePublisherPublicKeys remove_publisher_public_keys = 4;
158+
SetPublisherPublicKeys set_publisher_public_keys = 5;
159+
SetPublisherActive set_publisher_active = 6;
160+
google.protobuf.Empty remove_publisher = 7;
161+
}
162+
}
163+
164+
message SetPublisherName {
165+
// [required] New name.
166+
optional string name = 1;
167+
}
168+
169+
// Add new keys.
170+
message AddPublisherPublicKeys {
171+
// Must not be empty.
172+
repeated bytes public_keys = 1;
173+
}
174+
175+
// Remove existing keys.
176+
message RemovePublisherPublicKeys {
177+
// Must not be empty.
178+
repeated bytes public_keys = 1;
179+
}
180+
181+
// Remove all existing public keys and add new keys (if specified).
182+
message SetPublisherPublicKeys {
183+
repeated bytes public_keys = 1;
184+
}
185+
186+
message SetPublisherActive {
187+
// [required]
188+
optional bool is_active = 1;
189+
}
190+
191+
// Feed is inactive when added, meaning that it will be available to publishers but not to consumers.
192+
message AddFeed {
193+
// [required] ID of the price feed. Must be unique (within the shard).
194+
optional uint32 price_feed_id = 1;
195+
// [required] Feed metadata. Some properties are required (exponent, etc.).
196+
// Known properties must have the expected type.
197+
// Additional arbitrary properties are allowed.
198+
// (TODO: document known metadata properties)
199+
optional DynamicValue.Map metadata = 2;
200+
// IDs of publishers enabled for this feed.
201+
repeated uint32 permissioned_publishers = 3;
202+
}
203+
204+
message UpdateFeed {
205+
// [required] ID of the feed that is being updated.
206+
optional uint32 price_feed_id = 1;
207+
// [required]
208+
oneof action {
209+
UpdateFeedMetadata update_feed_metadata = 2;
210+
ActivateFeed activate_feed = 3;
211+
DeactivateFeed deactivate_feed = 4;
212+
google.protobuf.Empty remove_feed = 5;
213+
}
214+
}
215+
216+
message UpdateFeedMetadata {
217+
// [required] Property name.
218+
optional string name = 1;
219+
// [optional] Property value. If unset, the property will be removed.
220+
optional DynamicValue value = 2;
221+
}
222+
223+
message ActivateFeed {
224+
// [optional] If provided, the feed will activate at the specified timestamp.
225+
// If `activation_timestamp` is already passed or if it's unset,
226+
// the feed will be activated immediately when this
227+
// governance instruction is processed.
228+
// If there was already a pending activation or deactivation, it will be cleared
229+
// when this governance instruction is processed.
230+
optional google.protobuf.Timestamp activation_timestamp = 1;
231+
}
232+
233+
message DeactivateFeed {
234+
// [optional] If provided, the feed will deactivate at the specified timestamp.
235+
// If `deactivation_timestamp` is already passed or if it's unset,
236+
// the feed will be deactivated immediately when this
237+
// governance instruction is processed.
238+
// If there was already a pending activation or deactivation, it will be cleared
239+
// when this governance instruction is processed.
240+
optional google.protobuf.Timestamp deactivation_timestamp = 1;
241+
}
242+

lazer/publisher_sdk/proto/pyth_lazer_transaction.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ syntax = "proto3";
33
package pyth_lazer_transaction;
44

55
import "publisher_update.proto";
6+
import "governance_instruction.proto";
67

78
// Types of Signatures allowed for signing Lazer Transactions
89
enum TransactionSignatureType {
@@ -30,5 +31,7 @@ message LazerTransaction {
3031
// Expected transaction sent by Publishers
3132
// May contain many individual updates to various feeds
3233
PublisherUpdate publisher_update = 1;
34+
// Sent by governance.
35+
GovernanceInstruction governance_instruction = 2;
3336
}
3437
}

lazer/publisher_sdk/rust/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ repository = "https://github.com/pyth-network/pyth-crosschain"
1010
protobuf = "3.7.2"
1111

1212
[build-dependencies]
13+
fs-err = "3.1.0"
1314
protobuf-codegen = "3.7.2"

lazer/publisher_sdk/rust/build.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::io::Result;
22

3+
use fs_err::read_dir;
4+
35
/// Automatically runs during cargo build.
46
/// Proto files for Lazer are defined in the lazer sdk folder in the proto/ subdirectory.
57
/// Both JS and Rust SDKs read the proto files for generating types.
@@ -8,10 +10,8 @@ fn main() -> Result<()> {
810
println!("cargo:rerun-if-changed=../proto/");
911

1012
protobuf_codegen::Codegen::new()
11-
.pure()
1213
.include("../proto")
13-
.input("../proto/publisher_update.proto")
14-
.input("../proto/pyth_lazer_transaction.proto")
14+
.inputs(read_dir("../proto")?.map(|item| item.unwrap().path()))
1515
.cargo_out_dir("protobuf")
1616
.run_from_script();
1717

0 commit comments

Comments
 (0)