Skip to content
This repository has been archived by the owner on Aug 2, 2024. It is now read-only.

Commit

Permalink
fix eth da for sovereign mode, add header to calldata (#1363)
Browse files Browse the repository at this point in the history
  • Loading branch information
apoorvsadana authored Jan 16, 2024
1 parent fd064e1 commit 8c285b4
Show file tree
Hide file tree
Showing 12 changed files with 140 additions and 70 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Next release

- chore: add headers to da calldata, fix eth da in sovereign mode
- refacto(simulate_tx): move logic to the client
- chore: added ca-certificate in DockerFile for SSL related issues
- chore(primitives/commitment): remove crate
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/client/commitment-state-diff/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ sp-blockchain = { workspace = true }
sp-runtime = { workspace = true, default-features = true }

# Madara
mc-db = { workspace = true, default-features = true }
mp-digest-log = { workspace = true, default-features = true }
mp-hashers = { workspace = true, default-features = true }
mp-storage = { workspace = true, default-features = true }
Expand Down
53 changes: 40 additions & 13 deletions crates/client/commitment-state-diff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,39 @@ use sp_blockchain::HeaderBackend;
use sp_runtime::traits::{Block as BlockT, Header};
use starknet_api::api_core::{ClassHash, CompiledClassHash, ContractAddress, Nonce, PatriciaKey};
use starknet_api::block::BlockHash;
use starknet_api::hash::StarkFelt;
use starknet_api::hash::{StarkFelt, StarkHash};
use starknet_api::state::{StorageKey as StarknetStorageKey, ThinStateDiff};
use thiserror::Error;

pub struct BlockDAData(pub BlockHash, pub ThinStateDiff, pub usize);
#[derive(Clone)]
pub struct BlockDAData {
pub block_hash: BlockHash,
pub state_diff: ThinStateDiff,
pub num_addr_accessed: usize,
pub block_number: u64,
pub config_hash: StarkHash,
pub new_state_root: StarkHash,
pub previous_state_root: StarkHash,
}

pub struct CommitmentStateDiffWorker<B: BlockT, C, H> {
client: Arc<C>,
storage_event_stream: StorageEventStream<B::Hash>,
tx: mpsc::Sender<BlockDAData>,
msg: Option<BlockDAData>,
backend: Arc<mc_db::Backend<B>>,
phantom: PhantomData<H>,
}

impl<B: BlockT, C, H> CommitmentStateDiffWorker<B, C, H>
where
C: BlockchainEvents<B>,
{
pub fn new(client: Arc<C>, tx: mpsc::Sender<BlockDAData>) -> Self {
pub fn new(client: Arc<C>, backend: Arc<mc_db::Backend<B>>, tx: mpsc::Sender<BlockDAData>) -> Self {
let storage_event_stream = client
.storage_changes_notification_stream(None, None)
.expect("the node storage changes notification stream should be up and running");
Self { client, storage_event_stream, tx, msg: Default::default(), phantom: PhantomData }
Self { client, storage_event_stream, tx, msg: Default::default(), backend, phantom: PhantomData }
}
}

Expand Down Expand Up @@ -66,7 +76,11 @@ where
Poll::Ready(Some(storage_notification)) => {
let block_hash = storage_notification.block;

match build_commitment_state_diff::<B, C, H>(self_as_mut.client.clone(), storage_notification) {
match build_commitment_state_diff::<B, C, H>(
self_as_mut.client.clone(),
self_as_mut.backend.clone(),
storage_notification,
) {
Ok(msg) => self_as_mut.msg = Some(msg),
Err(e) => {
log::error!(
Expand Down Expand Up @@ -119,10 +133,13 @@ enum BuildCommitmentStateDiffError {
BlockNotFound,
#[error("digest log not found")]
DigestLogNotFound(#[from] mp_digest_log::FindLogError),
#[error("failed to get config hash")]
FailedToGetConfigHash(#[from] sp_api::ApiError),
}

fn build_commitment_state_diff<B: BlockT, C, H>(
client: Arc<C>,
backend: Arc<mc_db::Backend<B>>,
storage_notification: StorageNotification<B::Hash>,
) -> Result<BlockDAData, BuildCommitmentStateDiffError>
where
Expand All @@ -131,13 +148,6 @@ where
C: HeaderBackend<B>,
H: HasherT,
{
let starknet_block_hash = {
let header = client.header(storage_notification.block)?.ok_or(BuildCommitmentStateDiffError::BlockNotFound)?;
let digest = header.digest();
let block = mp_digest_log::find_starknet_block(digest)?;
block.header().hash::<H>().into()
};

let mut accessed_addrs: IndexSet<ContractAddress> = IndexSet::new();
let mut commitment_state_diff = ThinStateDiff {
declared_classes: IndexMap::new(),
Expand Down Expand Up @@ -216,5 +226,22 @@ where
}
}

Ok(BlockDAData(starknet_block_hash, commitment_state_diff, accessed_addrs.len()))
let current_block = {
let header = client.header(storage_notification.block)?.ok_or(BuildCommitmentStateDiffError::BlockNotFound)?;
let digest = header.digest();
mp_digest_log::find_starknet_block(digest)?
};

let config_hash = client.runtime_api().config_hash(storage_notification.block)?;

Ok(BlockDAData {
block_hash: current_block.header().hash::<H>().into(),
state_diff: commitment_state_diff,
num_addr_accessed: accessed_addrs.len(),
block_number: current_block.header().block_number,
config_hash,
// TODO: fix when we implement state root
new_state_root: backend.temporary_global_state_root_getter(),
previous_state_root: backend.temporary_global_state_root_getter(),
})
}
36 changes: 26 additions & 10 deletions crates/client/data-availability/src/ethereum/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,40 @@ pub struct EthereumClient {
#[async_trait]
impl DaClient for EthereumClient {
async fn publish_state_diff(&self, state_diff: Vec<U256>) -> Result<()> {
abigen!(
STARKNET,
r#"[
function updateState(uint256[] calldata programOutput, uint256 onchainDataHash, uint256 onchainDataSize) external
]"#,
);

let core_contracts = STARKNET::new(self.cc_address, self.signer.clone());
log::debug!("State Update: {:?}", state_diff);
let fmt_tx = match self.mode {
DaMode::Sovereign => {
abigen!(
STARKNET,
r#"[
function updateState(uint256[] calldata programOutput) external
]"#,
);

let core_contracts = STARKNET::new(self.cc_address, self.signer.clone());
core_contracts.update_state(state_diff)
}
_ => {
abigen!(
STARKNET,
r#"[
function updateState(uint256[] calldata programOutput, uint256 onchainDataHash, uint256 onchainDataSize) external
]"#,
);

let core_contracts = STARKNET::new(self.cc_address, self.signer.clone());
core_contracts.update_state(state_diff, U256::default(), U256::default())
}
};

let fmt_tx = core_contracts.update_state(state_diff, U256::default(), U256::default());
let tx = fmt_tx
.send()
.await
.map_err(|e| anyhow::anyhow!("ethereum send update err: {e}"))?
.await
.map_err(|e| anyhow::anyhow!("ethereum poll update err: {e}"))?;

log::info!("State Update: {:?}", tx);
log::debug!("State Update: {:?}", tx);
Ok(())
}

Expand Down
30 changes: 16 additions & 14 deletions crates/client/data-availability/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,26 +129,29 @@ where
}
}
}
while let Some(BlockDAData(starknet_block_hash, csd, num_addr_accessed)) = state_diffs_rx.next().await {
log::info!("Received state diff for block {starknet_block_hash}");
while let Some(block_da_data) = state_diffs_rx.next().await {
log::info!("Received state diff for block {}", block_da_data.block_hash);

let da_metrics = da_metrics.clone();
let da_client = da_client.clone();
let madara_backend = madara_backend.clone();
tokio::spawn(async move {
let prove_state_start = time::Instant::now();

if let Err(err) =
prove(da_client.get_mode(), starknet_block_hash, &csd, num_addr_accessed, madara_backend.clone())
.await
if let Err(err) = prove(
da_client.get_mode(),
block_da_data.block_hash,
&block_da_data.state_diff,
block_da_data.num_addr_accessed,
madara_backend.clone(),
)
.await
{
log::error!("Failed to prove block: {err}");
}
let prove_state_end = time::Instant::now();

if let Err(err) =
update_state::<B, H>(madara_backend, da_client, starknet_block_hash, csd, num_addr_accessed).await
{
if let Err(err) = update_state::<B, H>(madara_backend, da_client, block_da_data).await {
log::error!("Failed to update the DA state: {err}");
};
let update_state_end = time::Instant::now();
Expand Down Expand Up @@ -200,14 +203,13 @@ pub async fn prove<B: BlockT>(
pub async fn update_state<B: BlockT, H: HasherT>(
madara_backend: Arc<mc_db::Backend<B>>,
da_client: Arc<dyn DaClient + Send + Sync>,
starknet_block_hash: BlockHash,
csd: ThinStateDiff,
num_addr_accessed: usize,
block_da_data: BlockDAData,
) -> Result<(), anyhow::Error> {
let block_hash = block_da_data.block_hash;
// store the state diff
madara_backend
.da()
.store_state_diff(&starknet_block_hash, state_diff_to_calldata(csd, num_addr_accessed))
.store_state_diff(&block_hash, state_diff_to_calldata(block_da_data))
.map_err(|e| anyhow!("{e}"))?;

// Query last written state
Expand All @@ -221,11 +223,11 @@ pub async fn update_state<B: BlockT, H: HasherT>(
// Write the publish state diff of last_proved + 1
log::info!("validity da mode not implemented");
}
DaMode::Sovereign => match madara_backend.da().state_diff(&starknet_block_hash) {
DaMode::Sovereign => match madara_backend.da().state_diff(&block_hash) {
Ok(state_diff) => {
da_client.publish_state_diff(state_diff).await.map_err(|e| anyhow!("DA PUBLISH ERROR: {e}"))?;
}
Err(e) => Err(anyhow!("could not pull state diff for block {starknet_block_hash}: {e}"))?,
Err(e) => Err(anyhow!("could not pull state diff for block {}: {}", block_hash, e))?,
},
DaMode::Volition => log::info!("volition da mode not implemented"),
};
Expand Down
40 changes: 27 additions & 13 deletions crates/client/data-availability/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
use ethers::types::U256;
use mc_commitment_state_diff::BlockDAData;
use starknet_api::api_core::{Nonce, PatriciaKey};
use starknet_api::hash::StarkFelt;
use starknet_api::state::ThinStateDiff;
use url::{ParseError, Url};

const CLASS_FLAG_TRUE: &str = "0x100000000000000000000000000000001"; // 2 ^ 128 + 1
const NONCE_BASE: &str = "0x10000000000000000"; // 2 ^ 64

/// DA calldata encoding:
/// - https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/on-chain-data
pub fn state_diff_to_calldata(mut state_diff: ThinStateDiff, num_addrs_accessed: usize) -> Vec<U256> {
let mut calldata: Vec<U256> = Vec::new();

calldata.push(U256::from(num_addrs_accessed));
pub fn state_diff_to_calldata(mut block_da_data: BlockDAData) -> Vec<U256> {
// pushing the headers and num_addr_accessed
let mut calldata: Vec<U256> = vec![
U256::from_big_endian(&block_da_data.previous_state_root.0), // prev merkle root
U256::from_big_endian(&block_da_data.new_state_root.0), // new merkle root
U256::from(block_da_data.block_number), // block number
U256::from_big_endian(&block_da_data.block_hash.0.0), // block hash
U256::from_big_endian(&block_da_data.config_hash.0), // config hash,
U256::from(block_da_data.num_addr_accessed), // num_addr_accessed
];

// Loop over storage diffs
for (addr, writes) in state_diff.storage_diffs {
for (addr, writes) in block_da_data.state_diff.storage_diffs {
calldata.push(U256::from_big_endian(&addr.0.key().0));

let class_flag = state_diff.deployed_contracts.get(&addr).or_else(|| state_diff.replaced_classes.get(&addr));
let class_flag = block_da_data
.state_diff
.deployed_contracts
.get(&addr)
.or_else(|| block_da_data.state_diff.replaced_classes.get(&addr));

let nonce = state_diff.nonces.remove(&addr);
let nonce = block_da_data.state_diff.nonces.remove(&addr);
calldata.push(da_word(class_flag.is_some(), nonce, writes.len() as u64));

if let Some(class_hash) = class_flag {
Expand All @@ -34,10 +44,14 @@ pub fn state_diff_to_calldata(mut state_diff: ThinStateDiff, num_addrs_accessed:
}

// Handle nonces
for (addr, nonce) in state_diff.nonces {
for (addr, nonce) in block_da_data.state_diff.nonces {
calldata.push(U256::from_big_endian(&addr.0.key().0));

let class_flag = state_diff.deployed_contracts.get(&addr).or_else(|| state_diff.replaced_classes.get(&addr));
let class_flag = block_da_data
.state_diff
.deployed_contracts
.get(&addr)
.or_else(|| block_da_data.state_diff.replaced_classes.get(&addr));

calldata.push(da_word(class_flag.is_some(), Some(nonce), 0_u64));
if let Some(class_hash) = class_flag {
Expand All @@ -46,17 +60,17 @@ pub fn state_diff_to_calldata(mut state_diff: ThinStateDiff, num_addrs_accessed:
}

// Handle deployed contracts
for (addr, class_hash) in state_diff.deployed_contracts {
for (addr, class_hash) in block_da_data.state_diff.deployed_contracts {
calldata.push(U256::from_big_endian(&addr.0.key().0));

calldata.push(da_word(true, None, 0_u64));
calldata.push(U256::from_big_endian(class_hash.0.bytes()));
}

// Handle replaced classes
calldata.push(U256::from(state_diff.declared_classes.len()));
calldata.push(U256::from(block_da_data.state_diff.declared_classes.len()));

for (class_hash, compiled_class_hash) in &state_diff.declared_classes {
for (class_hash, compiled_class_hash) in &block_da_data.state_diff.declared_classes {
calldata.push(U256::from_big_endian(class_hash.0.bytes()));
calldata.push(U256::from_big_endian(compiled_class_hash.0.bytes()));
}
Expand Down
17 changes: 2 additions & 15 deletions crates/client/settlement/src/sync_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::sync::Arc;
use futures::StreamExt;
use futures_timer::Delay;
use mp_block::Block as StarknetBlock;
use mp_felt::Felt252Wrapper;
use mp_hashers::HasherT;
use mp_messages::{MessageL1ToL2, MessageL2ToL1};
use mp_snos_output::StarknetOsOutput;
Expand All @@ -15,15 +14,12 @@ use sp_api::{HeaderT, ProvideRuntimeApi};
use sp_arithmetic::traits::UniqueSaturatedInto;
use sp_blockchain::HeaderBackend;
use sp_runtime::traits::Block as BlockT;
use starknet_api::hash::{pedersen_hash_array, StarkFelt, StarkHash};
use starknet_api::hash::StarkHash;
use starknet_api::transaction::TransactionHash;
use starknet_crypto::FieldElement;

use crate::errors::Error;
use crate::{Result, RetryStrategy, SettlementProvider, SettlementWorker, StarknetSpec, StarknetState};

pub const SN_OS_CONFIG_HASH_VERSION: &str = "StarknetOsConfig1";

impl<B, H, SC> SettlementWorker<B, H, SC>
where
B: BlockT,
Expand Down Expand Up @@ -187,16 +183,7 @@ where
return Err(Error::ProgramHashMismatch { expected: program_hash, actual: starknet_spec.program_hash });
}

let chain_id = substrate_client.runtime_api().chain_id(substrate_hash)?;
let fee_token_address = substrate_client.runtime_api().fee_token_address(substrate_hash)?;

let config_hash = pedersen_hash_array(&[
StarkFelt::from(Felt252Wrapper::from(
FieldElement::from_byte_slice_be(SN_OS_CONFIG_HASH_VERSION.as_bytes()).unwrap(),
)),
chain_id.into(),
fee_token_address.0.0,
]);
let config_hash = substrate_client.runtime_api().config_hash(substrate_hash)?;

if starknet_spec.config_hash != config_hash {
return Err(Error::ConfigHashMismatch { expected: config_hash, actual: starknet_spec.config_hash });
Expand Down
8 changes: 6 additions & 2 deletions crates/node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,12 @@ pub fn new_full(
task_manager.spawn_essential_handle().spawn(
"commitment-state-diff",
Some("madara"),
CommitmentStateDiffWorker::<_, _, StarknetHasher>::new(client.clone(), commitment_state_diff_tx)
.for_each(|()| future::ready(())),
CommitmentStateDiffWorker::<_, _, StarknetHasher>::new(
client.clone(),
madara_backend.clone(),
commitment_state_diff_tx,
)
.for_each(|()| future::ready(())),
);

let da_client: Arc<dyn DaClient + Send + Sync> = match da_layer {
Expand Down
Loading

0 comments on commit 8c285b4

Please sign in to comment.