Extract the top pool operation execution into separate modules - #500

Merged
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution
Nov 11, 2021
Merged

Extract the top pool operation execution into separate modules#500
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution

Conversation

@murerfel

@murerfelmurerfel commented Nov 10, 2021

Copy link
Copy Markdown
Contributor

Created new traits/components that execute the trusted operations from the top pool.
Also separated the execution and block/confirmation composition.

The is in preparation for moving these parts into the sidechain crate.

Comment on lines +44 to +64
pub trait ComposeBlockAndConfirmation {
type SidechainBlockT: SignedBlockT;
type ParentchainBlockT: BlockT;

fn compose_block_and_confirmation(
&self,
latest_onchain_header: &<Self::ParentchainBlockT as BlockT>::Header,
top_call_hashes: Vec<H256>,
shard: ShardIdentifier,
state_hash_apriori: H256,
) -> Result<(OpaqueCall, Self::SidechainBlockT)>;
}

/// Block composer implementation for the sidechain
pub struct BlockComposer<PB, SB, Signer, StateKey, RpcAuthor, StfExecutor> {
signer: Signer,
state_key: StateKey,
rpc_author: Arc<RpcAuthor>,
stf_executor: Arc<StfExecutor>,
_phantom: PhantomData<(PB, SB)>,
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new (sidechain) block composer, extracted from the former compose_block_and_confirmation function

@murerfelmurerfel self-assigned this Nov 10, 2021
let opaque_call =
OpaqueCall::from_tuple(&(xt_block, shard, block_hash, state_hash_new.encode()));

self.rpc_author.on_block_created(block.signed_top_hashes(), block.hash());

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composer is now responsible for doing the callback to the rpc author

Comment on lines +99 to +105
mod sidechain_block_composer;
mod sidechain_impl;
mod sync;
pub mod tls_ra;
pub mod top_pool_execution;
mod top_pool_operation_executor;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of code was removed from this lib.rs, refactored and moved to these new modules (temporary before we further refactor and move them into the sidechain crate)

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow here has now changed a bit. We have to first execute the trusted calls and then call the block composer to compose the block and corresponding confirmation extrinsic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -218 to +245
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler> {
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey> {
state_handler: Arc<StateHandler>,
state_key: StateKey,
_phantom: PhantomData<(A, PB, SB, ST, O)>,
}

impl<A, PB, SB, O, ST, StateHandler> BlockImporter<A, PB, SB, O, ST, StateHandler> {
impl<A, PB, SB, O, ST, StateHandler, StateKey>
BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey>
{
#[allow(unused)]
pub fn new(state_handler: Arc<StateHandler>) -> Self {
Self { state_handler, _phantom: Default::default() }
pub fn new(state_handler: Arc<StateHandler>, state_key: StateKey) -> Self {
Self { state_handler, state_key, _phantom: Default::default() }

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a small improvement on the side: The block importer should not read the state encryption key directly from file, but rather have it passed as member when it's constructed. This makes the dependency more obvious and lets us test this importer more easily, without having to rely on a file existing on the filesystem.

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor re-naming, I realized submit_and_execute_top in fact only submits to the top pool, does not execute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Comment on lines -225 to +261
let stf_executor = StfExecutor::new(Arc::new(OcallApi), state_handler.clone());
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));
let top_pool_executor = TopPoolOperationExecutor::<Block, SignedBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
);
let block_composer = BlockComposer::<Block, SignedBlock, _, _, _, _>::new(
test_account(),
state_key(),
rpc_author.clone(),
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some of the tests here we now need the top pool executor and the block composer explicitly

Comment on lines +512 to +544
fn state_key() -> Aes {
Aes::default()
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a default AES key for state encryption instead of reading it from file (and thus requiring that file to exists when we run the tests)


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file we have the top-level e-calls for executing trusted getters and trusted calls from the top pool. These will be further refactored and moved to the sidechain crate in the next PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically constructing all the necessary components to run this function. It's what a dependency injection framework would do for us. I'm thinking about having a 'sidechain container' (container being a dependency injection concept, where a container contains all registered and constructed components) that is initialized and constructed once and can be accessed at each call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫

Comment on lines +128 to +153
let mut validator = LightClientSeal::<PB>::unseal()?;

let authority = Ed25519Seal::unseal()?;
let state_key = AesSeal::unseal()?;

let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. Maybe it's not initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let latest_onchain_header = validator.latest_finalized_header(validator.num_relays()).unwrap();
let genesis_hash = validator.genesis_hash(validator.num_relays())?;
let extrinsics_factory =
ExtrinsicsFactory::new(genesis_hash, authority.clone(), GLOBAL_NONCE_CACHE.clone());

let top_pool_executor =
Arc::new(TopPoolOperationExecutor::<PB, SignedSidechainBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
));

let block_composer =
Arc::new(BlockComposer::new(authority.clone(), state_key, rpc_author, stf_executor));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is also just constructing the necessary components. Will try to refactor this in the next PR (as described above)

@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 67622c2 to 4a267f8CompareNovember 10, 2021 10:42
Base automatically changed from feature/fm-extrinsics-factory-nonce-cache to masterNovember 10, 2021 13:49
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 4a267f8 to e50f4d0CompareNovember 10, 2021 13:59
@haerdibhaerdib mentioned this pull request Nov 10, 2021

@haerdibhaerdib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good, but I think I need to take another look at it tomorrow.. too late now to wrap my head around everything in here.

sgx_status_t::SGX_SUCCESS
}

#[no_mangle]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much red. I love it !

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

@clangenbclangenb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good, nothing really to add!

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Also separated the execution and block/confirmation composition.
The is in preparation for moving these parts into the sidechain crate.
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from e50f4d0 to de5852bCompareNovember 11, 2021 10:06
@murerfel
murerfel merged commit bca26ab into masterNov 11, 2021
@murerfel
murerfel deleted the feature/fm-extract-top-pool-execution branch November 11, 2021 11:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@murerfel@clangenb@haerdib
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Extract the top pool operation execution into separate modules - #500

Merged
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution
Nov 11, 2021
Merged

Extract the top pool operation execution into separate modules#500
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution

Conversation

@murerfel

@murerfelmurerfel commented Nov 10, 2021

Copy link
Copy Markdown
Contributor

Created new traits/components that execute the trusted operations from the top pool.
Also separated the execution and block/confirmation composition.

The is in preparation for moving these parts into the sidechain crate.

Comment on lines +44 to +64
pub trait ComposeBlockAndConfirmation {
type SidechainBlockT: SignedBlockT;
type ParentchainBlockT: BlockT;

fn compose_block_and_confirmation(
&self,
latest_onchain_header: &<Self::ParentchainBlockT as BlockT>::Header,
top_call_hashes: Vec<H256>,
shard: ShardIdentifier,
state_hash_apriori: H256,
) -> Result<(OpaqueCall, Self::SidechainBlockT)>;
}

/// Block composer implementation for the sidechain
pub struct BlockComposer<PB, SB, Signer, StateKey, RpcAuthor, StfExecutor> {
signer: Signer,
state_key: StateKey,
rpc_author: Arc<RpcAuthor>,
stf_executor: Arc<StfExecutor>,
_phantom: PhantomData<(PB, SB)>,
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new (sidechain) block composer, extracted from the former compose_block_and_confirmation function

@murerfelmurerfel self-assigned this Nov 10, 2021
let opaque_call =
OpaqueCall::from_tuple(&(xt_block, shard, block_hash, state_hash_new.encode()));

self.rpc_author.on_block_created(block.signed_top_hashes(), block.hash());

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composer is now responsible for doing the callback to the rpc author

Comment on lines +99 to +105
mod sidechain_block_composer;
mod sidechain_impl;
mod sync;
pub mod tls_ra;
pub mod top_pool_execution;
mod top_pool_operation_executor;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of code was removed from this lib.rs, refactored and moved to these new modules (temporary before we further refactor and move them into the sidechain crate)

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow here has now changed a bit. We have to first execute the trusted calls and then call the block composer to compose the block and corresponding confirmation extrinsic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -218 to +245
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler> {
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey> {
state_handler: Arc<StateHandler>,
state_key: StateKey,
_phantom: PhantomData<(A, PB, SB, ST, O)>,
}

impl<A, PB, SB, O, ST, StateHandler> BlockImporter<A, PB, SB, O, ST, StateHandler> {
impl<A, PB, SB, O, ST, StateHandler, StateKey>
BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey>
{
#[allow(unused)]
pub fn new(state_handler: Arc<StateHandler>) -> Self {
Self { state_handler, _phantom: Default::default() }
pub fn new(state_handler: Arc<StateHandler>, state_key: StateKey) -> Self {
Self { state_handler, state_key, _phantom: Default::default() }

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a small improvement on the side: The block importer should not read the state encryption key directly from file, but rather have it passed as member when it's constructed. This makes the dependency more obvious and lets us test this importer more easily, without having to rely on a file existing on the filesystem.

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor re-naming, I realized submit_and_execute_top in fact only submits to the top pool, does not execute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Comment on lines -225 to +261
let stf_executor = StfExecutor::new(Arc::new(OcallApi), state_handler.clone());
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));
let top_pool_executor = TopPoolOperationExecutor::<Block, SignedBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
);
let block_composer = BlockComposer::<Block, SignedBlock, _, _, _, _>::new(
test_account(),
state_key(),
rpc_author.clone(),
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some of the tests here we now need the top pool executor and the block composer explicitly

Comment on lines +512 to +544
fn state_key() -> Aes {
Aes::default()
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a default AES key for state encryption instead of reading it from file (and thus requiring that file to exists when we run the tests)


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file we have the top-level e-calls for executing trusted getters and trusted calls from the top pool. These will be further refactored and moved to the sidechain crate in the next PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically constructing all the necessary components to run this function. It's what a dependency injection framework would do for us. I'm thinking about having a 'sidechain container' (container being a dependency injection concept, where a container contains all registered and constructed components) that is initialized and constructed once and can be accessed at each call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫

Comment on lines +128 to +153
let mut validator = LightClientSeal::<PB>::unseal()?;

let authority = Ed25519Seal::unseal()?;
let state_key = AesSeal::unseal()?;

let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. Maybe it's not initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let latest_onchain_header = validator.latest_finalized_header(validator.num_relays()).unwrap();
let genesis_hash = validator.genesis_hash(validator.num_relays())?;
let extrinsics_factory =
ExtrinsicsFactory::new(genesis_hash, authority.clone(), GLOBAL_NONCE_CACHE.clone());

let top_pool_executor =
Arc::new(TopPoolOperationExecutor::<PB, SignedSidechainBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
));

let block_composer =
Arc::new(BlockComposer::new(authority.clone(), state_key, rpc_author, stf_executor));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is also just constructing the necessary components. Will try to refactor this in the next PR (as described above)

@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 67622c2 to 4a267f8CompareNovember 10, 2021 10:42
Base automatically changed from feature/fm-extrinsics-factory-nonce-cache to masterNovember 10, 2021 13:49
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 4a267f8 to e50f4d0CompareNovember 10, 2021 13:59
@haerdibhaerdib mentioned this pull request Nov 10, 2021

@haerdibhaerdib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good, but I think I need to take another look at it tomorrow.. too late now to wrap my head around everything in here.

sgx_status_t::SGX_SUCCESS
}

#[no_mangle]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much red. I love it !

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

@clangenbclangenb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good, nothing really to add!

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Also separated the execution and block/confirmation composition.
The is in preparation for moving these parts into the sidechain crate.
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from e50f4d0 to de5852bCompareNovember 11, 2021 10:06
@murerfel
murerfel merged commit bca26ab into masterNov 11, 2021
@murerfel
murerfel deleted the feature/fm-extract-top-pool-execution branch November 11, 2021 11:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@murerfel@clangenb@haerdib
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Extract the top pool operation execution into separate modules - #500

Merged
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution
Nov 11, 2021
Merged

Extract the top pool operation execution into separate modules#500
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution

Conversation

@murerfel

@murerfelmurerfel commented Nov 10, 2021

Copy link
Copy Markdown
Contributor

Created new traits/components that execute the trusted operations from the top pool.
Also separated the execution and block/confirmation composition.

The is in preparation for moving these parts into the sidechain crate.

Comment on lines +44 to +64
pub trait ComposeBlockAndConfirmation {
type SidechainBlockT: SignedBlockT;
type ParentchainBlockT: BlockT;

fn compose_block_and_confirmation(
&self,
latest_onchain_header: &<Self::ParentchainBlockT as BlockT>::Header,
top_call_hashes: Vec<H256>,
shard: ShardIdentifier,
state_hash_apriori: H256,
) -> Result<(OpaqueCall, Self::SidechainBlockT)>;
}

/// Block composer implementation for the sidechain
pub struct BlockComposer<PB, SB, Signer, StateKey, RpcAuthor, StfExecutor> {
signer: Signer,
state_key: StateKey,
rpc_author: Arc<RpcAuthor>,
stf_executor: Arc<StfExecutor>,
_phantom: PhantomData<(PB, SB)>,
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new (sidechain) block composer, extracted from the former compose_block_and_confirmation function

@murerfelmurerfel self-assigned this Nov 10, 2021
let opaque_call =
OpaqueCall::from_tuple(&(xt_block, shard, block_hash, state_hash_new.encode()));

self.rpc_author.on_block_created(block.signed_top_hashes(), block.hash());

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composer is now responsible for doing the callback to the rpc author

Comment on lines +99 to +105
mod sidechain_block_composer;
mod sidechain_impl;
mod sync;
pub mod tls_ra;
pub mod top_pool_execution;
mod top_pool_operation_executor;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of code was removed from this lib.rs, refactored and moved to these new modules (temporary before we further refactor and move them into the sidechain crate)

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow here has now changed a bit. We have to first execute the trusted calls and then call the block composer to compose the block and corresponding confirmation extrinsic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -218 to +245
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler> {
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey> {
state_handler: Arc<StateHandler>,
state_key: StateKey,
_phantom: PhantomData<(A, PB, SB, ST, O)>,
}

impl<A, PB, SB, O, ST, StateHandler> BlockImporter<A, PB, SB, O, ST, StateHandler> {
impl<A, PB, SB, O, ST, StateHandler, StateKey>
BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey>
{
#[allow(unused)]
pub fn new(state_handler: Arc<StateHandler>) -> Self {
Self { state_handler, _phantom: Default::default() }
pub fn new(state_handler: Arc<StateHandler>, state_key: StateKey) -> Self {
Self { state_handler, state_key, _phantom: Default::default() }

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a small improvement on the side: The block importer should not read the state encryption key directly from file, but rather have it passed as member when it's constructed. This makes the dependency more obvious and lets us test this importer more easily, without having to rely on a file existing on the filesystem.

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor re-naming, I realized submit_and_execute_top in fact only submits to the top pool, does not execute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Comment on lines -225 to +261
let stf_executor = StfExecutor::new(Arc::new(OcallApi), state_handler.clone());
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));
let top_pool_executor = TopPoolOperationExecutor::<Block, SignedBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
);
let block_composer = BlockComposer::<Block, SignedBlock, _, _, _, _>::new(
test_account(),
state_key(),
rpc_author.clone(),
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some of the tests here we now need the top pool executor and the block composer explicitly

Comment on lines +512 to +544
fn state_key() -> Aes {
Aes::default()
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a default AES key for state encryption instead of reading it from file (and thus requiring that file to exists when we run the tests)


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file we have the top-level e-calls for executing trusted getters and trusted calls from the top pool. These will be further refactored and moved to the sidechain crate in the next PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically constructing all the necessary components to run this function. It's what a dependency injection framework would do for us. I'm thinking about having a 'sidechain container' (container being a dependency injection concept, where a container contains all registered and constructed components) that is initialized and constructed once and can be accessed at each call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫

Comment on lines +128 to +153
let mut validator = LightClientSeal::<PB>::unseal()?;

let authority = Ed25519Seal::unseal()?;
let state_key = AesSeal::unseal()?;

let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. Maybe it's not initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let latest_onchain_header = validator.latest_finalized_header(validator.num_relays()).unwrap();
let genesis_hash = validator.genesis_hash(validator.num_relays())?;
let extrinsics_factory =
ExtrinsicsFactory::new(genesis_hash, authority.clone(), GLOBAL_NONCE_CACHE.clone());

let top_pool_executor =
Arc::new(TopPoolOperationExecutor::<PB, SignedSidechainBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
));

let block_composer =
Arc::new(BlockComposer::new(authority.clone(), state_key, rpc_author, stf_executor));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is also just constructing the necessary components. Will try to refactor this in the next PR (as described above)

@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 67622c2 to 4a267f8CompareNovember 10, 2021 10:42
Base automatically changed from feature/fm-extrinsics-factory-nonce-cache to masterNovember 10, 2021 13:49
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 4a267f8 to e50f4d0CompareNovember 10, 2021 13:59
@haerdibhaerdib mentioned this pull request Nov 10, 2021

@haerdibhaerdib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good, but I think I need to take another look at it tomorrow.. too late now to wrap my head around everything in here.

sgx_status_t::SGX_SUCCESS
}

#[no_mangle]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much red. I love it !

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

@clangenbclangenb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good, nothing really to add!

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Also separated the execution and block/confirmation composition.
The is in preparation for moving these parts into the sidechain crate.
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from e50f4d0 to de5852bCompareNovember 11, 2021 10:06
@murerfel
murerfel merged commit bca26ab into masterNov 11, 2021
@murerfel
murerfel deleted the feature/fm-extract-top-pool-execution branch November 11, 2021 11:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@murerfel@clangenb@haerdib
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Extract the top pool operation execution into separate modules - #500

Merged
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution
Nov 11, 2021
Merged

Extract the top pool operation execution into separate modules#500
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution

Conversation

@murerfel

@murerfelmurerfel commented Nov 10, 2021

Copy link
Copy Markdown
Contributor

Created new traits/components that execute the trusted operations from the top pool.
Also separated the execution and block/confirmation composition.

The is in preparation for moving these parts into the sidechain crate.

Comment on lines +44 to +64
pub trait ComposeBlockAndConfirmation {
type SidechainBlockT: SignedBlockT;
type ParentchainBlockT: BlockT;

fn compose_block_and_confirmation(
&self,
latest_onchain_header: &<Self::ParentchainBlockT as BlockT>::Header,
top_call_hashes: Vec<H256>,
shard: ShardIdentifier,
state_hash_apriori: H256,
) -> Result<(OpaqueCall, Self::SidechainBlockT)>;
}

/// Block composer implementation for the sidechain
pub struct BlockComposer<PB, SB, Signer, StateKey, RpcAuthor, StfExecutor> {
signer: Signer,
state_key: StateKey,
rpc_author: Arc<RpcAuthor>,
stf_executor: Arc<StfExecutor>,
_phantom: PhantomData<(PB, SB)>,
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new (sidechain) block composer, extracted from the former compose_block_and_confirmation function

@murerfelmurerfel self-assigned this Nov 10, 2021
let opaque_call =
OpaqueCall::from_tuple(&(xt_block, shard, block_hash, state_hash_new.encode()));

self.rpc_author.on_block_created(block.signed_top_hashes(), block.hash());

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composer is now responsible for doing the callback to the rpc author

Comment on lines +99 to +105
mod sidechain_block_composer;
mod sidechain_impl;
mod sync;
pub mod tls_ra;
pub mod top_pool_execution;
mod top_pool_operation_executor;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of code was removed from this lib.rs, refactored and moved to these new modules (temporary before we further refactor and move them into the sidechain crate)

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow here has now changed a bit. We have to first execute the trusted calls and then call the block composer to compose the block and corresponding confirmation extrinsic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -218 to +245
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler> {
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey> {
state_handler: Arc<StateHandler>,
state_key: StateKey,
_phantom: PhantomData<(A, PB, SB, ST, O)>,
}

impl<A, PB, SB, O, ST, StateHandler> BlockImporter<A, PB, SB, O, ST, StateHandler> {
impl<A, PB, SB, O, ST, StateHandler, StateKey>
BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey>
{
#[allow(unused)]
pub fn new(state_handler: Arc<StateHandler>) -> Self {
Self { state_handler, _phantom: Default::default() }
pub fn new(state_handler: Arc<StateHandler>, state_key: StateKey) -> Self {
Self { state_handler, state_key, _phantom: Default::default() }

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a small improvement on the side: The block importer should not read the state encryption key directly from file, but rather have it passed as member when it's constructed. This makes the dependency more obvious and lets us test this importer more easily, without having to rely on a file existing on the filesystem.

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor re-naming, I realized submit_and_execute_top in fact only submits to the top pool, does not execute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Comment on lines -225 to +261
let stf_executor = StfExecutor::new(Arc::new(OcallApi), state_handler.clone());
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));
let top_pool_executor = TopPoolOperationExecutor::<Block, SignedBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
);
let block_composer = BlockComposer::<Block, SignedBlock, _, _, _, _>::new(
test_account(),
state_key(),
rpc_author.clone(),
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some of the tests here we now need the top pool executor and the block composer explicitly

Comment on lines +512 to +544
fn state_key() -> Aes {
Aes::default()
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a default AES key for state encryption instead of reading it from file (and thus requiring that file to exists when we run the tests)


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file we have the top-level e-calls for executing trusted getters and trusted calls from the top pool. These will be further refactored and moved to the sidechain crate in the next PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically constructing all the necessary components to run this function. It's what a dependency injection framework would do for us. I'm thinking about having a 'sidechain container' (container being a dependency injection concept, where a container contains all registered and constructed components) that is initialized and constructed once and can be accessed at each call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫

Comment on lines +128 to +153
let mut validator = LightClientSeal::<PB>::unseal()?;

let authority = Ed25519Seal::unseal()?;
let state_key = AesSeal::unseal()?;

let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. Maybe it's not initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let latest_onchain_header = validator.latest_finalized_header(validator.num_relays()).unwrap();
let genesis_hash = validator.genesis_hash(validator.num_relays())?;
let extrinsics_factory =
ExtrinsicsFactory::new(genesis_hash, authority.clone(), GLOBAL_NONCE_CACHE.clone());

let top_pool_executor =
Arc::new(TopPoolOperationExecutor::<PB, SignedSidechainBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
));

let block_composer =
Arc::new(BlockComposer::new(authority.clone(), state_key, rpc_author, stf_executor));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is also just constructing the necessary components. Will try to refactor this in the next PR (as described above)

@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 67622c2 to 4a267f8CompareNovember 10, 2021 10:42
Base automatically changed from feature/fm-extrinsics-factory-nonce-cache to masterNovember 10, 2021 13:49
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 4a267f8 to e50f4d0CompareNovember 10, 2021 13:59
@haerdibhaerdib mentioned this pull request Nov 10, 2021

@haerdibhaerdib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good, but I think I need to take another look at it tomorrow.. too late now to wrap my head around everything in here.

sgx_status_t::SGX_SUCCESS
}

#[no_mangle]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much red. I love it !

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

@clangenbclangenb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good, nothing really to add!

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Also separated the execution and block/confirmation composition.
The is in preparation for moving these parts into the sidechain crate.
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from e50f4d0 to de5852bCompareNovember 11, 2021 10:06
@murerfel
murerfel merged commit bca26ab into masterNov 11, 2021
@murerfel
murerfel deleted the feature/fm-extract-top-pool-execution branch November 11, 2021 11:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@murerfel@clangenb@haerdib
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Extract the top pool operation execution into separate modules - #500

Merged
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution
Nov 11, 2021
Merged

Extract the top pool operation execution into separate modules#500
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution

Conversation

@murerfel

@murerfelmurerfel commented Nov 10, 2021

Copy link
Copy Markdown
Contributor

Created new traits/components that execute the trusted operations from the top pool.
Also separated the execution and block/confirmation composition.

The is in preparation for moving these parts into the sidechain crate.

Comment on lines +44 to +64
pub trait ComposeBlockAndConfirmation {
type SidechainBlockT: SignedBlockT;
type ParentchainBlockT: BlockT;

fn compose_block_and_confirmation(
&self,
latest_onchain_header: &<Self::ParentchainBlockT as BlockT>::Header,
top_call_hashes: Vec<H256>,
shard: ShardIdentifier,
state_hash_apriori: H256,
) -> Result<(OpaqueCall, Self::SidechainBlockT)>;
}

/// Block composer implementation for the sidechain
pub struct BlockComposer<PB, SB, Signer, StateKey, RpcAuthor, StfExecutor> {
signer: Signer,
state_key: StateKey,
rpc_author: Arc<RpcAuthor>,
stf_executor: Arc<StfExecutor>,
_phantom: PhantomData<(PB, SB)>,
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new (sidechain) block composer, extracted from the former compose_block_and_confirmation function

@murerfelmurerfel self-assigned this Nov 10, 2021
let opaque_call =
OpaqueCall::from_tuple(&(xt_block, shard, block_hash, state_hash_new.encode()));

self.rpc_author.on_block_created(block.signed_top_hashes(), block.hash());

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composer is now responsible for doing the callback to the rpc author

Comment on lines +99 to +105
mod sidechain_block_composer;
mod sidechain_impl;
mod sync;
pub mod tls_ra;
pub mod top_pool_execution;
mod top_pool_operation_executor;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of code was removed from this lib.rs, refactored and moved to these new modules (temporary before we further refactor and move them into the sidechain crate)

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow here has now changed a bit. We have to first execute the trusted calls and then call the block composer to compose the block and corresponding confirmation extrinsic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -218 to +245
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler> {
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey> {
state_handler: Arc<StateHandler>,
state_key: StateKey,
_phantom: PhantomData<(A, PB, SB, ST, O)>,
}

impl<A, PB, SB, O, ST, StateHandler> BlockImporter<A, PB, SB, O, ST, StateHandler> {
impl<A, PB, SB, O, ST, StateHandler, StateKey>
BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey>
{
#[allow(unused)]
pub fn new(state_handler: Arc<StateHandler>) -> Self {
Self { state_handler, _phantom: Default::default() }
pub fn new(state_handler: Arc<StateHandler>, state_key: StateKey) -> Self {
Self { state_handler, state_key, _phantom: Default::default() }

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a small improvement on the side: The block importer should not read the state encryption key directly from file, but rather have it passed as member when it's constructed. This makes the dependency more obvious and lets us test this importer more easily, without having to rely on a file existing on the filesystem.

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor re-naming, I realized submit_and_execute_top in fact only submits to the top pool, does not execute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Comment on lines -225 to +261
let stf_executor = StfExecutor::new(Arc::new(OcallApi), state_handler.clone());
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));
let top_pool_executor = TopPoolOperationExecutor::<Block, SignedBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
);
let block_composer = BlockComposer::<Block, SignedBlock, _, _, _, _>::new(
test_account(),
state_key(),
rpc_author.clone(),
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some of the tests here we now need the top pool executor and the block composer explicitly

Comment on lines +512 to +544
fn state_key() -> Aes {
Aes::default()
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a default AES key for state encryption instead of reading it from file (and thus requiring that file to exists when we run the tests)


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file we have the top-level e-calls for executing trusted getters and trusted calls from the top pool. These will be further refactored and moved to the sidechain crate in the next PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically constructing all the necessary components to run this function. It's what a dependency injection framework would do for us. I'm thinking about having a 'sidechain container' (container being a dependency injection concept, where a container contains all registered and constructed components) that is initialized and constructed once and can be accessed at each call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫

Comment on lines +128 to +153
let mut validator = LightClientSeal::<PB>::unseal()?;

let authority = Ed25519Seal::unseal()?;
let state_key = AesSeal::unseal()?;

let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. Maybe it's not initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let latest_onchain_header = validator.latest_finalized_header(validator.num_relays()).unwrap();
let genesis_hash = validator.genesis_hash(validator.num_relays())?;
let extrinsics_factory =
ExtrinsicsFactory::new(genesis_hash, authority.clone(), GLOBAL_NONCE_CACHE.clone());

let top_pool_executor =
Arc::new(TopPoolOperationExecutor::<PB, SignedSidechainBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
));

let block_composer =
Arc::new(BlockComposer::new(authority.clone(), state_key, rpc_author, stf_executor));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is also just constructing the necessary components. Will try to refactor this in the next PR (as described above)

@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 67622c2 to 4a267f8CompareNovember 10, 2021 10:42
Base automatically changed from feature/fm-extrinsics-factory-nonce-cache to masterNovember 10, 2021 13:49
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 4a267f8 to e50f4d0CompareNovember 10, 2021 13:59
@haerdibhaerdib mentioned this pull request Nov 10, 2021

@haerdibhaerdib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good, but I think I need to take another look at it tomorrow.. too late now to wrap my head around everything in here.

sgx_status_t::SGX_SUCCESS
}

#[no_mangle]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much red. I love it !

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

@clangenbclangenb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good, nothing really to add!

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Also separated the execution and block/confirmation composition.
The is in preparation for moving these parts into the sidechain crate.
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from e50f4d0 to de5852bCompareNovember 11, 2021 10:06
@murerfel
murerfel merged commit bca26ab into masterNov 11, 2021
@murerfel
murerfel deleted the feature/fm-extract-top-pool-execution branch November 11, 2021 11:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@murerfel@clangenb@haerdib
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Extract the top pool operation execution into separate modules - #500

Merged
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution
Nov 11, 2021
Merged

Extract the top pool operation execution into separate modules#500
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution

Conversation

@murerfel

@murerfelmurerfel commented Nov 10, 2021

Copy link
Copy Markdown
Contributor

Created new traits/components that execute the trusted operations from the top pool.
Also separated the execution and block/confirmation composition.

The is in preparation for moving these parts into the sidechain crate.

Comment on lines +44 to +64
pub trait ComposeBlockAndConfirmation {
type SidechainBlockT: SignedBlockT;
type ParentchainBlockT: BlockT;

fn compose_block_and_confirmation(
&self,
latest_onchain_header: &<Self::ParentchainBlockT as BlockT>::Header,
top_call_hashes: Vec<H256>,
shard: ShardIdentifier,
state_hash_apriori: H256,
) -> Result<(OpaqueCall, Self::SidechainBlockT)>;
}

/// Block composer implementation for the sidechain
pub struct BlockComposer<PB, SB, Signer, StateKey, RpcAuthor, StfExecutor> {
signer: Signer,
state_key: StateKey,
rpc_author: Arc<RpcAuthor>,
stf_executor: Arc<StfExecutor>,
_phantom: PhantomData<(PB, SB)>,
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new (sidechain) block composer, extracted from the former compose_block_and_confirmation function

@murerfelmurerfel self-assigned this Nov 10, 2021
let opaque_call =
OpaqueCall::from_tuple(&(xt_block, shard, block_hash, state_hash_new.encode()));

self.rpc_author.on_block_created(block.signed_top_hashes(), block.hash());

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composer is now responsible for doing the callback to the rpc author

Comment on lines +99 to +105
mod sidechain_block_composer;
mod sidechain_impl;
mod sync;
pub mod tls_ra;
pub mod top_pool_execution;
mod top_pool_operation_executor;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of code was removed from this lib.rs, refactored and moved to these new modules (temporary before we further refactor and move them into the sidechain crate)

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow here has now changed a bit. We have to first execute the trusted calls and then call the block composer to compose the block and corresponding confirmation extrinsic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -218 to +245
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler> {
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey> {
state_handler: Arc<StateHandler>,
state_key: StateKey,
_phantom: PhantomData<(A, PB, SB, ST, O)>,
}

impl<A, PB, SB, O, ST, StateHandler> BlockImporter<A, PB, SB, O, ST, StateHandler> {
impl<A, PB, SB, O, ST, StateHandler, StateKey>
BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey>
{
#[allow(unused)]
pub fn new(state_handler: Arc<StateHandler>) -> Self {
Self { state_handler, _phantom: Default::default() }
pub fn new(state_handler: Arc<StateHandler>, state_key: StateKey) -> Self {
Self { state_handler, state_key, _phantom: Default::default() }

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a small improvement on the side: The block importer should not read the state encryption key directly from file, but rather have it passed as member when it's constructed. This makes the dependency more obvious and lets us test this importer more easily, without having to rely on a file existing on the filesystem.

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor re-naming, I realized submit_and_execute_top in fact only submits to the top pool, does not execute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Comment on lines -225 to +261
let stf_executor = StfExecutor::new(Arc::new(OcallApi), state_handler.clone());
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));
let top_pool_executor = TopPoolOperationExecutor::<Block, SignedBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
);
let block_composer = BlockComposer::<Block, SignedBlock, _, _, _, _>::new(
test_account(),
state_key(),
rpc_author.clone(),
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some of the tests here we now need the top pool executor and the block composer explicitly

Comment on lines +512 to +544
fn state_key() -> Aes {
Aes::default()
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a default AES key for state encryption instead of reading it from file (and thus requiring that file to exists when we run the tests)


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file we have the top-level e-calls for executing trusted getters and trusted calls from the top pool. These will be further refactored and moved to the sidechain crate in the next PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically constructing all the necessary components to run this function. It's what a dependency injection framework would do for us. I'm thinking about having a 'sidechain container' (container being a dependency injection concept, where a container contains all registered and constructed components) that is initialized and constructed once and can be accessed at each call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫

Comment on lines +128 to +153
let mut validator = LightClientSeal::<PB>::unseal()?;

let authority = Ed25519Seal::unseal()?;
let state_key = AesSeal::unseal()?;

let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. Maybe it's not initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let latest_onchain_header = validator.latest_finalized_header(validator.num_relays()).unwrap();
let genesis_hash = validator.genesis_hash(validator.num_relays())?;
let extrinsics_factory =
ExtrinsicsFactory::new(genesis_hash, authority.clone(), GLOBAL_NONCE_CACHE.clone());

let top_pool_executor =
Arc::new(TopPoolOperationExecutor::<PB, SignedSidechainBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
));

let block_composer =
Arc::new(BlockComposer::new(authority.clone(), state_key, rpc_author, stf_executor));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is also just constructing the necessary components. Will try to refactor this in the next PR (as described above)

@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 67622c2 to 4a267f8CompareNovember 10, 2021 10:42
Base automatically changed from feature/fm-extrinsics-factory-nonce-cache to masterNovember 10, 2021 13:49
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 4a267f8 to e50f4d0CompareNovember 10, 2021 13:59
@haerdibhaerdib mentioned this pull request Nov 10, 2021

@haerdibhaerdib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good, but I think I need to take another look at it tomorrow.. too late now to wrap my head around everything in here.

sgx_status_t::SGX_SUCCESS
}

#[no_mangle]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much red. I love it !

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

@clangenbclangenb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good, nothing really to add!

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Also separated the execution and block/confirmation composition.
The is in preparation for moving these parts into the sidechain crate.
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from e50f4d0 to de5852bCompareNovember 11, 2021 10:06
@murerfel
murerfel merged commit bca26ab into masterNov 11, 2021
@murerfel
murerfel deleted the feature/fm-extract-top-pool-execution branch November 11, 2021 11:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@murerfel@clangenb@haerdib
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Extract the top pool operation execution into separate modules - #500

Merged
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution
Nov 11, 2021
Merged

Extract the top pool operation execution into separate modules#500
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution

Conversation

@murerfel

@murerfelmurerfel commented Nov 10, 2021

Copy link
Copy Markdown
Contributor

Created new traits/components that execute the trusted operations from the top pool.
Also separated the execution and block/confirmation composition.

The is in preparation for moving these parts into the sidechain crate.

Comment on lines +44 to +64
pub trait ComposeBlockAndConfirmation {
type SidechainBlockT: SignedBlockT;
type ParentchainBlockT: BlockT;

fn compose_block_and_confirmation(
&self,
latest_onchain_header: &<Self::ParentchainBlockT as BlockT>::Header,
top_call_hashes: Vec<H256>,
shard: ShardIdentifier,
state_hash_apriori: H256,
) -> Result<(OpaqueCall, Self::SidechainBlockT)>;
}

/// Block composer implementation for the sidechain
pub struct BlockComposer<PB, SB, Signer, StateKey, RpcAuthor, StfExecutor> {
signer: Signer,
state_key: StateKey,
rpc_author: Arc<RpcAuthor>,
stf_executor: Arc<StfExecutor>,
_phantom: PhantomData<(PB, SB)>,
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new (sidechain) block composer, extracted from the former compose_block_and_confirmation function

@murerfelmurerfel self-assigned this Nov 10, 2021
let opaque_call =
OpaqueCall::from_tuple(&(xt_block, shard, block_hash, state_hash_new.encode()));

self.rpc_author.on_block_created(block.signed_top_hashes(), block.hash());

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composer is now responsible for doing the callback to the rpc author

Comment on lines +99 to +105
mod sidechain_block_composer;
mod sidechain_impl;
mod sync;
pub mod tls_ra;
pub mod top_pool_execution;
mod top_pool_operation_executor;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of code was removed from this lib.rs, refactored and moved to these new modules (temporary before we further refactor and move them into the sidechain crate)

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow here has now changed a bit. We have to first execute the trusted calls and then call the block composer to compose the block and corresponding confirmation extrinsic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -218 to +245
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler> {
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey> {
state_handler: Arc<StateHandler>,
state_key: StateKey,
_phantom: PhantomData<(A, PB, SB, ST, O)>,
}

impl<A, PB, SB, O, ST, StateHandler> BlockImporter<A, PB, SB, O, ST, StateHandler> {
impl<A, PB, SB, O, ST, StateHandler, StateKey>
BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey>
{
#[allow(unused)]
pub fn new(state_handler: Arc<StateHandler>) -> Self {
Self { state_handler, _phantom: Default::default() }
pub fn new(state_handler: Arc<StateHandler>, state_key: StateKey) -> Self {
Self { state_handler, state_key, _phantom: Default::default() }

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a small improvement on the side: The block importer should not read the state encryption key directly from file, but rather have it passed as member when it's constructed. This makes the dependency more obvious and lets us test this importer more easily, without having to rely on a file existing on the filesystem.

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor re-naming, I realized submit_and_execute_top in fact only submits to the top pool, does not execute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Comment on lines -225 to +261
let stf_executor = StfExecutor::new(Arc::new(OcallApi), state_handler.clone());
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));
let top_pool_executor = TopPoolOperationExecutor::<Block, SignedBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
);
let block_composer = BlockComposer::<Block, SignedBlock, _, _, _, _>::new(
test_account(),
state_key(),
rpc_author.clone(),
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some of the tests here we now need the top pool executor and the block composer explicitly

Comment on lines +512 to +544
fn state_key() -> Aes {
Aes::default()
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a default AES key for state encryption instead of reading it from file (and thus requiring that file to exists when we run the tests)


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file we have the top-level e-calls for executing trusted getters and trusted calls from the top pool. These will be further refactored and moved to the sidechain crate in the next PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically constructing all the necessary components to run this function. It's what a dependency injection framework would do for us. I'm thinking about having a 'sidechain container' (container being a dependency injection concept, where a container contains all registered and constructed components) that is initialized and constructed once and can be accessed at each call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫

Comment on lines +128 to +153
let mut validator = LightClientSeal::<PB>::unseal()?;

let authority = Ed25519Seal::unseal()?;
let state_key = AesSeal::unseal()?;

let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. Maybe it's not initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let latest_onchain_header = validator.latest_finalized_header(validator.num_relays()).unwrap();
let genesis_hash = validator.genesis_hash(validator.num_relays())?;
let extrinsics_factory =
ExtrinsicsFactory::new(genesis_hash, authority.clone(), GLOBAL_NONCE_CACHE.clone());

let top_pool_executor =
Arc::new(TopPoolOperationExecutor::<PB, SignedSidechainBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
));

let block_composer =
Arc::new(BlockComposer::new(authority.clone(), state_key, rpc_author, stf_executor));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is also just constructing the necessary components. Will try to refactor this in the next PR (as described above)

@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 67622c2 to 4a267f8CompareNovember 10, 2021 10:42
Base automatically changed from feature/fm-extrinsics-factory-nonce-cache to masterNovember 10, 2021 13:49
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 4a267f8 to e50f4d0CompareNovember 10, 2021 13:59
@haerdibhaerdib mentioned this pull request Nov 10, 2021

@haerdibhaerdib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good, but I think I need to take another look at it tomorrow.. too late now to wrap my head around everything in here.

sgx_status_t::SGX_SUCCESS
}

#[no_mangle]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much red. I love it !

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

@clangenbclangenb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good, nothing really to add!

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Also separated the execution and block/confirmation composition.
The is in preparation for moving these parts into the sidechain crate.
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from e50f4d0 to de5852bCompareNovember 11, 2021 10:06
@murerfel
murerfel merged commit bca26ab into masterNov 11, 2021
@murerfel
murerfel deleted the feature/fm-extract-top-pool-execution branch November 11, 2021 11:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@murerfel@clangenb@haerdib
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Extract the top pool operation execution into separate modules - #500

Merged
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution
Nov 11, 2021
Merged

Extract the top pool operation execution into separate modules#500
murerfel merged 1 commit into
masterfrom
feature/fm-extract-top-pool-execution

Conversation

@murerfel

@murerfelmurerfel commented Nov 10, 2021

Copy link
Copy Markdown
Contributor

Created new traits/components that execute the trusted operations from the top pool.
Also separated the execution and block/confirmation composition.

The is in preparation for moving these parts into the sidechain crate.

Comment on lines +44 to +64
pub trait ComposeBlockAndConfirmation {
type SidechainBlockT: SignedBlockT;
type ParentchainBlockT: BlockT;

fn compose_block_and_confirmation(
&self,
latest_onchain_header: &<Self::ParentchainBlockT as BlockT>::Header,
top_call_hashes: Vec<H256>,
shard: ShardIdentifier,
state_hash_apriori: H256,
) -> Result<(OpaqueCall, Self::SidechainBlockT)>;
}

/// Block composer implementation for the sidechain
pub struct BlockComposer<PB, SB, Signer, StateKey, RpcAuthor, StfExecutor> {
signer: Signer,
state_key: StateKey,
rpc_author: Arc<RpcAuthor>,
stf_executor: Arc<StfExecutor>,
_phantom: PhantomData<(PB, SB)>,
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the new (sidechain) block composer, extracted from the former compose_block_and_confirmation function

@murerfelmurerfel self-assigned this Nov 10, 2021
let opaque_call =
OpaqueCall::from_tuple(&(xt_block, shard, block_hash, state_hash_new.encode()));

self.rpc_author.on_block_created(block.signed_top_hashes(), block.hash());

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composer is now responsible for doing the callback to the rpc author

Comment on lines +99 to +105
mod sidechain_block_composer;
mod sidechain_impl;
mod sync;
pub mod tls_ra;
pub mod top_pool_execution;
mod top_pool_operation_executor;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of code was removed from this lib.rs, refactored and moved to these new modules (temporary before we further refactor and move them into the sidechain crate)

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow here has now changed a bit. We have to first execute the trusted calls and then call the block composer to compose the block and corresponding confirmation extrinsic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -218 to +245
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler> {
pub struct BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey> {
state_handler: Arc<StateHandler>,
state_key: StateKey,
_phantom: PhantomData<(A, PB, SB, ST, O)>,
}

impl<A, PB, SB, O, ST, StateHandler> BlockImporter<A, PB, SB, O, ST, StateHandler> {
impl<A, PB, SB, O, ST, StateHandler, StateKey>
BlockImporter<A, PB, SB, O, ST, StateHandler, StateKey>
{
#[allow(unused)]
pub fn new(state_handler: Arc<StateHandler>) -> Self {
Self { state_handler, _phantom: Default::default() }
pub fn new(state_handler: Arc<StateHandler>, state_key: StateKey) -> Self {
Self { state_handler, state_key, _phantom: Default::default() }

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a small improvement on the side: The block importer should not read the state encryption key directly from file, but rather have it passed as member when it's constructed. This makes the dependency more obvious and lets us test this importer more easily, without having to rely on a file existing on the filesystem.

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor re-naming, I realized submit_and_execute_top in fact only submits to the top pool, does not execute.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Comment on lines -225 to +261
let stf_executor = StfExecutor::new(Arc::new(OcallApi), state_handler.clone());
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));
let top_pool_executor = TopPoolOperationExecutor::<Block, SignedBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
);
let block_composer = BlockComposer::<Block, SignedBlock, _, _, _, _>::new(
test_account(),
state_key(),
rpc_author.clone(),
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in some of the tests here we now need the top pool executor and the block composer explicitly

Comment on lines +512 to +544
fn state_key() -> Aes {
Aes::default()
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a default AES key for state encryption instead of reading it from file (and thus requiring that file to exists when we run the tests)


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file we have the top-level e-calls for executing trusted getters and trusted calls from the top pool. These will be further refactored and moved to the sidechain crate in the next PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is basically constructing all the necessary components to run this function. It's what a dependency injection framework would do for us. I'm thinking about having a 'sidechain container' (container being a dependency injection concept, where a container contains all registered and constructed components) that is initialized and constructed once and can be accessed at each call.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫

Comment on lines +128 to +153
let mut validator = LightClientSeal::<PB>::unseal()?;

let authority = Ed25519Seal::unseal()?;
let state_key = AesSeal::unseal()?;

let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. Maybe it's not initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let latest_onchain_header = validator.latest_finalized_header(validator.num_relays()).unwrap();
let genesis_hash = validator.genesis_hash(validator.num_relays())?;
let extrinsics_factory =
ExtrinsicsFactory::new(genesis_hash, authority.clone(), GLOBAL_NONCE_CACHE.clone());

let top_pool_executor =
Arc::new(TopPoolOperationExecutor::<PB, SignedSidechainBlock, _, _>::new(
rpc_author.clone(),
stf_executor.clone(),
));

let block_composer =
Arc::new(BlockComposer::new(authority.clone(), state_key, rpc_author, stf_executor));

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this is also just constructing the necessary components. Will try to refactor this in the next PR (as described above)

@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 67622c2 to 4a267f8CompareNovember 10, 2021 10:42
Base automatically changed from feature/fm-extrinsics-factory-nonce-cache to masterNovember 10, 2021 13:49
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from 4a267f8 to e50f4d0CompareNovember 10, 2021 13:59
@haerdibhaerdib mentioned this pull request Nov 10, 2021

@haerdibhaerdib left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good, but I think I need to take another look at it tomorrow.. too late now to wrap my head around everything in here.

sgx_status_t::SGX_SUCCESS
}

#[no_mangle]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So much red. I love it !

Comment on lines +60 to +75
let rpc_author = GlobalAuthorContainer.get().ok_or_else(|| {
error!("Failed to retrieve author mutex. It might not be initialized?");
Error::MutexAccess
})?;

let state_handler = Arc::new(GlobalFileStateHandler);
let stf_executor = Arc::new(StfExecutor::new(Arc::new(OcallApi), state_handler.clone()));

let shards = state_handler.list_shards()?;
let mut remaining_shards = shards.len() as u32;
let ends_at = duration_now() + MAX_TRUSTED_GETTERS_EXEC_DURATION;

let top_pool_executor = TopPoolOperationExecutor::<Block, SignedSidechainBlock, _, _>::new(
rpc_author,
stf_executor,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One day, I'd really love to see the architecture you have in mind.. 😵‍💫


sgx_status_t::SGX_SUCCESS
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it will be further refactored - but what do you think about adding top-level-file description, i.e. documenting the thought process of about what should be placed in this file?

What I'm dreaming about:
https://github.com/paritytech/substrate/blob/master/frame/scheduler/src/lib.rs#L18-L48

What might be reality:
https://github.com/paritytech/substrate/blob/master/primitives/core/src/hash.rs#L18

But we could try?

@clangenbclangenb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very good, nothing really to add!

Comment on lines -118 to +143
let (calls, blocks) = execute_top_pool_trusted_calls::<PB, SB, _, _, Signer>(
self.author.as_ref(),
self.stf_executor.as_ref(),
self.signer.clone(),
&self.parentchain_header,
self.shard,
max_duration,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Ok(Proposal {
block: blocks.ok_or(ConsensusError::CannotPropose)?,
parentchain_effects: calls,
})
let latest_onchain_header = &self.parentchain_header;

let batch_execution_result = self
.top_pool_executor
.execute_trusted_calls(latest_onchain_header, self.shard, max_duration)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

let mut parentchain_extrinsics = batch_execution_result.get_extrinsic_callbacks();

let executed_operation_hashes =
batch_execution_result.get_executed_operation_hashes().iter().copied().collect();

let (confirmation_extrinsic, sidechain_block) = self
.block_composer
.compose_block_and_confirmation(
latest_onchain_header,
executed_operation_hashes,
self.shard,
batch_execution_result.previous_state_hash,
)
.map_err(|e| ConsensusError::Other(e.to_string().into()))?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I had this separation of concerns also in mind. 😄

Comment on lines -210 to +226
submit_and_execute_top(&rpc_author, &signed_getter.clone().into(), &shielding_key, shard)
.unwrap();
submit_and_execute_top(&rpc_author, &direct_top(signed_call.clone()), &shielding_key, shard)
.unwrap();
submit_operation_to_top_pool(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, this changed quite a while ago, thanks! 👍

Also separated the execution and block/confirmation composition.
The is in preparation for moving these parts into the sidechain crate.
@murerfel
murerfelforce-pushed the feature/fm-extract-top-pool-execution branch from e50f4d0 to de5852bCompareNovember 11, 2021 10:06
@murerfel
murerfel merged commit bca26ab into masterNov 11, 2021
@murerfel
murerfel deleted the feature/fm-extract-top-pool-execution branch November 11, 2021 11:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@murerfel@clangenb@haerdib