Skip to content

Commit 4e98a9b

Browse files
authored
feat: write plutus data v1 for permissioned candidates and registrations (#923)
1 parent 05a8778 commit 4e98a9b

File tree

5 files changed

+173
-67
lines changed

5 files changed

+173
-67
lines changed

toolkit/data-sources/db-sync/testdata/migrations/6_insert_transactions.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ registration_SPO_C jsonb := '
9494
{"bytes": "1fd2f1e5ad14c829c7359474764701cd74ab9c433c29b0bbafaa6bcf22376e9d651391d08ae6f40b418d2abf827c4c1fcb007e779a2beba7894d68012942c708"}
9595
]
9696
},
97-
{"list": [{"bytes": "63726368"}, {"bytes": "02333e47cab242fefe88d7da1caa713307290291897f100efb911672d317147f72"}]},
97+
{"bytes": "02333e47cab242fefe88d7da1caa713307290291897f100efb911672d317147f72"},
9898
{"bytes": "3e8a8b29e513a08d0a66e22422a1a85d1bf409987f30a8c6fcab85ba38a85d0d27793df7e7fb63ace12203b062feb7edb5e6664ac1810b94c38182acc6167425"},
9999
{
100100
"constructor": 0,
@@ -306,14 +306,14 @@ DO $$
306306
{"constructor": 0, "fields": [] },
307307
{"list": [
308308
{"list": [
309-
{"list":[{"bytes": "63726368"}, {"bytes": "cb6df9de1efca7a3998a8ead4e02159d5fa99c3e0d4fd6432667390bb4726854"}]},
309+
{"bytes": "cb6df9de1efca7a3998a8ead4e02159d5fa99c3e0d4fd6432667390bb4726854"},
310310
{"list":[
311311
{"list":[{"bytes": "61757261"}, {"bytes": "bf20afa1c1a72af3341fa7a447e3f9eada9f3d054a7408fb9e49ad4d6e6559ec"}]},
312312
{"list":[{"bytes": "6772616e"}, {"bytes": "9042a40b0b1baa9adcead024432a923eac706be5e1a89d7f2f2d58bfa8f3c26d"}]}
313313
]}
314314
]},
315315
{"list": [
316-
{"list":[{"bytes": "63726368"}, {"bytes": "79c3b7fc0b7697b9414cb87adcb37317d1cab32818ae18c0e97ad76395d1fdcf"}]},
316+
{"bytes": "79c3b7fc0b7697b9414cb87adcb37317d1cab32818ae18c0e97ad76395d1fdcf"},
317317
{"list":[
318318
{"list":[{"bytes": "61757261"}, {"bytes": "56d1da82e56e4cb35b13de25f69a3e9db917f3e13d6f786321f4b0a9dc153b19"}]},
319319
{"list":[{"bytes": "6772616e"}, {"bytes": "7392f3ea668aa2be7997d82c07bcfbec3ee4a9a4e01e3216d92b8f0d0a086c32"}]}

toolkit/sidechain/domain/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,11 @@ impl CandidateKeys {
12261226
pub fn find_or_empty(&self, id: KeyTypeId) -> Vec<u8> {
12271227
self.find(id).unwrap_or_default()
12281228
}
1229+
1230+
/// True for keys that are only AURA and Grandpa
1231+
pub fn has_only_aura_and_grandpa_keys(&self) -> bool {
1232+
self.0.len() == 2 && self.find(AURA).is_some() && self.find(GRANDPA).is_some()
1233+
}
12291234
}
12301235

12311236
impl From<Vec<([u8; 4], Vec<u8>)>> for CandidateKeys {

toolkit/smart-contracts/plutus-data/src/permissioned_candidates.rs

Lines changed: 129 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,15 @@ impl From<PermissionedCandidateDatumV1> for PermissionedCandidateData {
3232
// with T: OpaqueKeys, this function will be re-implemented.
3333
fn from(value: PermissionedCandidateDatumV1) -> Self {
3434
let PermissionedCandidateDatumV1 { partner_chains_key, keys } = value;
35-
let sidechain_public_key = SidechainPublicKey(partner_chains_key.bytes);
36-
PermissionedCandidateData { sidechain_public_key, keys }
35+
PermissionedCandidateData { sidechain_public_key: partner_chains_key, keys }
3736
}
3837
}
3938

4039
#[derive(Clone, Debug, PartialEq)]
4140
/// Datum representing a permissioned candidate with arbitrary set of keys
4241
pub struct PermissionedCandidateDatumV1 {
4342
/// Partner Chains key identifier and bytes
44-
pub partner_chains_key: CandidateKey,
43+
pub partner_chains_key: SidechainPublicKey,
4544
/// Represents arbitrary set of keys with 4 character identifier
4645
pub keys: CandidateKeys,
4746
}
@@ -75,11 +74,12 @@ impl From<PermissionedCandidateDatums> for Vec<PermissionedCandidateData> {
7574
}
7675

7776
/// Converts a list of [PermissionedCandidateData] values to [VersionedGenericDatum] encoded as [PlutusData].
78-
///
77+
/// Version 0 is used for specific set of Partner Chains Key: partner chains key, AURA, Grandpa
78+
/// If other set of key is used, then version 1 is used.
7979
/// Encoding:
8080
/// ```ignore
8181
/// VersionedGenericDatum:
82-
/// - datum: ()
82+
/// - datum: Constr 0 []
8383
/// - appendix:
8484
/// [
8585
/// [ candidates[0].sidechain_public_key
@@ -94,31 +94,89 @@ impl From<PermissionedCandidateDatums> for Vec<PermissionedCandidateData> {
9494
/// // etc.
9595
/// ]
9696
/// - version: 0
97+
/// or:
98+
/// VersionedGenericDatum:
99+
/// - datum: Constr 0 []
100+
/// - appendix:
101+
/// [
102+
/// [ candidates[0].sidechain_public_key
103+
/// ,
104+
/// [
105+
/// [ candidates[0].keys[0].id,
106+
/// , candidates[0].keys[0].bytes
107+
/// ]
108+
/// , [ candidates[0].keys[1].id,
109+
/// , candidates[0].keys[1].bytes
110+
/// ]
111+
/// // etc.
112+
/// ]
113+
/// ]
114+
/// ,
115+
/// [ candidates[1].sidechain_public_key
116+
/// ,
117+
/// [
118+
/// [ candidates[1].keys[0].id,
119+
/// , candidates[1].keys[0].bytes
120+
/// ]
121+
/// , [ candidates[1].keys[1].id,
122+
/// , candidates[1].keys[1].bytes
123+
/// ]
124+
/// // etc.
125+
/// ]
126+
/// ]
127+
/// // etc.
128+
/// ]
129+
/// - version: 1
97130
/// ```
131+
98132
pub fn permissioned_candidates_to_plutus_data(
99133
candidates: &[PermissionedCandidateData],
100134
) -> PlutusData {
101-
let mut list = PlutusList::new();
102-
for candidate in candidates {
103-
let mut candidate_datum = PlutusList::new();
104-
candidate_datum.add(&PlutusData::new_bytes(candidate.sidechain_public_key.0.clone()));
105-
for key in candidate.keys.0.iter() {
106-
candidate_datum.add(&PlutusData::new_bytes(key.bytes.clone()));
135+
fn candidates_to_plutus_data_v0(candidates: &[PermissionedCandidateData]) -> PlutusData {
136+
let mut list = PlutusList::new();
137+
for candidate in candidates {
138+
let mut candidate_datum = PlutusList::new();
139+
candidate_datum.add(&PlutusData::new_bytes(candidate.sidechain_public_key.0.clone()));
140+
for key in candidate.keys.0.iter() {
141+
candidate_datum.add(&PlutusData::new_bytes(key.bytes.clone()));
142+
}
143+
list.add(&PlutusData::new_list(&candidate_datum));
144+
}
145+
let appendix = PlutusData::new_list(&list);
146+
VersionedGenericDatum {
147+
datum: PlutusData::new_empty_constr_plutus_data(&BigNum::zero()),
148+
appendix,
149+
version: 0,
107150
}
108-
list.add(&PlutusData::new_list(&candidate_datum));
151+
.into()
109152
}
110-
let appendix = PlutusData::new_list(&list);
111-
VersionedGenericDatum {
112-
datum: PlutusData::new_empty_constr_plutus_data(&BigNum::zero()),
113-
appendix,
114-
version: 0,
153+
154+
fn candidates_to_plutus_data_v1(candidates: &[PermissionedCandidateData]) -> PlutusData {
155+
let mut list = PlutusList::new();
156+
for candidate in candidates {
157+
let mut candidate_datum = PlutusList::new();
158+
candidate_datum.add(&PlutusData::new_bytes(candidate.sidechain_public_key.0.clone()));
159+
candidate_datum.add(&candidate_keys_to_plutus(&candidate.keys));
160+
list.add(&PlutusData::new_list(&candidate_datum));
161+
}
162+
VersionedGenericDatum {
163+
datum: PlutusData::new_empty_constr_plutus_data(&BigNum::zero()),
164+
appendix: PlutusData::new_list(&list),
165+
version: 1,
166+
}
167+
.into()
168+
}
169+
170+
if candidates.iter().all(|c| c.keys.has_only_aura_and_grandpa_keys()) {
171+
candidates_to_plutus_data_v0(candidates)
172+
} else {
173+
candidates_to_plutus_data_v1(candidates)
115174
}
116-
.into()
117175
}
118176

119177
impl PermissionedCandidateDatums {
120178
/// Parses plutus data schema in accordance with V1 schema
121-
fn decode_v1(data: &PlutusData) -> Result<Self, String> {
179+
fn decode_v1_appendix(data: &PlutusData) -> Result<Self, String> {
122180
let permissioned_candidates = data
123181
.as_list()
124182
.and_then(|list_datums| {
@@ -156,9 +214,10 @@ impl VersionedDatumWithLegacy for PermissionedCandidateDatums {
156214
appendix: &PlutusData,
157215
) -> Result<Self, String> {
158216
match version {
217+
// v0 appendix is the same as legacy format of whole plutus data
159218
0 => PermissionedCandidateDatums::decode_legacy(appendix)
160219
.map_err(|msg| format!("Cannot parse appendix: {msg}")),
161-
1 => PermissionedCandidateDatums::decode_v1(appendix)
220+
1 => PermissionedCandidateDatums::decode_v1_appendix(appendix)
162221
.map_err(|msg| format!("Cannot parse appendix: {msg}")),
163222
_ => Err(format!("Unknown version: {version}")),
164223
}
@@ -184,7 +243,7 @@ fn decode_legacy_candidate_datum(datum: &PlutusData) -> Option<PermissionedCandi
184243
fn decode_v1_candidate_datum(datum: &PlutusData) -> Option<PermissionedCandidateDatumV1> {
185244
// The first element has Partner Chains key, second contains all other keys
186245
let outer_list = datum.as_list().filter(|l| l.len() == 2)?;
187-
let partner_chains_key = decode_candidate_key(&outer_list.get(0))?;
246+
let partner_chains_key = SidechainPublicKey(outer_list.get(0).as_bytes()?);
188247
let keys = decode_candidate_keys(&outer_list.get(1))?;
189248
Some(PermissionedCandidateDatumV1 { partner_chains_key, keys })
190249
}
@@ -267,14 +326,14 @@ mod tests {
267326
{ "constructor": 0, "fields": [] },
268327
{"list": [
269328
{"list":[
270-
{"list": [{"bytes": hex::encode(b"crch")}, {"bytes": "cb6df9de1efca7a3998a8ead4e02159d5fa99c3e0d4fd6432667390bb4726854"}]},
329+
{"bytes": "cb6df9de1efca7a3998a8ead4e02159d5fa99c3e0d4fd6432667390bb4726854"},
271330
{"list": [
272331
{"list": [{"bytes": hex::encode(b"aura")}, {"bytes": "bf20afa1c1a72af3341fa7a447e3f9eada9f3d054a7408fb9e49ad4d6e6559ec"}]},
273332
{"list": [{"bytes": hex::encode(b"gran")}, {"bytes": "9042a40b0b1baa9adcead024432a923eac706be5e1a89d7f2f2d58bfa8f3c26d"}]}
274333
]}
275334
]},
276335
{"list":[
277-
{"list": [{"bytes": hex::encode(b"crch")}, {"bytes": "79c3b7fc0b7697b9414cb87adcb37317d1cab32818ae18c0e97ad76395d1fdcf"}]},
336+
{"bytes": "79c3b7fc0b7697b9414cb87adcb37317d1cab32818ae18c0e97ad76395d1fdcf"},
278337
{"list": [
279338
{"list": [{"bytes": hex::encode(b"aura")}, {"bytes": "56d1da82e56e4cb35b13de25f69a3e9db917f3e13d6f786321f4b0a9dc153b19"}]},
280339
{"list": [{"bytes": hex::encode(b"gran")}, {"bytes": "7392f3ea668aa2be7997d82c07bcfbec3ee4a9a4e01e3216d92b8f0d0a086c32"}]}
@@ -287,7 +346,7 @@ mod tests {
287346
}
288347

289348
#[test]
290-
fn test_permissioned_candidates_to_plutus_data() {
349+
fn permissioned_candidates_to_plutus_data_outputs_v0_for_aura_and_grandpa_keys() {
291350
let expected_plutus_data = json_to_plutus_data(v0_datum_json());
292351

293352
let domain_data = vec![
@@ -331,6 +390,50 @@ mod tests {
331390
assert_eq!(permissioned_candidates_to_plutus_data(&domain_data), expected_plutus_data)
332391
}
333392

393+
#[test]
394+
fn permissioned_candidates_to_plutus_data_outputs_v1() {
395+
let domain_data = vec![
396+
PermissionedCandidateData {
397+
sidechain_public_key: SidechainPublicKey([1; 33].to_vec()),
398+
keys: CandidateKeys(vec![
399+
CandidateKey { id: [2; 4], bytes: [3; 32].to_vec() },
400+
CandidateKey { id: [4; 4], bytes: [5; 32].to_vec() },
401+
]),
402+
},
403+
PermissionedCandidateData {
404+
sidechain_public_key: SidechainPublicKey([6; 33].to_vec()),
405+
keys: CandidateKeys(vec![
406+
CandidateKey { id: [7; 4], bytes: [8; 32].to_vec() },
407+
CandidateKey { id: [9; 4], bytes: [10u8; 32].to_vec() },
408+
]),
409+
},
410+
];
411+
let json = serde_json::json!({
412+
"list": [
413+
{ "constructor": 0, "fields": [] },
414+
{"list": [
415+
{"list":[
416+
{"bytes": "010101010101010101010101010101010101010101010101010101010101010101"},
417+
{"list": [
418+
{"list": [{"bytes": "02020202"}, {"bytes": "0303030303030303030303030303030303030303030303030303030303030303"}]},
419+
{"list": [{"bytes": "04040404"}, {"bytes": "0505050505050505050505050505050505050505050505050505050505050505"}]}
420+
]}
421+
]},
422+
{"list":[
423+
{"bytes": "060606060606060606060606060606060606060606060606060606060606060606"},
424+
{"list": [
425+
{"list": [{"bytes": "07070707"}, {"bytes": "0808080808080808080808080808080808080808080808080808080808080808"}]},
426+
{"list": [{"bytes": "09090909"}, {"bytes": "0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"}]}
427+
]}
428+
]}
429+
]},
430+
{ "int": 1 }
431+
]
432+
});
433+
let expected_plutus_data = json_to_plutus_data(json);
434+
assert_eq!(permissioned_candidates_to_plutus_data(&domain_data), expected_plutus_data)
435+
}
436+
334437
#[test]
335438
fn valid_v0_permissioned_candidates() {
336439
let plutus_data = json_to_plutus_data(v0_datum_json());
@@ -369,8 +472,7 @@ mod tests {
369472

370473
let expected_datum = PermissionedCandidateDatums::V1(vec![
371474
PermissionedCandidateDatumV1 {
372-
partner_chains_key: CandidateKey::new(
373-
CROSS_CHAIN_KEY_TYPE_ID,
475+
partner_chains_key: SidechainPublicKey(
374476
hex!("cb6df9de1efca7a3998a8ead4e02159d5fa99c3e0d4fd6432667390bb4726854").into(),
375477
),
376478
keys: CandidateKeys(vec![
@@ -387,8 +489,7 @@ mod tests {
387489
]),
388490
},
389491
PermissionedCandidateDatumV1 {
390-
partner_chains_key: CandidateKey::new(
391-
CROSS_CHAIN_KEY_TYPE_ID,
492+
partner_chains_key: SidechainPublicKey(
392493
hex!("79c3b7fc0b7697b9414cb87adcb37317d1cab32818ae18c0e97ad76395d1fdcf").into(),
393494
),
394495
keys: CandidateKeys(vec![

0 commit comments

Comments
 (0)