truthlinked_runtime/
compiler_aware.rs1use std::collections::HashSet;
6
7use truthlinked_core::pq_execution::{AccountId, Transaction, TransactionIntent};
8
9use crate::cells::CellAccount;
10
11#[derive(Debug, Clone)]
12pub struct ConcreteConflictDomain {
13 pub reads: HashSet<StorageKey>,
14 pub writes: HashSet<StorageKey>,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub enum StorageKey {
19 Account(AccountId),
20 CellStorage(AccountId, [u8; 32]),
21 Global(String),
22 Unknown([u8; 32]),
23}
24
25impl ConcreteConflictDomain {
26 pub fn conflicts_with(&self, other: &Self) -> bool {
27 if self.writes.iter().any(|w| other.writes.contains(w)) {
28 return true;
29 }
30 if self.reads.iter().any(|r| other.writes.contains(r)) {
31 return true;
32 }
33 if self.writes.iter().any(|w| other.reads.contains(w)) {
34 return true;
35 }
36 false
37 }
38
39 pub fn from_transaction(
40 tx: &Transaction,
41 cell: Option<&CellAccount>,
42 cells: &std::collections::HashMap<AccountId, CellAccount>,
43 ) -> Self {
44 let mut reads = HashSet::new();
45 let mut writes = HashSet::new();
46
47 match &tx.intent {
48 TransactionIntent::Transfer { recipient, .. }
49 | TransactionIntent::Claim { recipient, .. } => {
50 writes.insert(StorageKey::Account(tx.sender));
51 writes.insert(StorageKey::Account(*recipient));
52 }
53 TransactionIntent::BatchTransfer { transfers } => {
54 writes.insert(StorageKey::Account(tx.sender));
55 for t in transfers {
56 writes.insert(StorageKey::Account(t.recipient));
57 }
58 }
59 TransactionIntent::TransferToName { .. }
60 | TransactionIntent::BatchTransferToName { .. } => {
61 writes.insert(StorageKey::Account(tx.sender));
63 writes.insert(StorageKey::Global("name_registry".to_string()));
64 }
65 TransactionIntent::DepositCompute { .. }
66 | TransactionIntent::WithdrawCompute { .. }
67 | TransactionIntent::WrapTRTH { .. }
68 | TransactionIntent::UnwrapTRTH { .. } => {
69 writes.insert(StorageKey::Account(tx.sender));
70 }
71
72 TransactionIntent::TokenTransfer { token_cell, .. } => {
73 writes.insert(StorageKey::CellStorage(*token_cell, tx.sender));
74 }
75 TransactionIntent::CloseCell { cell_id } => {
76 writes.insert(StorageKey::CellStorage(*cell_id, *cell_id));
77 }
78 TransactionIntent::ProposeCellUpgrade { cell_id, .. }
79 | TransactionIntent::ProposeCellOwnershipTransfer { cell_id, .. }
80 | TransactionIntent::ProposeCellMakeImmutable { cell_id, .. }
81 | TransactionIntent::VoteCellProposal { cell_id, .. }
82 | TransactionIntent::ExecuteCellProposal { cell_id, .. } => {
83 writes.insert(StorageKey::CellStorage(*cell_id, *cell_id));
84 }
85 TransactionIntent::ProposeTokenAuthority { .. }
86 | TransactionIntent::VoteTokenAuthority { .. }
87 | TransactionIntent::CallSystem { .. }
88 | TransactionIntent::ProposeUrl { .. }
89 | TransactionIntent::VoteUrl { .. }
90 | TransactionIntent::ReportMaliciousUrl { .. } => {
91 writes.insert(StorageKey::Global("system".to_string()));
92 }
93
94 TransactionIntent::CallCell {
95 cell_id, calldata, ..
96 } => {
97 if let Some(cell) = cell {
98 for read_key in &cell.declared_reads {
99 reads.insert(StorageKey::CellStorage(*cell_id, *read_key));
100 }
101 for write_key in &cell.declared_writes {
102 if !cell.commutative_keys.contains(write_key) {
103 writes.insert(StorageKey::CellStorage(*cell_id, *write_key));
104 }
105 }
106
107 if !cell.storage_key_specs.is_empty() {
108 for spec in &cell.storage_key_specs {
109 let end = match spec.offset.checked_add(spec.len) {
110 Some(v) => v,
111 None => continue,
112 };
113 if spec.len == 32 && calldata.len() >= end {
114 let mut user_key = [0u8; 32];
115 user_key.copy_from_slice(&calldata[spec.offset..end]);
116 if !cell.commutative_keys.contains(&user_key) {
117 writes.insert(StorageKey::CellStorage(*cell_id, user_key));
118 }
119 }
120 }
121 }
122 } else {
123 writes.insert(StorageKey::Global("global".to_string()));
124 }
125 }
126
127 TransactionIntent::CallCellChain { calls, .. } => {
128 for call in calls {
129 if let Some(c) = cells.get(&call.cell_id) {
130 for read_key in &c.declared_reads {
131 reads.insert(StorageKey::CellStorage(call.cell_id, *read_key));
132 }
133 for write_key in &c.declared_writes {
134 if !c.commutative_keys.contains(write_key) {
135 writes.insert(StorageKey::CellStorage(call.cell_id, *write_key));
136 }
137 }
138 if !c.storage_key_specs.is_empty() {
139 for spec in &c.storage_key_specs {
140 let end = match spec.offset.checked_add(spec.len) {
141 Some(v) => v,
142 None => continue,
143 };
144 if spec.len == 32 && call.calldata.len() >= end {
145 let mut user_key = [0u8; 32];
146 user_key.copy_from_slice(&call.calldata[spec.offset..end]);
147 if !c.commutative_keys.contains(&user_key) {
148 writes.insert(StorageKey::CellStorage(
149 call.cell_id,
150 user_key,
151 ));
152 }
153 }
154 }
155 }
156 } else {
157 writes.insert(StorageKey::Global("global".to_string()));
159 }
160 }
161 }
162
163 TransactionIntent::RegisterMcpTool { .. }
165 | TransactionIntent::RegisterMcpResource { .. }
166 | TransactionIntent::RegisterMcpPrompt { .. }
167 | TransactionIntent::RegisterAgent { .. }
168 | TransactionIntent::SuspendAgent { .. }
169 | TransactionIntent::ReinstateAgent { .. }
170 | TransactionIntent::McpToolCall { .. }
171 | TransactionIntent::PrivateBalanceInit { .. }
172 | TransactionIntent::PrivateBalanceDeposit { .. }
173 | TransactionIntent::PrivateBalanceWithdraw { .. }
174 | TransactionIntent::PrivateBalanceConfidentialTransfer { .. }
175 | TransactionIntent::SubmitOracleCommit { .. }
176 | TransactionIntent::SubmitOracleReveal { .. }
177 | TransactionIntent::SetCellVisibility { .. }
178 | TransactionIntent::MintNFT { .. }
179 | TransactionIntent::TransferNFT { .. }
180 | TransactionIntent::BurnNFT { .. }
181 | TransactionIntent::ApproveNFT { .. }
182 | TransactionIntent::DeployCell { .. }
183 | TransactionIntent::DeployToken { .. }
184 | TransactionIntent::UpgradeCell { .. }
185 | TransactionIntent::TransferOwnership { .. }
186 | TransactionIntent::AcceptOwnership { .. }
187 | TransactionIntent::MakeImmutable { .. }
188 | TransactionIntent::TokenMint { .. }
189 | TransactionIntent::TokenBurn { .. }
190 | TransactionIntent::TokenFreeze { .. }
191 | TransactionIntent::TokenThaw { .. }
192 | TransactionIntent::Stake { .. }
193 | TransactionIntent::Unstake { .. }
194 | TransactionIntent::WithdrawStake
195 | TransactionIntent::Unjail
196 | TransactionIntent::RotateKey { .. } => {
197 writes.insert(StorageKey::Global("global".to_string()));
198 }
199 }
200
201 ConcreteConflictDomain { reads, writes }
202 }
203}
204
205pub fn partition_by_compiler_domains(
206 batch: &[Transaction],
207 cells: &std::collections::HashMap<AccountId, CellAccount>,
208) -> Vec<Vec<usize>> {
209 let mut partitions: Vec<Vec<usize>> = Vec::new();
210 let mut domains: Vec<ConcreteConflictDomain> = Vec::new();
211
212 for (tx_idx, tx) in batch.iter().enumerate() {
213 let cell = match &tx.intent {
214 TransactionIntent::CallCell { cell_id, .. } => cells.get(cell_id),
215 TransactionIntent::CallCellChain { calls, .. } => {
216 calls.get(0).and_then(|c| cells.get(&c.cell_id))
217 }
218 _ => None,
219 };
220 let domain = ConcreteConflictDomain::from_transaction(tx, cell, cells);
221
222 let mut placed = false;
223 for (part_idx, part_domain) in domains.iter_mut().enumerate() {
224 if !domain.conflicts_with(part_domain) {
225 part_domain.reads.extend(domain.reads.iter().cloned());
226 part_domain.writes.extend(domain.writes.iter().cloned());
227 partitions[part_idx].push(tx_idx);
228 placed = true;
229 break;
230 }
231 }
232 if !placed {
233 partitions.push(vec![tx_idx]);
234 domains.push(domain);
235 }
236 }
237
238 partitions
239}