governance_instruction.proto 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. syntax = "proto3";
  2. import "google/protobuf/timestamp.proto";
  3. import "google/protobuf/duration.proto";
  4. import "google/protobuf/empty.proto";
  5. import "dynamic_value.proto";
  6. // If any field documented as `[required]` is not present in the instruction,
  7. // the instruction will be rejected.
  8. package pyth_lazer_transaction;
  9. // Representation of a complete governance instruction. This value will be signed
  10. // by a governance source.
  11. //
  12. // If the governance source is SingleEd25519, this message will be the payload of LazerTransaction.
  13. //
  14. // If the governance source is Wormhole emitter, this message will be the body of the GovernancePayload which
  15. // is the VAA message Pyth governance sends to Wormhole. The GovernancePayload follows xc-admin spec
  16. // and looks like so:
  17. // <magic:u32><module:u8><action:u8><chain:u16><GovernanceInstruction:bytes>
  18. // You can find the xc-admin spec in: ../../../governance/xc_admin/packages/xc_admin_common/src/governance_payload
  19. message GovernanceInstruction {
  20. // Action requested by this instruction. For the instruction to be accepted, all directives
  21. // must be successfully applied. In case of any failure, the whole instruction is reverted.
  22. // However, note that if the instruction targets multiple (or all) shards, each shard will
  23. // accept or reject the instruction independently of other shards.
  24. repeated GovernanceDirective directives = 2;
  25. // [optional] If specified, the instruction will be rejected if the current timestamp
  26. // is less than the specified value. In case of rejection, the same instruction can be resubmitted
  27. // and executed later once the time requirement is met.
  28. optional google.protobuf.Timestamp min_execution_timestamp = 3;
  29. // [optional] If specified, the instruction will be rejected if the current timestamp
  30. // is greater than the specified value. After `max_execution_timestamp` is in the past,
  31. // it will no longer be possible to execute this instruction.
  32. optional google.protobuf.Timestamp max_execution_timestamp = 4;
  33. // [optional] Sequence number of this instruction. Required for SingleEd25519 governance source
  34. // and optional for WomrholeEmitter governance source (because Wormhole has its own sequence
  35. // numbers). If set, it must be greater than 0, and always be increasing, but not required to be
  36. // strictly sequential (i.e. gaps are allowed). Each shard separately keeps track of the last
  37. // executed governance instruction and will reject instructions with the same or smaller
  38. // sequence no. Note that if instructions are received out of order, some of them may become
  39. // permanently rejected (e.g. if instruction #3 has been successfully processed before
  40. // instruction #2 was observed, #2 will always be rejected). Sequence numbers are assigned and
  41. // tracked separately for each governance source.
  42. optional uint32 governance_sequence_no = 5;
  43. }
  44. // Specifies which shards the governance instruction applies to.
  45. message ShardFilter {
  46. // The instruction applies to the specified shards.
  47. message ShardNames {
  48. // Must not be empty.
  49. repeated string shard_names = 1;
  50. }
  51. // The instruction applies to the specified shard groups.
  52. message ShardGroups {
  53. // Must not be empty.
  54. repeated string shard_groups = 1;
  55. }
  56. // [required]
  57. oneof filter {
  58. // The instruction applies to all shards.
  59. google.protobuf.Empty all_shards = 1;
  60. ShardNames shard_names = 2;
  61. ShardGroups shard_groups = 3;
  62. }
  63. }
  64. // An item of a governance instruction.
  65. message GovernanceDirective {
  66. // [required] Specifies which shards the governance instruction applies to.
  67. // The instruction applies to each shard independently of other shards and may apply
  68. // at a different time. The instruction may succeed on some shards and fail on other shards.
  69. // Note that each shard has its own list of governance sources and permissions,
  70. // and a `GovernanceInstruction` is issued by a single source, so multiple instructions
  71. // from different sources may be needed to apply a change to multiple shards or shard groups.
  72. optional ShardFilter shard_filter = 1;
  73. // [required]
  74. // Note: when adding a new variant here, update `Permissions` as well.
  75. oneof action {
  76. CreateShard create_shard = 101;
  77. AddGovernanceSource add_governance_source = 102;
  78. UpdateGovernanceSource update_governance_source = 103;
  79. SetShardName set_shard_name = 104;
  80. SetShardGroup set_shard_group = 105;
  81. ResetLastSequenceNo reset_last_sequence_no = 106;
  82. AddPublisher add_publisher = 107;
  83. UpdatePublisher update_publisher = 108;
  84. AddFeed add_feed = 109;
  85. UpdateFeed update_feed = 110;
  86. }
  87. }
  88. // Permissions granted to a governance source.
  89. // bool fields in this message are optional and default to false (no permission).
  90. message Permissions {
  91. enum ShardAction {
  92. // Required by protobuf. Instruction will be rejected if this value is encountered.
  93. SHARD_ACTION_UNSPECIFIED = 0;
  94. CREATE_SHARD = 101;
  95. ADD_GOVERNANCE_SOURCE = 102;
  96. UPDATE_GOVERNANCE_SOURCE = 103;
  97. SET_SHARD_NAME = 104;
  98. SET_SHARD_GROUP = 105;
  99. RESET_LAST_SEQUENCE_NO = 106;
  100. ADD_PUBLISHER = 107;
  101. ADD_FEED = 109;
  102. }
  103. enum UpdateGovernanceSourceAction {
  104. // Required by protobuf. Instruction will be rejected if this value is encountered.
  105. UPDATE_GOVERNANCE_SOURCE_ACTION_UNSPECIFIED = 0;
  106. SET_GOVERNANCE_SOURCE_PERMISSIONS = 101;
  107. REMOVE_GOVERNANCE_SOURCE = 199;
  108. }
  109. enum UpdatePublisherAction {
  110. // Required by protobuf. Instruction will be rejected if this value is encountered.
  111. UPDATE_PUBLISHER_ACTION_UNSPECIFIED = 0;
  112. SET_PUBLISHER_NAME = 101;
  113. ADD_PUBLISHER_PUBLIC_KEYS = 102;
  114. REMOVE_PUBLISHER_PUBLIC_KEYS = 103;
  115. SET_PUBLISHER_PUBLIC_KEYS = 104;
  116. SET_PUBLISHER_ACTIVE = 105;
  117. REMOVE_PUBLISHER = 199;
  118. }
  119. enum UpdateFeedAction {
  120. // Required by protobuf. Instruction will be rejected if this value is encountered.
  121. UPDATE_FEED_ACTION_UNSPECIFIED = 0;
  122. UPDATE_FEED_METADATA = 101;
  123. ACTIVATE_FEED = 102;
  124. DEACTIVATE_FEED = 103;
  125. REMOVE_FEED = 199;
  126. }
  127. // All operations, including operations added in the future.
  128. optional bool all_actions = 1;
  129. repeated ShardAction shard_actions = 2;
  130. // All operations under `UpdateGovernanceSource` (update and delete),
  131. // including operations added in the future.
  132. optional bool all_update_governance_source_actions = 3;
  133. repeated UpdateGovernanceSourceAction update_governance_source_actions = 4;
  134. // All operations under `UpdatePublisher` (update and delete),
  135. // including operations added in the future.
  136. optional bool all_update_publisher_action = 5;
  137. repeated UpdatePublisherAction update_publisher_actions = 6;
  138. // All operations under `UpdateFeed` (update and delete),
  139. // including operations added in the future.
  140. optional bool all_update_feed_actions = 7;
  141. repeated UpdateFeedAction update_feed_actions = 8;
  142. }
  143. // Specifies the way governance transactions are signed and verified.
  144. message GovernanceSource {
  145. // Governance transactions are signed by a single Ed25519 signature.
  146. // This will generally be used in development and testing groups.
  147. message SingleEd25519 {
  148. // [required] Ed25519 public key that signs governance transactions.
  149. optional bytes public_key = 1;
  150. }
  151. message WormholeEmitter {
  152. // [required] Wormhole emitter address.
  153. optional bytes address = 1;
  154. // [required] Wormhole emitter chain ID. Restricted to uint16.
  155. optional uint32 chain_id = 2;
  156. }
  157. // [required]
  158. oneof source {
  159. SingleEd25519 single_ed25519 = 1;
  160. WormholeEmitter wormhole_emitter = 2;
  161. }
  162. }
  163. // Create a new shard. A shard is a partially isolated part of Lazer that has its own state and
  164. // cannot be directly influenced by other shards. The main purpose of shards in Lazer is
  165. // to allow horizontal scaling when the number of feeds grows. Feeds can be divided into subsets
  166. // and each subset will be assigned to a shard.
  167. //
  168. // Shard name will be determined by the value of `GovernanceDirective.filter`.
  169. // This action will be rejected unless `GovernanceDirective.filter` specified a single shard.
  170. // Shard name must be unique across all shards in all groups.
  171. // (Warning: it's not possible to enforce this rule within a shard!)
  172. message CreateShard {
  173. // [required] ID of the new shard.
  174. // Shard ID must be unique across all shards in all groups.
  175. // (Warning: it's not possible to enforce this rule within a shard!)
  176. optional uint32 shard_id = 1;
  177. // [required] Group name, e.g. "production", "staging", "testing", etc.
  178. // Data from shards belonging to the same group can be joined and served to consumers as a whole.
  179. // Active feed names must be unique within a group, but not across all groups.
  180. optional string shard_group = 2;
  181. // [required] Minimal aggregation rate allowed in this shard.
  182. optional google.protobuf.Duration min_rate = 3;
  183. }
  184. message AddGovernanceSource {
  185. // [required] Governance source that should be added.
  186. optional GovernanceSource new_source = 1;
  187. // [required] Permissions granted to this source.
  188. optional Permissions permissions = 2;
  189. }
  190. message UpdateGovernanceSource {
  191. // [required] Governance source that should be updated. Rejects if there is no such source.
  192. // Rejects if the specified source is the same as the source of the current instruction.
  193. optional GovernanceSource source = 1;
  194. // [required]
  195. // Note: when adding a new variant here, update `Permissions` as well.
  196. oneof action {
  197. SetGovernanceSourcePermissions set_governance_source_permissions = 101;
  198. // Removes a governance source. Note that the last sequence number associated with this source
  199. // will be retained in the state to prevent repeated execution of instructions in case
  200. // the same source is re-added later.
  201. google.protobuf.Empty remove_governance_source = 199;
  202. }
  203. }
  204. message SetGovernanceSourcePermissions {
  205. // [required] Permissions granted to this source. Replaces all previous permissions.
  206. optional Permissions permissions = 1;
  207. }
  208. // Set shard name. This action will be rejected if `GovernanceDirective.shard_names` is empty or contains
  209. // more than one item.
  210. message SetShardName {
  211. // [required] New shard name. Must be unique across all shards in all groups.
  212. // (Warning: it's not possible to enforce this rule within a shard!)
  213. optional string shard_name = 1;
  214. }
  215. // Set shard group. This action will be rejected if `GovernanceDirective.shard_names` is empty or contains
  216. // more than one item.
  217. message SetShardGroup {
  218. // [required] Group name, e.g. "production", "staging", "testing", etc.
  219. // Data from shards belonging to the same group can be joined and served to consumers as a whole.
  220. // Active feed names must be unique within a group, but not across all groups.
  221. optional string shard_group = 1;
  222. }
  223. // Set `last_sequence_no`. This can be used as a workaround in case some updates are lost and
  224. // the services are unable to proceed.
  225. message ResetLastSequenceNo {
  226. optional uint64 last_sequence_no = 1;
  227. }
  228. message AddPublisher {
  229. // [required] Publisher ID. Restricted to uint16. Must be different from existing ids.
  230. optional uint32 publisher_id = 1;
  231. // [required] Publisher name (only for debug/monitoring/management purposes).
  232. // Must be different from existing publisher names.
  233. optional string name = 2;
  234. // Public keys used to sign publisher update transactions.
  235. repeated bytes public_keys = 3;
  236. // [required] If true, the publisher is active, i.e. it's allowed to publish updates.
  237. optional bool is_active = 4;
  238. }
  239. message UpdatePublisher {
  240. // [required] ID of the publisher that is being updated. Rejects if there is no such publisher.
  241. optional uint32 publisher_id = 1;
  242. // [required]
  243. // Note: when adding a new variant here, update `Permissions` as well.
  244. oneof action {
  245. SetPublisherName set_publisher_name = 101;
  246. AddPublisherPublicKeys add_publisher_public_keys = 102;
  247. RemovePublisherPublicKeys remove_publisher_public_keys = 103;
  248. SetPublisherPublicKeys set_publisher_public_keys = 104;
  249. SetPublisherActive set_publisher_active = 105;
  250. google.protobuf.Empty remove_publisher = 199;
  251. }
  252. }
  253. message SetPublisherName {
  254. // [required] New name.
  255. optional string name = 1;
  256. }
  257. // Add new keys.
  258. message AddPublisherPublicKeys {
  259. // Must not be empty.
  260. repeated bytes public_keys = 1;
  261. }
  262. // Remove existing keys.
  263. message RemovePublisherPublicKeys {
  264. // Must not be empty.
  265. repeated bytes public_keys = 1;
  266. }
  267. // Remove all existing public keys and add new keys (if specified).
  268. message SetPublisherPublicKeys {
  269. repeated bytes public_keys = 1;
  270. }
  271. message SetPublisherActive {
  272. // [required]
  273. optional bool is_active = 1;
  274. }
  275. // Feed is inactive when added, meaning that it will be available to publishers but not to consumers.
  276. message AddFeed {
  277. // [required] ID of the feed. Must be unique (within the shard).
  278. optional uint32 feed_id = 1;
  279. // [required] Feed metadata. Some properties are required (name, exponent, etc.).
  280. // Known properties must have the expected type.
  281. // Additional arbitrary properties are allowed.
  282. // (TODO: document known metadata properties)
  283. optional DynamicValue.Map metadata = 2;
  284. // IDs of publishers enabled for this feed.
  285. repeated uint32 permissioned_publishers = 3;
  286. }
  287. message UpdateFeed {
  288. // [required] ID of the feed that is being updated. Rejects if there is no such feed.
  289. optional uint32 feed_id = 1;
  290. // [required]
  291. // Note: when adding a new variant here, update `Permissions` as well.
  292. oneof action {
  293. UpdateFeedMetadata update_feed_metadata = 101;
  294. ActivateFeed activate_feed = 102;
  295. DeactivateFeed deactivate_feed = 103;
  296. google.protobuf.Empty remove_feed = 199;
  297. }
  298. }
  299. message UpdateFeedMetadata {
  300. // [required] Property name.
  301. optional string name = 1;
  302. // [optional] Property value. If unset, the property will be removed.
  303. optional DynamicValue value = 2;
  304. }
  305. // Set the feed as active or shedule an activation.
  306. // If there was already a pending activation or deactivation, it will be cleared
  307. // when this governance instruction is processed.
  308. // Warning: there must never be two feeds with the same name active at the same time
  309. // within a shard group. This cannot be enforced within a shard. When a feed needs to be
  310. // moved between shards, use `activation_timestamp` and `deactivation_timestamp`
  311. // to deactivate it in the old shard and activate it in the new shard at the same time.
  312. message ActivateFeed {
  313. // [optional] If provided, the feed will activate at the specified timestamp.
  314. // If `activation_timestamp` is already passed or if it's unset,
  315. // the feed will be activated immediately when this
  316. // governance instruction is processed.
  317. optional google.protobuf.Timestamp activation_timestamp = 1;
  318. }
  319. // Set the feed as inactive or shedule a deactivation.
  320. // If there was already a pending activation or deactivation, it will be cleared
  321. // when this governance instruction is processed.
  322. // See also: `ActivateFeed` docs.
  323. message DeactivateFeed {
  324. // [optional] If provided, the feed will deactivate at the specified timestamp.
  325. // If `deactivation_timestamp` is already passed or if it's unset,
  326. // the feed will be deactivated immediately when this
  327. // governance instruction is processed.
  328. optional google.protobuf.Timestamp deactivation_timestamp = 1;
  329. }