Skip to content

Commit 6505c83

Browse files
Move opa bootstrap into genesis, use substrate keystore / vault for opa root key storage
Signed-off-by: Ryan <ryan.roberts@btp.works>
1 parent 97635a7 commit 6505c83

File tree

18 files changed

+130
-114
lines changed

18 files changed

+130
-114
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/chronicle-arrow/src/query/activity.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ pub async fn load_activities_by_type(
299299
.on(activity::id.eq(activity_block_info::activity_id)),
300300
)
301301
.filter(activity::domaintype.eq(typ_value.external_id_part()))
302-
.order(activity_block_info::block_time)
302+
.order(activity_block_info::block_time.desc())
303303
.select((Activity::as_select(), Namespace::as_select()))
304304
.offset(position as i64)
305305
.limit(max_records as i64)
@@ -313,7 +313,7 @@ pub async fn load_activities_by_type(
313313
.on(activity::id.eq(activity_block_info::activity_id)),
314314
)
315315
.filter(activity::domaintype.is_null())
316-
.order(activity_block_info::block_time)
316+
.order(activity_block_info::block_time.desc())
317317
.select((Activity::as_select(), Namespace::as_select()))
318318
.offset(position as i64)
319319
.limit(max_records as i64)

crates/chronicle-persistence/src/queryable.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,6 @@ pub struct Entity {
3030
pub domaintype: Option<String>,
3131
}
3232

33-
#[derive(Queryable, Selectable, SimpleObject)]
34-
#[diesel(table_name = crate::schema::entity_block_info)]
35-
pub struct EntityBlockInfo {
36-
pub entity_id: i32,
37-
pub block_time: Option<NaiveDateTime>,
38-
pub block_hash: Option<String>,
39-
}
40-
4133
#[derive(Default, Queryable)]
4234
pub struct Namespace {
4335
_id: i32,

crates/chronicle/src/bootstrap/cli.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ impl CliError {
174174
}
175175
}
176176

177-
/// Ugly but we need this until ! is stable, see <https://github.com/rust-lang/rust/issues/64715>
178177
impl From<Infallible> for CliError {
179178
fn from(_: Infallible) -> Self {
180179
unreachable!()
@@ -372,8 +371,6 @@ fn attributes_from(
372371

373372
impl SubCommand for AgentCliModel {
374373
fn as_cmd(&self) -> Command {
375-
let cmd = Command::new(&*self.external_id).about(&*self.about);
376-
377374
let mut define = Command::new("define")
378375
.about(&*self.define_about)
379376
.arg(Arg::new("external_id")

crates/common/src/opa/core.rs

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,6 @@ impl AsRef<[u8]> for KeyAddress {
136136
}
137137
}
138138

139-
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
140-
// This message is used to bootstrap the root key for a newly created authz tp,
141-
// it can only be executed once
142-
pub struct BootstrapRoot {
143-
pub public_key: PemEncoded,
144-
}
145-
146139
#[cfg_attr(
147140
feature = "parity-encoding",
148141
derive(
@@ -153,8 +146,7 @@ pub struct BootstrapRoot {
153146
scale_decode::DecodeAsType,
154147
)
155148
)]
156-
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize,))]
157-
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
149+
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq, Hash)]
158150
pub struct PemEncoded(String);
159151

160152
impl PemEncoded {
@@ -242,7 +234,6 @@ pub struct OpaSubmission {
242234

243235
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
244236
pub enum Payload {
245-
BootstrapRoot(BootstrapRoot),
246237
SignedOperation(SignedOperation),
247238
}
248239

@@ -522,7 +513,6 @@ pub mod codec {
522513

523514
#[derive(Encode, EncodeAsType, DecodeAsType, Decode, Debug, TypeInfo, Clone, PartialEq, Eq)]
524515
pub enum PayloadV1 {
525-
BootstrapRoot(BootstrapRootV1),
526516
SignedOperation(SignedOperationV1),
527517
}
528518

@@ -582,23 +572,9 @@ pub mod codec {
582572
}
583573
}
584574

585-
impl From<codec::BootstrapRootV1> for BootstrapRoot {
586-
fn from(item: codec::BootstrapRootV1) -> Self {
587-
Self { public_key: item.public_key }
588-
}
589-
}
590-
591-
impl From<BootstrapRoot> for codec::BootstrapRootV1 {
592-
fn from(item: BootstrapRoot) -> Self {
593-
tracing::debug!(target: "codec_conversion", "Converting BootstrapRoot to BootstrapRootV1");
594-
Self { public_key: item.public_key }
595-
}
596-
}
597-
598575
impl From<codec::PayloadV1> for Payload {
599576
fn from(item: codec::PayloadV1) -> Self {
600577
match item {
601-
codec::PayloadV1::BootstrapRoot(v) => Self::BootstrapRoot(v.into()),
602578
codec::PayloadV1::SignedOperation(v) => Self::SignedOperation(v.into()),
603579
}
604580
}
@@ -623,10 +599,6 @@ pub mod codec {
623599
correlation_id: item.correlation_id,
624600
span_id: item.span_id,
625601
payload: match item.payload {
626-
Payload::BootstrapRoot(v) => {
627-
tracing::trace!(target: "codec_conversion", "Payload is BootstrapRoot");
628-
codec::PayloadV1::BootstrapRoot(v.into())
629-
},
630602
Payload::SignedOperation(v) => {
631603
tracing::trace!(target: "codec_conversion", "Payload is SignedOperation");
632604
codec::PayloadV1::SignedOperation(v.into())

crates/common/src/prov/model/proptest.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,5 +605,8 @@ proptest! {
605605
let lhs_json_2 = compact_json(&prov).clone();
606606
prop_assert_eq!( lhs_json.clone().to_string(), lhs_json_2.to_string());
607607
}
608+
609+
610+
608611
}
609612
}

crates/embedded-substrate/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use protocol_substrate::SubxtClientError;
33
use protocol_substrate_chronicle::ChronicleSubstrateClient;
44
use sc_cli::{print_node_infos, CliConfiguration, Signals, SubstrateCli};
55
use subxt::{
6-
config::ExtrinsicParams,
76
ext::futures::{pin_mut, FutureExt},
87
};
98
use tempfile::TempDir;

crates/opactl/src/cli.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,6 @@ fn wait_args(command: Command) -> Command {
3232
)
3333
}
3434

35-
fn bootstrap() -> Command {
36-
wait_args(
37-
Command::new("bootstrap")
38-
.about("Initialize the OPA transaction processor with a root key from the keystore")
39-
.arg(batcher_key()),
40-
)
41-
}
42-
4335
fn generate() -> Command {
4436
Command::new("generate")
4537
.arg(Arg::new("output").short('o').long("output").num_args(0..=1).help(
@@ -306,7 +298,6 @@ pub fn cli() -> Command {
306298
.env("SAWTOOTH_ADDRESS")
307299
.default_value("tcp://localhost:4004"),
308300
)
309-
.subcommand(bootstrap())
310301
.subcommand(generate())
311302
.subcommand(rotate_root())
312303
.subcommand(register_key())

crates/opactl/src/main.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -251,17 +251,6 @@ async fn dispatch_args<
251251
let _entered = span.enter();
252252
let span_id = span.id().map(|x| x.into_u64()).unwrap_or(u64::MAX);
253253
match matches.subcommand() {
254-
Some(("bootstrap", command_matches)) => {
255-
let signing = configure_signing(vec![], &matches, command_matches).await?;
256-
let bootstrap = SubmissionBuilder::bootstrap_root(signing.opa_verifying().await?)
257-
.build(span_id, Uuid::new_v4());
258-
Ok(handle_wait(
259-
command_matches,
260-
client,
261-
OpaTransaction::bootstrap_root(bootstrap, &signing).await?,
262-
)
263-
.await?)
264-
},
265254
Some(("generate", matches)) => {
266255
let key = SecretKey::random(StdRng::from_entropy());
267256
let key = key.to_pkcs8_pem(LineEnding::CRLF).map_err(|_| OpaCtlError::Pkcs8)?;

crates/opactl/src/test/mockchain.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ impl frame_system::Config for Test {
5151

5252
impl pallet_timestamp::Config for Test {
5353
type MinimumPeriod = ConstU64<1>;
54+
type Moment = u64;
5455
type OnTimestampSet = ();
5556
type WeightInfo = ();
56-
type Moment = u64;
5757
}
5858

5959
impl pallet_opa::Config for Test {
@@ -62,7 +62,40 @@ impl pallet_opa::Config for Test {
6262
type WeightInfo = ();
6363
}
6464

65+
use k256::SecretKey;
66+
use rand::rngs::StdRng;
67+
use rand_core::SeedableRng;
68+
69+
pub struct GenesisConfig {
70+
pub root_key: SecretKey,
71+
}
72+
73+
impl Default for GenesisConfig {
74+
fn default() -> Self {
75+
let root_key = SecretKey::random(StdRng::from_seed([0u8; 32]));
76+
GenesisConfig { root_key }
77+
}
78+
}
79+
80+
impl GenesisConfig {
81+
pub fn build_storage(&self) -> sp_io::TestExternalities {
82+
use k256::pkcs8::EncodePublicKey;
83+
let mut storage = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
84+
// Insert the root key into the storage
85+
storage.top.insert(
86+
b"pallet_opa::root_key".to_vec(),
87+
self.root_key
88+
.public_key()
89+
.to_public_key_pem(k256::pkcs8::LineEnding::CRLF)
90+
.unwrap()
91+
.as_bytes()
92+
.to_vec(),
93+
);
94+
storage.into()
95+
}
96+
}
97+
6598
// Build genesis storage according to the mock runtime.
6699
pub fn new_test_ext() -> sp_io::TestExternalities {
67-
frame_system::GenesisConfig::<Test>::default().build_storage().unwrap().into()
100+
GenesisConfig::default().build_storage()
68101
}

crates/pallet-opa/src/lib.rs

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use common::{
88
k256::ecdsa::{Signature, VerifyingKey},
99
opa::{
1010
codec::{NewPublicKeyV1, OpaSubmissionV1, PayloadV1, SignedOperationV1},
11-
BootstrapRoot, KeyAddress, KeyRegistration, Keys, OpaSubmission, Operation, Payload,
12-
PolicyAddress, PolicyMeta, PolicyMetaAddress, RegisterKey, RotateKey, SetPolicy,
13-
SignedOperation, SignedOperationPayload,
11+
KeyAddress, KeyRegistration, Keys, OpaSubmission, Operation, Payload, PolicyAddress,
12+
PolicyMeta, PolicyMetaAddress, RegisterKey, RotateKey, SetPolicy, SignedOperation,
13+
SignedOperationPayload,
1414
},
1515
};
1616

@@ -71,7 +71,6 @@ fn verify_signed_operation<T: Config>(
7171
) -> Result<(), OpaError> {
7272
use k256::ecdsa::signature::Verifier;
7373
match &submission.payload {
74-
PayloadV1::BootstrapRoot(_) => Ok(()),
7574
PayloadV1::SignedOperation(SignedOperationV1 { payload, verifying_key, signature }) => {
7675
if root_keys.is_none() {
7776
error!("No registered root keys for signature verification");
@@ -111,31 +110,7 @@ fn apply_signed_operation<T: Config>(
111110
correlation_id: ChronicleTransactionId,
112111
payload: Payload,
113112
) -> Result<(), OpaError> {
114-
use scale_info::prelude::string::ToString;
115113
match payload {
116-
Payload::BootstrapRoot(BootstrapRoot { public_key }) => {
117-
let existing_key = pallet::KeyStore::<T>::try_get(key_address("root"));
118-
119-
if existing_key.is_ok() {
120-
error!("OPA TP has already been bootstrapped");
121-
return Err(OpaError::InvalidOperation);
122-
}
123-
124-
let keys = Keys {
125-
id: "root".to_string(),
126-
current: KeyRegistration { key: public_key, version: 0 },
127-
expired: None,
128-
};
129-
130-
pallet::KeyStore::<T>::set(key_address("root"), Some(keys.clone().into()));
131-
132-
pallet::Pallet::<T>::deposit_event(pallet::Event::<T>::KeyUpdate(
133-
keys.into(),
134-
correlation_id,
135-
));
136-
137-
Ok(())
138-
},
139114
Payload::SignedOperation(SignedOperation {
140115
payload: SignedOperationPayload { operation },
141116
verifying_key: _,
@@ -291,9 +266,23 @@ fn root_keys_from_state<T: Config>() -> Result<Option<Keys>, OpaError> {
291266
#[frame_support::pallet]
292267
pub mod pallet {
293268
use super::*;
269+
use common::opa::PemEncoded;
294270
use frame_support::pallet_prelude::*;
295271
use frame_system::pallet_prelude::*;
296272

273+
/// Genesis configuration, whether or not we need to enforce OPA policies
274+
#[pallet::genesis_config]
275+
pub struct GenesisConfig<T: Config> {
276+
pub root_account: Option<PemEncoded>,
277+
pub _phantom: PhantomData<T>,
278+
}
279+
280+
impl<T: Config> Default for GenesisConfig<T> {
281+
fn default() -> Self {
282+
Self { root_account: None, _phantom: PhantomData }
283+
}
284+
}
285+
297286
#[pallet::pallet]
298287
pub struct Pallet<T>(_);
299288

@@ -355,13 +344,31 @@ pub mod pallet {
355344
}
356345
}
357346

347+
#[pallet::genesis_build]
348+
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
349+
fn build(&self) {
350+
use scale_info::prelude::string::ToString;
351+
if let Some(key) = &self.root_account {
352+
pallet::KeyStore::<T>::set(
353+
key_address("root"),
354+
Some(
355+
Keys {
356+
id: "root".to_string(),
357+
current: KeyRegistration { key: key.clone(), version: 0 },
358+
expired: None,
359+
}
360+
.into(),
361+
),
362+
);
363+
}
364+
}
365+
}
366+
358367
// Dispatchable functions allows users to interact with the pallet and invoke state changes.
359368
// These functions materialize as "extrinsics", which are often compared to transactions.
360369
// Dispatchable functions must be annotated with a weight and must return a DispatchResult.
361370
#[pallet::call]
362371
impl<T: Config> Pallet<T> {
363-
// Apply a vector of chronicle operations, yielding an event that indicates state change or
364-
// contradiction
365372
#[pallet::call_index(0)]
366373
#[pallet::weight(T::WeightInfo::apply())]
367374
pub fn apply(origin: OriginFor<T>, submission: T::OpaSubmission) -> DispatchResult {

0 commit comments

Comments
 (0)