Skip to content

Commit 7decc41

Browse files
feat(nns): Support SelfDescribingValue::Null (#8205)
# Why To make "empty" values more explicit, we opt to support a `Null` variant to represent absent values. The downside of diverging from ICRC3 was considered. However, if we choose to adopt ICRC3 for proposals in the future (if at all), it will likely affect the entire method (`list_proposals`) rather than the "action" part of the proposal. # What * Introduce a `Null` variant for storage and api * Define conversions between them * Define `impl From<Option<T>> for SelfDescribingValue` using `Null` for `None` * Remove add_field_with_empty_as_fallback as `null` can be used to represent the "emptiness" * Use `null` for some ManageNeuron commands where no content is needed
1 parent e732546 commit 7decc41

File tree

17 files changed

+125
-194
lines changed

17 files changed

+125
-194
lines changed

rs/nns/governance/api/src/types.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4567,6 +4567,7 @@ pub enum SelfDescribingValue {
45674567
Text(String),
45684568
Nat(Nat),
45694569
Int(Int),
4570+
Null,
45704571
Array(Vec<SelfDescribingValue>),
45714572
Map(HashMap<String, SelfDescribingValue>),
45724573
}

rs/nns/governance/canister/governance.did

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,6 +1480,7 @@ type SelfDescribingValue = variant {
14801480
Int : int;
14811481
Array : vec SelfDescribingValue;
14821482
Map : vec record { text; SelfDescribingValue };
1483+
Null;
14831484
};
14841485

14851486
type GetPendingProposalsRequest = record {

rs/nns/governance/derive_self_describing/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,11 @@ fn derive_mixed_enum(name: &Ident, data_enum: &DataEnum) -> Result<TokenStream2,
188188
})
189189
}
190190
Fields::Unit => {
191-
// Unit variant in mixed enum: map with variant name as key, empty array as value
191+
// Unit variant in mixed enum: map with variant name as key, null value as value
192192
Ok(quote! {
193193
#name::#variant_name => {
194194
crate::proposals::self_describing::ValueBuilder::new()
195-
.add_empty_field(#variant_name_str)
195+
.add_field(#variant_name_str, crate::proposals::self_describing::SelfDescribingValue::NULL)
196196
.build()
197197
}
198198
})

rs/nns/governance/proto/ic_nns_governance/pb/v1/governance.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2651,6 +2651,7 @@ message SelfDescribingValue {
26512651
bytes int = 4;
26522652
SelfDescribingValueArray array = 5;
26532653
SelfDescribingValueMap map = 6;
2654+
Empty null = 7;
26542655
}
26552656
}
26562657

rs/nns/governance/src/gen/ic_nns_governance.pb.v1.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4138,7 +4138,7 @@ pub struct FinalizeDisburseMaturity {
41384138
::prost::Message,
41394139
)]
41404140
pub struct SelfDescribingValue {
4141-
#[prost(oneof = "self_describing_value::Value", tags = "1, 2, 3, 4, 5, 6")]
4141+
#[prost(oneof = "self_describing_value::Value", tags = "1, 2, 3, 4, 5, 6, 7")]
41424142
pub value: ::core::option::Option<self_describing_value::Value>,
41434143
}
41444144
/// Nested message and enum types in `SelfDescribingValue`.
@@ -4166,6 +4166,8 @@ pub mod self_describing_value {
41664166
Array(super::SelfDescribingValueArray),
41674167
#[prost(message, tag = "6")]
41684168
Map(super::SelfDescribingValueMap),
4169+
#[prost(message, tag = "7")]
4170+
Null(super::Empty),
41694171
}
41704172
}
41714173
#[derive(

rs/nns/governance/src/pb/conversions/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4202,6 +4202,7 @@ impl From<pb::SelfDescribingValue> for pb_api::SelfDescribingValue {
42024202
.map(|(k, v)| (k, Self::from(v)))
42034203
.collect(),
42044204
),
4205+
pb::self_describing_value::Value::Null(_) => Self::Null,
42054206
}
42064207
}
42074208
}
@@ -4231,6 +4232,9 @@ impl From<pb_api::SelfDescribingValue> for pb::SelfDescribingValue {
42314232
values: v.into_iter().map(|(k, v)| (k, Self::from(v))).collect(),
42324233
})
42334234
}
4235+
pb_api::SelfDescribingValue::Null => {
4236+
pb::self_describing_value::Value::Null(pb::Empty {})
4237+
}
42344238
};
42354239
Self { value: Some(value) }
42364240
}

rs/nns/governance/src/proposals/add_or_remove_node_provider_tests.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,7 @@ fn test_to_self_describing_value() {
281281
SelfDescribingValue::Map(hashmap! {
282282
"ToAdd".to_string() => SelfDescribingValue::Map(hashmap! {
283283
"id".to_string() => SelfDescribingValue::Text("6fyp7-3ibaa-aaaaa-aaaap-4ai".to_string()),
284-
"reward_account".to_string() => SelfDescribingValue::Array(vec![
285-
SelfDescribingValue::Text(account.to_hex())
286-
])
284+
"reward_account".to_string() => SelfDescribingValue::Text(account.to_hex())
287285
})
288286
})
289287
);

rs/nns/governance/src/proposals/deregister_known_neuron.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl LocallyDescribableProposalAction for DeregisterKnownNeuron {
6060

6161
fn to_self_describing_value(&self) -> SelfDescribingValue {
6262
ValueBuilder::new()
63-
.add_field_with_empty_as_fallback("neuron_id", self.id.map(|id| id.id))
63+
.add_field("neuron_id", self.id.map(|id| id.id))
6464
.build()
6565
}
6666
}

rs/nns/governance/src/proposals/install_code.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,10 @@ impl LocallyDescribableProposalAction for InstallCode {
187187
let install_mode = install_mode.map(SelfDescribingProstEnum::<CanisterInstallMode>::new);
188188

189189
ValueBuilder::new()
190-
.add_field_with_empty_as_fallback("canister_id", *canister_id)
191-
.add_field_with_empty_as_fallback("install_mode", install_mode)
192-
.add_field_with_empty_as_fallback("wasm_module_hash", wasm_module_hash.clone())
193-
.add_field_with_empty_as_fallback("arg_hash", arg_hash.clone())
190+
.add_field("canister_id", *canister_id)
191+
.add_field("install_mode", install_mode)
192+
.add_field("wasm_module_hash", wasm_module_hash.clone())
193+
.add_field("arg_hash", arg_hash.clone())
194194
.add_field(
195195
"skip_stopping_before_installing",
196196
skip_stopping_before_installing.unwrap_or_default(),

rs/nns/governance/src/proposals/manage_neuron.rs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,11 @@ impl LocallyDescribableProposalAction for ManageNeuron {
5151
"A ManageNeuron proposal is created with an empty or conflicting \
5252
values of id and neuron_id_or_subaccount. This should never happen."
5353
);
54-
builder.add_empty_field("neuron_id_or_subaccount")
54+
builder.add_field("neuron_id_or_subaccount", SelfDescribingValue::NULL)
5555
}
5656
};
5757

58-
builder
59-
.add_field_with_empty_as_fallback("command", self.command.clone())
60-
.build()
58+
builder.add_field("command", self.command.clone()).build()
6159
}
6260
}
6361

@@ -99,13 +97,13 @@ impl From<Command> for SelfDescribingValue {
9997
println!(
10098
"A ManageNeuron proposal is created with a MergeMaturity command. This should never happen."
10199
);
102-
Self::singleton_map("MergeMaturity", Self::EMPTY)
100+
Self::singleton_map("MergeMaturity", Self::NULL)
103101
}
104102
C::MakeProposal(_) => {
105103
println!(
106104
"A ManageNeuron proposal is created with a MakeProposal command. This should never happen."
107105
);
108-
Self::singleton_map("MakeProposal", Self::EMPTY)
106+
Self::singleton_map("MakeProposal", Self::NULL)
109107
}
110108
}
111109
}
@@ -117,7 +115,7 @@ impl From<Configure> for SelfDescribingValue {
117115
println!(
118116
"A ManageNeuron proposal is created with an empty operation. This should never happen."
119117
);
120-
return Self::EMPTY;
118+
return Self::NULL;
121119
};
122120

123121
use Operation as O;
@@ -161,14 +159,14 @@ impl From<IncreaseDissolveDelay> for SelfDescribingValue {
161159
impl From<StartDissolving> for SelfDescribingValue {
162160
fn from(value: StartDissolving) -> Self {
163161
let StartDissolving {} = value;
164-
SelfDescribingValue::EMPTY
162+
SelfDescribingValue::NULL
165163
}
166164
}
167165

168166
impl From<StopDissolving> for SelfDescribingValue {
169167
fn from(value: StopDissolving) -> Self {
170168
let StopDissolving {} = value;
171-
SelfDescribingValue::EMPTY
169+
SelfDescribingValue::NULL
172170
}
173171
}
174172

@@ -198,14 +196,14 @@ impl From<SetDissolveTimestamp> for SelfDescribingValue {
198196
impl From<JoinCommunityFund> for SelfDescribingValue {
199197
fn from(value: JoinCommunityFund) -> Self {
200198
let JoinCommunityFund {} = value;
201-
SelfDescribingValue::EMPTY
199+
SelfDescribingValue::NULL
202200
}
203201
}
204202

205203
impl From<LeaveCommunityFund> for SelfDescribingValue {
206204
fn from(value: LeaveCommunityFund) -> Self {
207205
let LeaveCommunityFund {} = value;
208-
SelfDescribingValue::EMPTY
206+
SelfDescribingValue::NULL
209207
}
210208
}
211209

@@ -320,7 +318,7 @@ impl From<ClaimOrRefresh> for SelfDescribingValue {
320318
println!(
321319
"A ManageNeuron proposal is created with an empty by. This should never happen."
322320
);
323-
return Self::EMPTY;
321+
return Self::NULL;
324322
};
325323

326324
match by {
@@ -359,7 +357,7 @@ impl From<Merge> for SelfDescribingValue {
359357
impl From<RefreshVotingPower> for SelfDescribingValue {
360358
fn from(value: RefreshVotingPower) -> Self {
361359
let RefreshVotingPower {} = value;
362-
SelfDescribingValue::EMPTY
360+
SelfDescribingValue::NULL
363361
}
364362
}
365363

0 commit comments

Comments
 (0)