Skip to content

Commit 11326dc

Browse files
committed
First insertion of the composed operations code.
1 parent 692d3f6 commit 11326dc

File tree

18 files changed

+178
-83
lines changed

18 files changed

+178
-83
lines changed

linera-chain/src/block_tracker.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,20 @@ impl<'resources, 'blobs> BlockExecutionTracker<'resources, 'blobs> {
170170

171171
/// Returns a new TransactionTracker for the current transaction.
172172
fn new_transaction_tracker(&mut self) -> Result<TransactionTracker, ChainError> {
173+
// Convert operation results to Vec<Vec<u8>>
174+
let previous_operation_results = self.operation_results
175+
.iter()
176+
.map(|result| result.0.clone())
177+
.collect();
178+
173179
Ok(TransactionTracker::new(
174180
self.local_time,
175181
self.transaction_index,
176182
self.next_application_index,
177183
self.next_chain_index,
178184
self.oracle_responses()?,
179185
&self.blobs,
186+
previous_operation_results,
180187
))
181188
}
182189

linera-chain/src/data_types.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,14 @@ impl From<&Operation> for OperationMetadata {
181181
},
182182
Operation::User {
183183
application_id,
184-
bytes,
184+
input,
185185
} => OperationMetadata {
186186
operation_type: "User".to_string(),
187187
application_id: Some(*application_id),
188-
user_bytes_hex: Some(hex::encode(bytes)),
188+
user_bytes_hex: Some(match input {
189+
linera_execution::OperationInput::Direct(bytes) => hex::encode(bytes),
190+
linera_execution::OperationInput::Composed => "composed".to_string(),
191+
}),
189192
system_bytes_hex: None,
190193
},
191194
}

linera-chain/src/unit_tests/chain_tests.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use linera_execution::{
2626
committee::{Committee, ValidatorState},
2727
test_utils::{ExpectedCall, MockApplication},
2828
BaseRuntime, ContractRuntime, ExecutionError, ExecutionRuntimeConfig, ExecutionRuntimeContext,
29-
Operation, ResourceControlPolicy, ServiceRuntime, SystemOperation, TestExecutionRuntimeContext,
29+
Operation, OperationInput, ResourceControlPolicy, ServiceRuntime, SystemOperation, TestExecutionRuntimeContext,
3030
};
3131
use linera_views::{
3232
context::{Context as _, MemoryContext, ViewContext},
@@ -313,11 +313,11 @@ async fn test_application_permissions() -> anyhow::Result<()> {
313313
application.expect_call(ExpectedCall::default_finalize());
314314
let app_operation = Operation::User {
315315
application_id,
316-
bytes: b"foo".to_vec(),
316+
input: OperationInput::Direct(b"foo".to_vec()),
317317
};
318318
let another_app_operation = Operation::User {
319319
application_id: another_app_id,
320-
bytes: b"bar".to_vec(),
320+
input: OperationInput::Direct(b"bar".to_vec()),
321321
};
322322

323323
let valid_block = make_first_block(chain_id)
@@ -740,7 +740,7 @@ async fn prepare_test_with_dummy_mock_application(
740740

741741
let block = make_first_block(chain_id).with_operation(Operation::User {
742742
application_id,
743-
bytes: vec![],
743+
input: OperationInput::Direct(vec![]),
744744
});
745745

746746
Ok((application, application_id, chain, block, time))

linera-client/src/benchmark.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use linera_core::{
1919
client::{ChainClient, ChainClientError},
2020
Environment,
2121
};
22-
use linera_execution::{system::SystemOperation, Operation};
22+
use linera_execution::{system::SystemOperation, Operation, OperationInput};
2323
use linera_sdk::abis::fungible::{self, FungibleOperation};
2424
use num_format::{Locale, ToFormattedString};
2525
use prometheus_parse::{HistogramCount, Scrape, Value};
@@ -730,7 +730,7 @@ impl<Env: Environment> Benchmark<Env> {
730730
.expect("should serialize fungible token operation");
731731
Operation::User {
732732
application_id,
733-
bytes,
733+
input: OperationInput::Direct(bytes),
734734
}
735735
}
736736
}

linera-core/src/unit_tests/wasm_worker_tests.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use linera_chain::{
2828
};
2929
use linera_execution::{
3030
system::SystemOperation, test_utils::SystemExecutionState, ExecutionRuntimeContext, Operation,
31-
OperationContext, ResourceController, TransactionTracker, WasmContractModule, WasmRuntime,
31+
OperationInput, OperationContext, ResourceController, TransactionTracker, WasmContractModule, WasmRuntime,
3232
};
3333
use linera_storage::{DbStorage, Storage};
3434
#[cfg(feature = "dynamodb")]
@@ -258,7 +258,7 @@ where
258258
.with_timestamp(3)
259259
.with_operation(Operation::User {
260260
application_id,
261-
bytes: user_operation.clone(),
261+
input: OperationInput::Direct(user_operation.clone()),
262262
});
263263
let operation_context = OperationContext {
264264
chain_id: creator_chain.id(),
@@ -273,7 +273,7 @@ where
273273
operation_context,
274274
Operation::User {
275275
application_id,
276-
bytes: user_operation,
276+
input: OperationInput::Direct(user_operation),
277277
},
278278
&mut TransactionTracker::new(
279279
Timestamp::from(3),
@@ -282,6 +282,7 @@ where
282282
0,
283283
Some(vec![OracleResponse::Blob(application_description_blob_id)]),
284284
&[],
285+
vec![],
285286
),
286287
&mut controller,
287288
)

linera-execution/src/evm/revm.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use crate::{
3838
database::{DatabaseRuntime, StorageStats, EVM_SERVICE_GAS_LIMIT},
3939
},
4040
BaseRuntime, ContractRuntime, ContractSyncRuntimeHandle, DataBlobHash, EvmExecutionError,
41-
EvmRuntime, ExecutionError, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract,
41+
EvmRuntime, ExecutionError, OperationInput, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract,
4242
UserContractInstance, UserContractModule, UserService, UserServiceInstance, UserServiceModule,
4343
};
4444

@@ -1449,7 +1449,8 @@ where
14491449
EvmQuery::Query(vec) => vec,
14501450
EvmQuery::Mutation(operation) => {
14511451
let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1452-
runtime.schedule_operation(operation)?;
1452+
let input = OperationInput::Direct(operation);
1453+
runtime.schedule_operation(input)?;
14531454
return Ok(Vec::new());
14541455
}
14551456
};

linera-execution/src/execution.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ where
132132
next_chain_index,
133133
None,
134134
&[],
135+
vec![], // No previous operation results for testing
135136
);
136137
txn_tracker.add_created_blob(blob);
137138
self.run_user_action(
@@ -310,8 +311,24 @@ where
310311
}
311312
Operation::User {
312313
application_id,
313-
bytes,
314+
input,
314315
} => {
316+
// Get the bytes for the operation based on the input type
317+
let bytes = match input {
318+
crate::OperationInput::Direct(bytes) => bytes.clone(),
319+
crate::OperationInput::Composed => {
320+
// For composed operations, use the result from the last operation
321+
let previous_results = txn_tracker.previous_operation_results();
322+
if previous_results.is_empty() {
323+
return Err(ExecutionError::InternalError(
324+
"Composed operation requires a previous operation result, but none found"
325+
));
326+
}
327+
// Get the last operation result as input
328+
previous_results.last().unwrap().clone()
329+
}
330+
};
331+
315332
self.run_user_action(
316333
application_id,
317334
UserAction::Operation(context, bytes),

linera-execution/src/lib.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ use linera_base::{
4949
vm::VmRuntime,
5050
};
5151
use linera_views::{batch::Batch, ViewError};
52+
use linera_witty::{WitLoad, WitStore, WitType};
5253
use serde::{Deserialize, Serialize};
5354
use system::AdminOperation;
5455
use thiserror::Error;
@@ -679,7 +680,7 @@ pub trait ServiceRuntime: BaseRuntime {
679680
) -> Result<Vec<u8>, ExecutionError>;
680681

681682
/// Schedules an operation to be included in the block proposed after execution.
682-
fn schedule_operation(&mut self, operation: Vec<u8>) -> Result<(), ExecutionError>;
683+
fn schedule_operation(&mut self, input: OperationInput) -> Result<(), ExecutionError>;
683684

684685
/// Checks if the service has exceeded its execution time limit.
685686
fn check_execution_time(&mut self) -> Result<(), ExecutionError>;
@@ -817,17 +818,29 @@ pub trait ContractRuntime: BaseRuntime {
817818
fn write_batch(&mut self, batch: Batch) -> Result<(), ExecutionError>;
818819
}
819820

821+
/// Input for an operation, which can be either direct bytes or a composed operation.
822+
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, WitType, WitLoad, WitStore)]
823+
pub enum OperationInput {
824+
/// Direct input as bytes.
825+
Direct(
826+
#[serde(with = "serde_bytes")]
827+
#[debug(with = "hex_debug")]
828+
Vec<u8>
829+
),
830+
/// Composed input that uses the result from the previous operation in the block.
831+
/// If operation_results is empty, an error should be raised during execution.
832+
Composed,
833+
}
834+
820835
/// An operation to be executed in a block.
821836
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
822837
pub enum Operation {
823838
/// A system operation.
824839
System(Box<SystemOperation>),
825-
/// A user operation (in serialized form).
840+
/// A user operation.
826841
User {
827842
application_id: ApplicationId,
828-
#[serde(with = "serde_bytes")]
829-
#[debug(with = "hex_debug")]
830-
bytes: Vec<u8>,
843+
input: OperationInput,
831844
},
832845
}
833846

@@ -1176,10 +1189,20 @@ impl Operation {
11761189
) -> Result<Self, bcs::Error> {
11771190
Ok(Operation::User {
11781191
application_id,
1179-
bytes: bcs::to_bytes(&operation)?,
1192+
input: OperationInput::Direct(bcs::to_bytes(&operation)?),
11801193
})
11811194
}
11821195

1196+
/// Creates a new composed user application operation that uses the result from the
1197+
/// previous operation as input.
1198+
#[cfg(with_testing)]
1199+
pub fn user_composed(application_id: ApplicationId) -> Self {
1200+
Operation::User {
1201+
application_id,
1202+
input: OperationInput::Composed,
1203+
}
1204+
}
1205+
11831206
/// Returns a reference to the [`SystemOperation`] in this [`Operation`], if this [`Operation`]
11841207
/// is for the system application.
11851208
pub fn as_system_operation(&self) -> Option<&SystemOperation> {

linera-execution/src/resources.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,16 @@ where
238238
self.update_balance(self.policy.operation)?;
239239
match operation {
240240
Operation::System(_) => Ok(()),
241-
Operation::User { bytes, .. } => {
242-
let size = bytes.len();
241+
Operation::User { input, .. } => {
242+
let size = match input {
243+
crate::OperationInput::Direct(bytes) => bytes.len(),
244+
crate::OperationInput::Composed => {
245+
// For composed operations, we don't know the size until execution time
246+
// Since the input comes from the previous operation result.
247+
// We'll use 0 for now but this might need to be revisited.
248+
0
249+
}
250+
};
243251
self.tracker.as_mut().operation_bytes = self
244252
.tracker
245253
.as_mut()

linera-execution/src/runtime.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::{
3333
util::{ReceiverExt, UnboundedSenderExt},
3434
ApplicationDescription, ApplicationId, BaseRuntime, ContractRuntime, DataBlobHash,
3535
ExecutionError, FinalizeContext, Message, MessageContext, MessageKind, ModuleId, Operation,
36-
OutgoingMessage, QueryContext, QueryOutcome, ServiceRuntime, TransactionTracker,
36+
OperationInput, OutgoingMessage, QueryContext, QueryOutcome, ServiceRuntime, TransactionTracker,
3737
UserContractCode, UserContractInstance, UserServiceCode, UserServiceInstance,
3838
MAX_STREAM_NAME_LEN,
3939
};
@@ -1809,13 +1809,13 @@ impl ServiceRuntime for ServiceSyncRuntimeHandle {
18091809
Ok(response)
18101810
}
18111811

1812-
fn schedule_operation(&mut self, operation: Vec<u8>) -> Result<(), ExecutionError> {
1812+
fn schedule_operation(&mut self, input: OperationInput) -> Result<(), ExecutionError> {
18131813
let mut this = self.inner();
18141814
let application_id = this.current_application().id;
18151815

18161816
this.scheduled_operations.push(Operation::User {
18171817
application_id,
1818-
bytes: operation,
1818+
input,
18191819
});
18201820

18211821
Ok(())

0 commit comments

Comments
 (0)