Repository: linera-io/linera-protocol
Pull request #3598: Add missing options from ResourceControlPolicy.
Author: login: MathieuDutSik
Created: 2025-03-19T10:14:09Z | Merged: 2025-03-19T17:50:26Z

## Motivation

A reading of `ResourceControlPolicy` in `policy.rs` and `ResourceControlPolicy` in `client_options.rs` revealed some discrepancies which are most likely oversights.

Fixes #3532 

## Proposal

Implement the needed insert and rename `http_allow_list` as `http_request_allow_list`.

## Test Plan

The CI.

## Release Plan

Normal release process.

## Links

Closes #3532.

Linked issue #3532: Update `resource-control-policy` command with missing configuration parameters
# Motivation

The `linera resource-control-policy` command allows changing some options in the `ResourceControlPolicy` specified in an `Epoch`. However, some configuration options are missing from the command.

# Proposal

Tweak the implementation to do something like:

```rust
let existing_policy = // From committee
let new_policy = ResourceControlPolicy {
    policy: policy_option.unwrap_or(existing_policy.policy),
    // etc.
};
```

So that new fields added to `ResourceControlPolicy` force new options to be written for the CLI.

Diff:
diff --git a/CLI.md b/CLI.md
index 781911bbacc6..08e3efbfc429 100644
--- a/CLI.md
+++ b/CLI.md
@@ -465,7 +465,10 @@ View or update the resource control policy
 * `--operation-byte <OPERATION_BYTE>` — Set the additional price for each byte in the argument of a user operation
 * `--message <MESSAGE>` — Set the base price of sending a message from a block..
 * `--message-byte <MESSAGE_BYTE>` — Set the additional price for each byte in the argument of a user message
+* `--service-as-oracle-query <SERVICE_AS_ORACLE_QUERY>` — Set the price per query to a service as an oracle
+* `--http-request <HTTP_REQUEST>` — Set the price for performing an HTTP request
 * `--maximum-fuel-per-block <MAXIMUM_FUEL_PER_BLOCK>` — Set the maximum amount of fuel per block
+* `--maximum-service-oracle-execution-ms <MAXIMUM_SERVICE_ORACLE_EXECUTION_MS>` — Set the maximum time in milliseconds that a block can spend executing services as oracles
 * `--maximum-executed-block-size <MAXIMUM_EXECUTED_BLOCK_SIZE>` — Set the maximum size of an executed block, in bytes
 * `--maximum-blob-size <MAXIMUM_BLOB_SIZE>` — Set the maximum size of data blobs, compressed bytecode and other binary blobs, in bytes
 * `--maximum-published-blobs <MAXIMUM_PUBLISHED_BLOBS>` — Set the maximum number of published blobs per block
@@ -473,6 +476,9 @@ View or update the resource control policy
 * `--maximum-block-proposal-size <MAXIMUM_BLOCK_PROPOSAL_SIZE>` — Set the maximum size of a block proposal, in bytes
 * `--maximum-bytes-read-per-block <MAXIMUM_BYTES_READ_PER_BLOCK>` — Set the maximum read data per block
 * `--maximum-bytes-written-per-block <MAXIMUM_BYTES_WRITTEN_PER_BLOCK>` — Set the maximum write data per block
+* `--maximum-http-response-bytes <MAXIMUM_HTTP_RESPONSE_BYTES>` — Set the maximum size in bytes of a received HTTP response
+* `--http-request-timeout-ms <HTTP_REQUEST_TIMEOUT_MS>` — Set the maximum amount of time allowed to wait for an HTTP response
+* `--http-request-allow-list <HTTP_REQUEST_ALLOW_LIST>` — Set the list of hosts that contracts and services can send HTTP requests to
 
 
 
@@ -518,7 +524,10 @@ Create genesis configuration for a Linera deployment. Create initial user chains
 * `--operation-byte-price <OPERATION_BYTE_PRICE>` — Set the additional price for each byte in the argument of a user operation. (This will overwrite value from `--policy-config`)
 * `--message-price <MESSAGE_PRICE>` — Set the base price of sending a message from a block.. (This will overwrite value from `--policy-config`)
 * `--message-byte-price <MESSAGE_BYTE_PRICE>` — Set the additional price for each byte in the argument of a user message. (This will overwrite value from `--policy-config`)
+* `--service-as-oracle-query-price <SERVICE_AS_ORACLE_QUERY_PRICE>` — Set the price per query to a service as an oracle
+* `--http-request-price <HTTP_REQUEST_PRICE>` — Set the price for performing an HTTP request
 * `--maximum-fuel-per-block <MAXIMUM_FUEL_PER_BLOCK>` — Set the maximum amount of fuel per block. (This will overwrite value from `--policy-config`)
+* `--maximum-service-oracle-execution-ms <MAXIMUM_SERVICE_ORACLE_EXECUTION_MS>` — Set the maximum time in milliseconds that a block can spend executing services as oracles
 * `--maximum-executed-block-size <MAXIMUM_EXECUTED_BLOCK_SIZE>` — Set the maximum size of an executed block. (This will overwrite value from `--policy-config`)
 * `--maximum-bytecode-size <MAXIMUM_BYTECODE_SIZE>` — Set the maximum size of decompressed contract or service bytecode, in bytes. (This will overwrite value from `--policy-config`)
 * `--maximum-blob-size <MAXIMUM_BLOB_SIZE>` — Set the maximum size of data blobs, compressed bytecode and other binary blobs, in bytes. (This will overwrite value from `--policy-config`)
@@ -526,7 +535,9 @@ Create genesis configuration for a Linera deployment. Create initial user chains
 * `--maximum-block-proposal-size <MAXIMUM_BLOCK_PROPOSAL_SIZE>` — Set the maximum size of a block proposal, in bytes. (This will overwrite value from `--policy-config`)
 * `--maximum-bytes-read-per-block <MAXIMUM_BYTES_READ_PER_BLOCK>` — Set the maximum read data per block. (This will overwrite value from `--policy-config`)
 * `--maximum-bytes-written-per-block <MAXIMUM_BYTES_WRITTEN_PER_BLOCK>` — Set the maximum write data per block. (This will overwrite value from `--policy-config`)
-* `--http-allow-list <HTTP_ALLOW_LIST>` — Set the list of hosts that contracts and services can send HTTP requests to
+* `--maximum-http-response-bytes <MAXIMUM_HTTP_RESPONSE_BYTES>` — Set the maximum size in bytes of a received HTTP response
+* `--http-request-timeout-ms <HTTP_REQUEST_TIMEOUT_MS>` — Set the maximum amount of time allowed to wait for an HTTP response
+* `--http-request-allow-list <HTTP_REQUEST_ALLOW_LIST>` — Set the list of hosts that contracts and services can send HTTP requests to
 * `--testing-prng-seed <TESTING_PRNG_SEED>` — Force this wallet to generate keys using a PRNG and a given seed. USE FOR TESTING ONLY
 * `--network-name <NETWORK_NAME>` — A unique name to identify this network
 
diff --git a/linera-client/src/client_options.rs b/linera-client/src/client_options.rs
index c370a452fed1..6a60e16aa700 100644
--- a/linera-client/src/client_options.rs
+++ b/linera-client/src/client_options.rs
@@ -567,10 +567,22 @@ pub enum ClientCommand {
         #[arg(long)]
         message_byte: Option<Amount>,
 
+        /// Set the price per query to a service as an oracle.
+        #[arg(long)]
+        service_as_oracle_query: Option<Amount>,
+
+        /// Set the price for performing an HTTP request.
+        #[arg(long)]
+        http_request: Option<Amount>,
+
         /// Set the maximum amount of fuel per block.
         #[arg(long)]
         maximum_fuel_per_block: Option<u64>,
 
+        /// Set the maximum time in milliseconds that a block can spend executing services as oracles.
+        #[arg(long)]
+        maximum_service_oracle_execution_ms: Option<u64>,
+
         /// Set the maximum size of an executed block, in bytes.
         #[arg(long)]
         maximum_executed_block_size: Option<u64>,
@@ -599,6 +611,18 @@ pub enum ClientCommand {
         /// Set the maximum write data per block.
         #[arg(long)]
         maximum_bytes_written_per_block: Option<u64>,
+
+        /// Set the maximum size in bytes of a received HTTP response.
+        #[arg(long)]
+        maximum_http_response_bytes: Option<u64>,
+
+        /// Set the maximum amount of time allowed to wait for an HTTP response.
+        #[arg(long)]
+        http_request_timeout_ms: Option<u64>,
+
+        /// Set the list of hosts that contracts and services can send HTTP requests to.
+        #[arg(long)]
+        http_request_allow_list: Option<Vec<String>>,
     },
 
     /// Send one transfer per chain in bulk mode
@@ -752,11 +776,23 @@ pub enum ClientCommand {
         #[arg(long)]
         message_byte_price: Option<Amount>,
 
+        /// Set the price per query to a service as an oracle.
+        #[arg(long)]
+        service_as_oracle_query_price: Option<Amount>,
+
+        /// Set the price for performing an HTTP request.
+        #[arg(long)]
+        http_request_price: Option<Amount>,
+
         /// Set the maximum amount of fuel per block.
         /// (This will overwrite value from `--policy-config`)
         #[arg(long)]
         maximum_fuel_per_block: Option<u64>,
 
+        /// Set the maximum time in milliseconds that a block can spend executing services as oracles.
+        #[arg(long)]
+        maximum_service_oracle_execution_ms: Option<u64>,
+
         /// Set the maximum size of an executed block.
         /// (This will overwrite value from `--policy-config`)
         #[arg(long)]
@@ -793,9 +829,17 @@ pub enum ClientCommand {
         #[arg(long)]
         maximum_bytes_written_per_block: Option<u64>,
 
+        /// Set the maximum size in bytes of a received HTTP response.
+        #[arg(long)]
+        maximum_http_response_bytes: Option<u64>,
+
+        /// Set the maximum amount of time allowed to wait for an HTTP response.
+        #[arg(long)]
+        http_request_timeout_ms: Option<u64>,
+
         /// Set the list of hosts that contracts and services can send HTTP requests to.
         #[arg(long)]
-        http_allow_list: Option<Vec<String>>,
+        http_request_allow_list: Option<Vec<String>>,
 
         /// Force this wallet to generate keys using a PRNG and a given seed. USE FOR
         /// TESTING ONLY.
diff --git a/linera-service/src/cli_wrappers/wallet.rs b/linera-service/src/cli_wrappers/wallet.rs
index ace16d69a2cd..63241d1f55c4 100644
--- a/linera-service/src/cli_wrappers/wallet.rs
+++ b/linera-service/src/cli_wrappers/wallet.rs
@@ -254,7 +254,9 @@ impl ClientWrapper {
                 &policy_config.to_string().to_kebab_case(),
             ]);
         if let Some(allow_list) = http_allow_list {
-            command.arg("--http-allow-list").arg(allow_list.join(","));
+            command
+                .arg("--http-request-allow-list")
+                .arg(allow_list.join(","));
         }
         if let Some(seed) = self.testing_prng_seed {
             command.arg("--testing-prng-seed").arg(seed.to_string());
diff --git a/linera-service/src/linera/main.rs b/linera-service/src/linera/main.rs
index d223b0eb3dd1..ca622dd968bd 100644
--- a/linera-service/src/linera/main.rs
+++ b/linera-service/src/linera/main.rs
@@ -620,7 +620,10 @@ impl Runnable for Job {
                                     operation_byte,
                                     message,
                                     message_byte,
+                                    service_as_oracle_query,
+                                    http_request,
                                     maximum_fuel_per_block,
+                                    maximum_service_oracle_execution_ms,
                                     maximum_executed_block_size,
                                     maximum_blob_size,
                                     maximum_published_blobs,
@@ -628,88 +631,72 @@ impl Runnable for Job {
                                     maximum_block_proposal_size,
                                     maximum_bytes_read_per_block,
                                     maximum_bytes_written_per_block,
+                                    maximum_http_response_bytes,
+                                    http_request_timeout_ms,
+                                    http_request_allow_list,
                                 } => {
-                                    if let Some(block) = block {
-                                        policy.block = block;
-                                    }
-                                    if let Some(fuel_unit) = fuel_unit {
-                                        policy.fuel_unit = fuel_unit;
-                                    }
-                                    if let Some(read_operation) = read_operation {
-                                        policy.read_operation = read_operation;
-                                    }
-                                    if let Some(write_operation) = write_operation {
-                                        policy.write_operation = write_operation;
-                                    }
-                                    if let Some(byte_read) = byte_read {
-                                        policy.byte_read = byte_read;
-                                    }
-                                    if let Some(byte_written) = byte_written {
-                                        policy.byte_written = byte_written;
-                                    }
-                                    if let Some(blob_read) = blob_read {
-                                        policy.blob_read = blob_read
-                                    }
-                                    if let Some(blob_published) = blob_published {
-                                        policy.blob_published = blob_published
-                                    }
-                                    if let Some(blob_byte_read) = blob_byte_read {
-                                        policy.blob_byte_read = blob_byte_read;
-                                    }
-                                    if let Some(blob_byte_published) = blob_byte_published {
-                                        policy.blob_byte_published = blob_byte_published;
-                                    }
-                                    if let Some(byte_stored) = byte_stored {
-                                        policy.byte_stored = byte_stored;
-                                    }
-                                    if let Some(operation) = operation {
-                                        policy.operation = operation;
-                                    }
-                                    if let Some(operation_byte) = operation_byte {
-                                        policy.operation_byte = operation_byte;
-                                    }
-                                    if let Some(message) = message {
-                                        policy.message = message;
-                                    }
-                                    if let Some(message_byte) = message_byte {
-                                        policy.message_byte = message_byte;
-                                    }
-                                    if let Some(maximum_fuel_per_block) = maximum_fuel_per_block {
-                                        policy.maximum_fuel_per_block = maximum_fuel_per_block;
-                                    }
-                                    if let Some(maximum_executed_block_size) =
-                                        maximum_executed_block_size
-                                    {
-                                        policy.maximum_executed_block_size =
-                                            maximum_executed_block_size;
-                                    }
-                                    if let Some(maximum_bytecode_size) = maximum_bytecode_size {
-                                        policy.maximum_bytecode_size = maximum_bytecode_size;
-                                    }
-                                    if let Some(maximum_blob_size) = maximum_blob_size {
-                                        policy.maximum_blob_size = maximum_blob_size;
-                                    }
-                                    if let Some(maximum_published_blobs) = maximum_published_blobs {
-                                        policy.maximum_published_blobs = maximum_published_blobs;
-                                    }
-                                    if let Some(maximum_block_proposal_size) =
-                                        maximum_block_proposal_size
-                                    {
-                                        policy.maximum_block_proposal_size =
-                                            maximum_block_proposal_size;
-                                    }
-                                    if let Some(maximum_bytes_read_per_block) =
-                                        maximum_bytes_read_per_block
-                                    {
-                                        policy.maximum_bytes_read_per_block =
-                                            maximum_bytes_read_per_block;
-                                    }
-                                    if let Some(maximum_bytes_written_per_block) =
-                                        maximum_bytes_written_per_block
-                                    {
-                                        policy.maximum_bytes_written_per_block =
-                                            maximum_bytes_written_per_block;
-                                    }
+                                    let existing_policy = policy.clone();
+                                    policy = linera_execution::ResourceControlPolicy {
+                                        block: block.unwrap_or(existing_policy.block),
+                                        fuel_unit: fuel_unit.unwrap_or(existing_policy.fuel_unit),
+                                        read_operation: read_operation
+                                            .unwrap_or(existing_policy.read_operation),
+                                        write_operation: write_operation
+                                            .unwrap_or(existing_policy.write_operation),
+                                        byte_read: byte_read.unwrap_or(existing_policy.byte_read),
+                                        byte_written: byte_written
+                                            .unwrap_or(existing_policy.byte_written),
+                                        blob_read: blob_read.unwrap_or(existing_policy.blob_read),
+                                        blob_published: blob_published
+                                            .unwrap_or(existing_policy.blob_published),
+                                        blob_byte_read: blob_byte_read
+                                            .unwrap_or(existing_policy.blob_byte_read),
+                                        blob_byte_published: blob_byte_published
+                                            .unwrap_or(existing_policy.blob_byte_published),
+                                        byte_stored: byte_stored
+                                            .unwrap_or(existing_policy.byte_stored),
+                                        operation: operation.unwrap_or(existing_policy.operation),
+                                        operation_byte: operation_byte
+                                            .unwrap_or(existing_policy.operation_byte),
+                                        message: message.unwrap_or(existing_policy.message),
+                                        message_byte: message_byte
+                                            .unwrap_or(existing_policy.message_byte),
+                                        service_as_oracle_query: service_as_oracle_query
+                                            .unwrap_or(existing_policy.service_as_oracle_query),
+                                        http_request: http_request
+                                            .unwrap_or(existing_policy.http_request),
+                                        maximum_fuel_per_block: maximum_fuel_per_block
+                                            .unwrap_or(existing_policy.maximum_fuel_per_block),
+                                        maximum_service_oracle_execution_ms:
+                                            maximum_service_oracle_execution_ms.unwrap_or(
+                                                existing_policy.maximum_service_oracle_execution_ms,
+                                            ),
+                                        maximum_executed_block_size: maximum_executed_block_size
+                                            .unwrap_or(existing_policy.maximum_executed_block_size),
+                                        maximum_bytecode_size: maximum_bytecode_size
+                                            .unwrap_or(existing_policy.maximum_bytecode_size),
+                                        maximum_blob_size: maximum_blob_size
+                                            .unwrap_or(existing_policy.maximum_blob_size),
+                                        maximum_published_blobs: maximum_published_blobs
+                                            .unwrap_or(existing_policy.maximum_published_blobs),
+                                        maximum_block_proposal_size: maximum_block_proposal_size
+                                            .unwrap_or(existing_policy.maximum_block_proposal_size),
+                                        maximum_bytes_read_per_block: maximum_bytes_read_per_block
+                                            .unwrap_or(
+                                                existing_policy.maximum_bytes_read_per_block,
+                                            ),
+                                        maximum_bytes_written_per_block:
+                                            maximum_bytes_written_per_block.unwrap_or(
+                                                existing_policy.maximum_bytes_written_per_block,
+                                            ),
+                                        maximum_http_response_bytes: maximum_http_response_bytes
+                                            .unwrap_or(existing_policy.maximum_http_response_bytes),
+                                        http_request_timeout_ms: http_request_timeout_ms
+                                            .unwrap_or(existing_policy.http_request_timeout_ms),
+                                        http_request_allow_list: http_request_allow_list
+                                            .map(BTreeSet::from_iter)
+                                            .unwrap_or(existing_policy.http_request_allow_list),
+                                    };
                                     info!("{policy}");
                                     if committee.policy() == &policy {
                                         return Ok(ClientOutcome::Committed(None));
@@ -1430,7 +1417,10 @@ async fn run(options: &ClientOptions) -> Result<i32, anyhow::Error> {
             operation_byte_price,
             message_price,
             message_byte_price,
+            service_as_oracle_query_price,
+            http_request_price,
             maximum_fuel_per_block,
+            maximum_service_oracle_execution_ms,
             maximum_executed_block_size,
             maximum_blob_size,
             maximum_published_blobs,
@@ -1438,86 +1428,62 @@ async fn run(options: &ClientOptions) -> Result<i32, anyhow::Error> {
             maximum_block_proposal_size,
             maximum_bytes_read_per_block,
             maximum_bytes_written_per_block,
+            maximum_http_response_bytes,
+            http_request_timeout_ms,
+            http_request_allow_list,
             testing_prng_seed,
             network_name,
-            http_allow_list,
         } => {
             let start_time = Instant::now();
             let committee_config: CommitteeConfig = util::read_json(committee_config_path)
                 .expect("Unable to read committee config file");
-            let mut policy = policy_config.into_policy();
-            if let Some(block_price) = block_price {
-                policy.block = *block_price;
-            }
-            if let Some(fuel_unit_price) = fuel_unit_price {
-                policy.fuel_unit = *fuel_unit_price;
-            }
-            if let Some(read_operation_price) = read_operation_price {
-                policy.read_operation = *read_operation_price;
-            }
-            if let Some(write_operation_price) = write_operation_price {
-                policy.write_operation = *write_operation_price;
-            }
-            if let Some(byte_read_price) = byte_read_price {
-                policy.byte_read = *byte_read_price;
-            }
-            if let Some(byte_written_price) = byte_written_price {
-                policy.byte_written = *byte_written_price;
-            }
-            if let Some(blob_read_price) = blob_read_price {
-                policy.blob_read = *blob_read_price;
-            }
-            if let Some(blob_published_price) = blob_published_price {
-                policy.blob_published = *blob_published_price;
-            }
-            if let Some(blob_byte_read_price) = blob_byte_read_price {
-                policy.blob_byte_read = *blob_byte_read_price;
-            }
-            if let Some(blob_byte_published_price) = blob_byte_published_price {
-                policy.blob_byte_published = *blob_byte_published_price;
-            }
-            if let Some(byte_stored_price) = byte_stored_price {
-                policy.byte_stored = *byte_stored_price;
-            }
-            if let Some(operation_price) = operation_price {
-                policy.operation = *operation_price;
-            }
-            if let Some(operation_byte_price) = operation_byte_price {
-                policy.operation_byte = *operation_byte_price;
-            }
-            if let Some(message_price) = message_price {
-                policy.message = *message_price;
-            }
-            if let Some(message_byte_price) = message_byte_price {
-                policy.message_byte = *message_byte_price;
-            }
-            if let Some(maximum_fuel_per_block) = maximum_fuel_per_block {
-                policy.maximum_fuel_per_block = *maximum_fuel_per_block;
-            }
-            if let Some(maximum_executed_block_size) = maximum_executed_block_size {
-                policy.maximum_executed_block_size = *maximum_executed_block_size;
-            }
-            if let Some(maximum_blob_size) = maximum_blob_size {
-                policy.maximum_blob_size = *maximum_blob_size;
-            }
-            if let Some(maximum_published_blobs) = maximum_published_blobs {
-                policy.maximum_published_blobs = *maximum_published_blobs;
-            }
-            if let Some(maximum_bytecode_size) = maximum_bytecode_size {
-                policy.maximum_bytecode_size = *maximum_bytecode_size;
-            }
-            if let Some(maximum_block_proposal_size) = maximum_block_proposal_size {
-                policy.maximum_block_proposal_size = *maximum_block_proposal_size;
-            }
-            if let Some(maximum_bytes_read_per_block) = maximum_bytes_read_per_block {
-                policy.maximum_bytes_read_per_block = *maximum_bytes_read_per_block;
-            }
-            if let Some(maximum_bytes_written_per_block) = maximum_bytes_written_per_block {
-                policy.maximum_bytes_written_per_block = *maximum_bytes_written_per_block;
-            }
-            if let Some(http_allow_list) = http_allow_list {
-                policy.http_request_allow_list = BTreeSet::from_iter(http_allow_list.clone());
-            }
+            let existing_policy = policy_config.into_policy();
+            let policy = linera_execution::ResourceControlPolicy {
+                block: block_price.unwrap_or(existing_policy.block),
+                fuel_unit: fuel_unit_price.unwrap_or(existing_policy.fuel_unit),
+                read_operation: read_operation_price.unwrap_or(existing_policy.read_operation),
+                write_operation: write_operation_price.unwrap_or(existing_policy.write_operation),
+                byte_read: byte_read_price.unwrap_or(existing_policy.byte_read),
+                byte_written: byte_written_price.unwrap_or(existing_policy.byte_written),
+                blob_read: blob_read_price.unwrap_or(existing_policy.blob_read),
+                blob_published: blob_published_price.unwrap_or(existing_policy.blob_published),
+                blob_byte_read: blob_byte_read_price.unwrap_or(existing_policy.blob_byte_read),
+                blob_byte_published: blob_byte_published_price
+                    .unwrap_or(existing_policy.blob_byte_published),
+                byte_stored: byte_stored_price.unwrap_or(existing_policy.byte_stored),
+                operation: operation_price.unwrap_or(existing_policy.operation),
+                operation_byte: operation_byte_price.unwrap_or(existing_policy.operation_byte),
+                message: message_price.unwrap_or(existing_policy.message),
+                message_byte: message_byte_price.unwrap_or(existing_policy.message_byte),
+                service_as_oracle_query: service_as_oracle_query_price
+                    .unwrap_or(existing_policy.service_as_oracle_query),
+                http_request: http_request_price.unwrap_or(existing_policy.http_request),
+                maximum_fuel_per_block: maximum_fuel_per_block
+                    .unwrap_or(existing_policy.maximum_fuel_per_block),
+                maximum_service_oracle_execution_ms: maximum_service_oracle_execution_ms
+                    .unwrap_or(existing_policy.maximum_service_oracle_execution_ms),
+                maximum_executed_block_size: maximum_executed_block_size
+                    .unwrap_or(existing_policy.maximum_executed_block_size),
+                maximum_bytecode_size: maximum_bytecode_size
+                    .unwrap_or(existing_policy.maximum_bytecode_size),
+                maximum_blob_size: maximum_blob_size.unwrap_or(existing_policy.maximum_blob_size),
+                maximum_published_blobs: maximum_published_blobs
+                    .unwrap_or(existing_policy.maximum_published_blobs),
+                maximum_block_proposal_size: maximum_block_proposal_size
+                    .unwrap_or(existing_policy.maximum_block_proposal_size),
+                maximum_bytes_read_per_block: maximum_bytes_read_per_block
+                    .unwrap_or(existing_policy.maximum_bytes_read_per_block),
+                maximum_bytes_written_per_block: maximum_bytes_written_per_block
+                    .unwrap_or(existing_policy.maximum_bytes_written_per_block),
+                maximum_http_response_bytes: maximum_http_response_bytes
+                    .unwrap_or(existing_policy.maximum_http_response_bytes),
+                http_request_timeout_ms: http_request_timeout_ms
+                    .unwrap_or(existing_policy.http_request_timeout_ms),
+                http_request_allow_list: http_request_allow_list
+                    .as_ref()
+                    .map(|list| list.iter().cloned().collect())
+                    .unwrap_or(existing_policy.http_request_allow_list),
+            };
             let timestamp = start_timestamp
                 .map(|st| {
                     let micros =


Reviews:
user: login: Twey
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T14:19:12Z
user: login: MathieuDutSik
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T14:31:08Z
user: login: jvff
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T15:01:25Z
user: login: MathieuDutSik
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T16:03:38Z
user: login: MathieuDutSik
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-19T16:07:15Z

Review comments:
diff_hunk: @@ -551,10 +551,22 @@ pub enum ClientCommand {
         #[arg(long)]
         message_byte: Option<Amount>,
 
+        /// Set the price per query to a service as an oracle.
+        #[arg(long)]
+        service_as_oracle_query: Option<Amount>,
+
+        /// Set the price for a performing an HTTP request.
path: linera-client/src/client_options.rs
user: login: jvff
body: Nit: tweaking the phrasing

```suggestion
        /// Set the price for performing an HTTP request.
```
created_at: 2025-03-19T14:18:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -616,84 +616,79 @@ impl Runnable for Job {
                                     operation_byte,
                                     message,
                                     message_byte,
+                                    service_as_oracle_query,
+                                    http_request,
                                     maximum_fuel_per_block,
+                                    maximum_service_oracle_execution_ms,
                                     maximum_executed_block_size,
                                     maximum_blob_size,
                                     maximum_published_blobs,
                                     maximum_bytecode_size,
                                     maximum_block_proposal_size,
                                     maximum_bytes_read_per_block,
                                     maximum_bytes_written_per_block,
+                                    maximum_http_response_bytes,
+                                    http_request_timeout_ms,
+                                    http_request_allow_list,
                                 } => {
-                                    if let Some(block) = block {
-                                        policy.block = block;
-                                    }
-                                    if let Some(fuel_unit) = fuel_unit {
-                                        policy.fuel_unit = fuel_unit;
-                                    }
-                                    if let Some(read_operation) = read_operation {
-                                        policy.read_operation = read_operation;
-                                    }
-                                    if let Some(write_operation) = write_operation {
-                                        policy.write_operation = write_operation;
-                                    }
-                                    if let Some(byte_read) = byte_read {
-                                        policy.byte_read = byte_read;
-                                    }
-                                    if let Some(byte_written) = byte_written {
-                                        policy.byte_written = byte_written;
-                                    }
-                                    if let Some(byte_stored) = byte_stored {
-                                        policy.byte_stored = byte_stored;
-                                    }
-                                    if let Some(operation) = operation {
-                                        policy.operation = operation;
-                                    }
-                                    if let Some(operation_byte) = operation_byte {
-                                        policy.operation_byte = operation_byte;
-                                    }
-                                    if let Some(message) = message {
-                                        policy.message = message;
-                                    }
-                                    if let Some(message_byte) = message_byte {
-                                        policy.message_byte = message_byte;
-                                    }
-                                    if let Some(maximum_fuel_per_block) = maximum_fuel_per_block {
-                                        policy.maximum_fuel_per_block = maximum_fuel_per_block;
-                                    }
-                                    if let Some(maximum_executed_block_size) =
-                                        maximum_executed_block_size
-                                    {
-                                        policy.maximum_executed_block_size =
-                                            maximum_executed_block_size;
-                                    }
-                                    if let Some(maximum_bytecode_size) = maximum_bytecode_size {
-                                        policy.maximum_bytecode_size = maximum_bytecode_size;
-                                    }
-                                    if let Some(maximum_blob_size) = maximum_blob_size {
-                                        policy.maximum_blob_size = maximum_blob_size;
-                                    }
-                                    if let Some(maximum_published_blobs) = maximum_published_blobs {
-                                        policy.maximum_published_blobs = maximum_published_blobs;
-                                    }
-                                    if let Some(maximum_block_proposal_size) =
-                                        maximum_block_proposal_size
-                                    {
-                                        policy.maximum_block_proposal_size =
-                                            maximum_block_proposal_size;
-                                    }
-                                    if let Some(maximum_bytes_read_per_block) =
-                                        maximum_bytes_read_per_block
-                                    {
-                                        policy.maximum_bytes_read_per_block =
-                                            maximum_bytes_read_per_block;
-                                    }
-                                    if let Some(maximum_bytes_written_per_block) =
-                                        maximum_bytes_written_per_block
-                                    {
-                                        policy.maximum_bytes_written_per_block =
-                                            maximum_bytes_written_per_block;
-                                    }
+                                    let existing_policy = policy.clone();
+                                    policy = linera_execution::ResourceControlPolicy {
+                                        block: block.unwrap_or(existing_policy.block),
+                                        fuel_unit: fuel_unit.unwrap_or(existing_policy.fuel_unit),
+                                        read_operation: read_operation
+                                            .unwrap_or(existing_policy.read_operation),
+                                        write_operation: write_operation
+                                            .unwrap_or(existing_policy.write_operation),
+                                        byte_read: byte_read.unwrap_or(existing_policy.byte_read),
+                                        byte_written: byte_written
+                                            .unwrap_or(existing_policy.byte_written),
+                                        byte_stored: byte_stored
+                                            .unwrap_or(existing_policy.byte_stored),
+                                        operation: operation.unwrap_or(existing_policy.operation),
+                                        operation_byte: operation_byte
+                                            .unwrap_or(existing_policy.operation_byte),
+                                        message: message.unwrap_or(existing_policy.message),
+                                        message_byte: message_byte
+                                            .unwrap_or(existing_policy.message_byte),
+                                        service_as_oracle_query: service_as_oracle_query
+                                            .unwrap_or(existing_policy.service_as_oracle_query),
+                                        http_request: http_request
+                                            .unwrap_or(existing_policy.http_request),
+                                        maximum_fuel_per_block: maximum_fuel_per_block
+                                            .unwrap_or(existing_policy.maximum_fuel_per_block),
+                                        maximum_service_oracle_execution_ms:
+                                            maximum_service_oracle_execution_ms.unwrap_or(
+                                                existing_policy.maximum_service_oracle_execution_ms,
+                                            ),
+                                        maximum_executed_block_size: maximum_executed_block_size
+                                            .unwrap_or(existing_policy.maximum_executed_block_size),
+                                        maximum_bytecode_size: maximum_bytecode_size
+                                            .unwrap_or(existing_policy.maximum_bytecode_size),
+                                        maximum_blob_size: maximum_blob_size
+                                            .unwrap_or(existing_policy.maximum_blob_size),
+                                        maximum_published_blobs: maximum_published_blobs
+                                            .unwrap_or(existing_policy.maximum_published_blobs),
+                                        maximum_block_proposal_size: maximum_block_proposal_size
+                                            .unwrap_or(existing_policy.maximum_block_proposal_size),
+                                        maximum_bytes_read_per_block: maximum_bytes_read_per_block
+                                            .unwrap_or(
+                                                existing_policy.maximum_bytes_read_per_block,
+                                            ),
+                                        maximum_bytes_written_per_block:
+                                            maximum_bytes_written_per_block.unwrap_or(
+                                                existing_policy.maximum_bytes_written_per_block,
+                                            ),
+                                        maximum_http_response_bytes: maximum_http_response_bytes
+                                            .unwrap_or(existing_policy.maximum_http_response_bytes),
+                                        http_request_timeout_ms: http_request_timeout_ms
+                                            .unwrap_or(existing_policy.http_request_timeout_ms),
+                                        http_request_allow_list: match http_request_allow_list {
+                                            None => existing_policy.http_request_allow_list,
+                                            Some(http_request_allow_list) => {
+                                                BTreeSet::from_iter(http_request_allow_list)
+                                            }
+                                        },
path: linera-service/src/linera/main.rs
user: login: Twey
body: ```suggestion
                                        http_request_allow_list: http_request_allow_list
                                            .map(BTreeSet::from_iter)
                                            .unwrap_or(existing_policy.http_request_allow_list),
```
? :)
created_at: 2025-03-19T14:19:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -616,84 +616,79 @@ impl Runnable for Job {
                                     operation_byte,
                                     message,
                                     message_byte,
+                                    service_as_oracle_query,
+                                    http_request,
                                     maximum_fuel_per_block,
+                                    maximum_service_oracle_execution_ms,
                                     maximum_executed_block_size,
                                     maximum_blob_size,
                                     maximum_published_blobs,
                                     maximum_bytecode_size,
                                     maximum_block_proposal_size,
                                     maximum_bytes_read_per_block,
                                     maximum_bytes_written_per_block,
+                                    maximum_http_response_bytes,
+                                    http_request_timeout_ms,
+                                    http_request_allow_list,
                                 } => {
-                                    if let Some(block) = block {
-                                        policy.block = block;
-                                    }
-                                    if let Some(fuel_unit) = fuel_unit {
-                                        policy.fuel_unit = fuel_unit;
-                                    }
-                                    if let Some(read_operation) = read_operation {
-                                        policy.read_operation = read_operation;
-                                    }
-                                    if let Some(write_operation) = write_operation {
-                                        policy.write_operation = write_operation;
-                                    }
-                                    if let Some(byte_read) = byte_read {
-                                        policy.byte_read = byte_read;
-                                    }
-                                    if let Some(byte_written) = byte_written {
-                                        policy.byte_written = byte_written;
-                                    }
-                                    if let Some(byte_stored) = byte_stored {
-                                        policy.byte_stored = byte_stored;
-                                    }
-                                    if let Some(operation) = operation {
-                                        policy.operation = operation;
-                                    }
-                                    if let Some(operation_byte) = operation_byte {
-                                        policy.operation_byte = operation_byte;
-                                    }
-                                    if let Some(message) = message {
-                                        policy.message = message;
-                                    }
-                                    if let Some(message_byte) = message_byte {
-                                        policy.message_byte = message_byte;
-                                    }
-                                    if let Some(maximum_fuel_per_block) = maximum_fuel_per_block {
-                                        policy.maximum_fuel_per_block = maximum_fuel_per_block;
-                                    }
-                                    if let Some(maximum_executed_block_size) =
-                                        maximum_executed_block_size
-                                    {
-                                        policy.maximum_executed_block_size =
-                                            maximum_executed_block_size;
-                                    }
-                                    if let Some(maximum_bytecode_size) = maximum_bytecode_size {
-                                        policy.maximum_bytecode_size = maximum_bytecode_size;
-                                    }
-                                    if let Some(maximum_blob_size) = maximum_blob_size {
-                                        policy.maximum_blob_size = maximum_blob_size;
-                                    }
-                                    if let Some(maximum_published_blobs) = maximum_published_blobs {
-                                        policy.maximum_published_blobs = maximum_published_blobs;
-                                    }
-                                    if let Some(maximum_block_proposal_size) =
-                                        maximum_block_proposal_size
-                                    {
-                                        policy.maximum_block_proposal_size =
-                                            maximum_block_proposal_size;
-                                    }
-                                    if let Some(maximum_bytes_read_per_block) =
-                                        maximum_bytes_read_per_block
-                                    {
-                                        policy.maximum_bytes_read_per_block =
-                                            maximum_bytes_read_per_block;
-                                    }
-                                    if let Some(maximum_bytes_written_per_block) =
-                                        maximum_bytes_written_per_block
-                                    {
-                                        policy.maximum_bytes_written_per_block =
-                                            maximum_bytes_written_per_block;
-                                    }
+                                    let existing_policy = policy.clone();
+                                    policy = linera_execution::ResourceControlPolicy {
+                                        block: block.unwrap_or(existing_policy.block),
+                                        fuel_unit: fuel_unit.unwrap_or(existing_policy.fuel_unit),
+                                        read_operation: read_operation
+                                            .unwrap_or(existing_policy.read_operation),
+                                        write_operation: write_operation
+                                            .unwrap_or(existing_policy.write_operation),
+                                        byte_read: byte_read.unwrap_or(existing_policy.byte_read),
+                                        byte_written: byte_written
+                                            .unwrap_or(existing_policy.byte_written),
+                                        byte_stored: byte_stored
+                                            .unwrap_or(existing_policy.byte_stored),
+                                        operation: operation.unwrap_or(existing_policy.operation),
+                                        operation_byte: operation_byte
+                                            .unwrap_or(existing_policy.operation_byte),
+                                        message: message.unwrap_or(existing_policy.message),
+                                        message_byte: message_byte
+                                            .unwrap_or(existing_policy.message_byte),
+                                        service_as_oracle_query: service_as_oracle_query
+                                            .unwrap_or(existing_policy.service_as_oracle_query),
+                                        http_request: http_request
+                                            .unwrap_or(existing_policy.http_request),
+                                        maximum_fuel_per_block: maximum_fuel_per_block
+                                            .unwrap_or(existing_policy.maximum_fuel_per_block),
+                                        maximum_service_oracle_execution_ms:
+                                            maximum_service_oracle_execution_ms.unwrap_or(
+                                                existing_policy.maximum_service_oracle_execution_ms,
+                                            ),
+                                        maximum_executed_block_size: maximum_executed_block_size
+                                            .unwrap_or(existing_policy.maximum_executed_block_size),
+                                        maximum_bytecode_size: maximum_bytecode_size
+                                            .unwrap_or(existing_policy.maximum_bytecode_size),
+                                        maximum_blob_size: maximum_blob_size
+                                            .unwrap_or(existing_policy.maximum_blob_size),
+                                        maximum_published_blobs: maximum_published_blobs
+                                            .unwrap_or(existing_policy.maximum_published_blobs),
+                                        maximum_block_proposal_size: maximum_block_proposal_size
+                                            .unwrap_or(existing_policy.maximum_block_proposal_size),
+                                        maximum_bytes_read_per_block: maximum_bytes_read_per_block
+                                            .unwrap_or(
+                                                existing_policy.maximum_bytes_read_per_block,
+                                            ),
+                                        maximum_bytes_written_per_block:
+                                            maximum_bytes_written_per_block.unwrap_or(
+                                                existing_policy.maximum_bytes_written_per_block,
+                                            ),
+                                        maximum_http_response_bytes: maximum_http_response_bytes
+                                            .unwrap_or(existing_policy.maximum_http_response_bytes),
+                                        http_request_timeout_ms: http_request_timeout_ms
+                                            .unwrap_or(existing_policy.http_request_timeout_ms),
+                                        http_request_allow_list: match http_request_allow_list {
+                                            None => existing_policy.http_request_allow_list,
+                                            Some(http_request_allow_list) => {
+                                                BTreeSet::from_iter(http_request_allow_list)
+                                            }
+                                        },
path: linera-service/src/linera/main.rs
user: login: MathieuDutSik
body: Yes, thank you.
created_at: 2025-03-19T14:31:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1430,94 +1417,76 @@ async fn run(options: &ClientOptions) -> Result<i32, anyhow::Error> {
             operation_byte_price,
             message_price,
             message_byte_price,
+            service_as_oracle_query_price,
+            http_request_price,
             maximum_fuel_per_block,
+            maximum_service_oracle_execution_ms,
             maximum_executed_block_size,
             maximum_blob_size,
             maximum_published_blobs,
             maximum_bytecode_size,
             maximum_block_proposal_size,
             maximum_bytes_read_per_block,
             maximum_bytes_written_per_block,
+            maximum_http_response_bytes,
+            http_request_timeout_ms,
+            http_request_allow_list,
             testing_prng_seed,
             network_name,
-            http_allow_list,
         } => {
             let start_time = Instant::now();
             let committee_config: CommitteeConfig = util::read_json(committee_config_path)
                 .expect("Unable to read committee config file");
-            let mut policy = policy_config.into_policy();
-            if let Some(block_price) = block_price {
-                policy.block = *block_price;
-            }
-            if let Some(fuel_unit_price) = fuel_unit_price {
-                policy.fuel_unit = *fuel_unit_price;
-            }
-            if let Some(read_operation_price) = read_operation_price {
-                policy.read_operation = *read_operation_price;
-            }
-            if let Some(write_operation_price) = write_operation_price {
-                policy.write_operation = *write_operation_price;
-            }
-            if let Some(byte_read_price) = byte_read_price {
-                policy.byte_read = *byte_read_price;
-            }
-            if let Some(byte_written_price) = byte_written_price {
-                policy.byte_written = *byte_written_price;
-            }
-            if let Some(blob_read_price) = blob_read_price {
-                policy.blob_read = *blob_read_price;
-            }
-            if let Some(blob_published_price) = blob_published_price {
-                policy.blob_published = *blob_published_price;
-            }
-            if let Some(blob_byte_read_price) = blob_byte_read_price {
-                policy.blob_byte_read = *blob_byte_read_price;
-            }
-            if let Some(blob_byte_published_price) = blob_byte_published_price {
-                policy.blob_byte_published = *blob_byte_published_price;
-            }
-            if let Some(byte_stored_price) = byte_stored_price {
-                policy.byte_stored = *byte_stored_price;
-            }
-            if let Some(operation_price) = operation_price {
-                policy.operation = *operation_price;
-            }
-            if let Some(operation_byte_price) = operation_byte_price {
-                policy.operation_byte = *operation_byte_price;
-            }
-            if let Some(message_price) = message_price {
-                policy.message = *message_price;
-            }
-            if let Some(message_byte_price) = message_byte_price {
-                policy.message_byte = *message_byte_price;
-            }
-            if let Some(maximum_fuel_per_block) = maximum_fuel_per_block {
-                policy.maximum_fuel_per_block = *maximum_fuel_per_block;
-            }
-            if let Some(maximum_executed_block_size) = maximum_executed_block_size {
-                policy.maximum_executed_block_size = *maximum_executed_block_size;
-            }
-            if let Some(maximum_blob_size) = maximum_blob_size {
-                policy.maximum_blob_size = *maximum_blob_size;
-            }
-            if let Some(maximum_published_blobs) = maximum_published_blobs {
-                policy.maximum_published_blobs = *maximum_published_blobs;
-            }
-            if let Some(maximum_bytecode_size) = maximum_bytecode_size {
-                policy.maximum_bytecode_size = *maximum_bytecode_size;
-            }
-            if let Some(maximum_block_proposal_size) = maximum_block_proposal_size {
-                policy.maximum_block_proposal_size = *maximum_block_proposal_size;
-            }
-            if let Some(maximum_bytes_read_per_block) = maximum_bytes_read_per_block {
-                policy.maximum_bytes_read_per_block = *maximum_bytes_read_per_block;
-            }
-            if let Some(maximum_bytes_written_per_block) = maximum_bytes_written_per_block {
-                policy.maximum_bytes_written_per_block = *maximum_bytes_written_per_block;
-            }
-            if let Some(http_allow_list) = http_allow_list {
-                policy.http_request_allow_list = BTreeSet::from_iter(http_allow_list.clone());
-            }
+            let existing_policy = policy_config.into_policy();
+            let policy = linera_execution::ResourceControlPolicy {
+                block: block_price.unwrap_or(existing_policy.block),
+                fuel_unit: fuel_unit_price.unwrap_or(existing_policy.fuel_unit),
+                read_operation: read_operation_price.unwrap_or(existing_policy.read_operation),
+                write_operation: write_operation_price.unwrap_or(existing_policy.write_operation),
+                byte_read: byte_read_price.unwrap_or(existing_policy.byte_read),
+                byte_written: byte_written_price.unwrap_or(existing_policy.byte_written),
+                blob_read: blob_read_price.unwrap_or(existing_policy.blob_read),
+                blob_published: blob_published_price.unwrap_or(existing_policy.blob_published),
+                blob_byte_read: blob_byte_read_price.unwrap_or(existing_policy.blob_byte_read),
+                blob_byte_published: blob_byte_published_price
+                    .unwrap_or(existing_policy.blob_byte_published),
+                byte_stored: byte_stored_price.unwrap_or(existing_policy.byte_stored),
+                operation: operation_price.unwrap_or(existing_policy.operation),
+                operation_byte: operation_byte_price.unwrap_or(existing_policy.operation_byte),
+                message: message_price.unwrap_or(existing_policy.message),
+                message_byte: message_byte_price.unwrap_or(existing_policy.message_byte),
+                service_as_oracle_query: service_as_oracle_query_price
+                    .unwrap_or(existing_policy.service_as_oracle_query),
+                http_request: http_request_price.unwrap_or(existing_policy.http_request),
+                maximum_fuel_per_block: maximum_fuel_per_block
+                    .unwrap_or(existing_policy.maximum_fuel_per_block),
+                maximum_service_oracle_execution_ms: maximum_service_oracle_execution_ms
+                    .unwrap_or(existing_policy.maximum_service_oracle_execution_ms),
+                maximum_executed_block_size: maximum_executed_block_size
+                    .unwrap_or(existing_policy.maximum_executed_block_size),
+                maximum_bytecode_size: maximum_bytecode_size
+                    .unwrap_or(existing_policy.maximum_bytecode_size),
+                maximum_blob_size: maximum_blob_size.unwrap_or(existing_policy.maximum_blob_size),
+                maximum_published_blobs: maximum_published_blobs
+                    .unwrap_or(existing_policy.maximum_published_blobs),
+                maximum_block_proposal_size: maximum_block_proposal_size
+                    .unwrap_or(existing_policy.maximum_block_proposal_size),
+                maximum_bytes_read_per_block: maximum_bytes_read_per_block
+                    .unwrap_or(existing_policy.maximum_bytes_read_per_block),
+                maximum_bytes_written_per_block: maximum_bytes_written_per_block
+                    .unwrap_or(existing_policy.maximum_bytes_written_per_block),
+                maximum_http_response_bytes: maximum_http_response_bytes
+                    .unwrap_or(existing_policy.maximum_http_response_bytes),
+                http_request_timeout_ms: http_request_timeout_ms
+                    .unwrap_or(existing_policy.http_request_timeout_ms),
+                http_request_allow_list: match http_request_allow_list {
+                    None => existing_policy.http_request_allow_list,
+                    Some(http_request_allow_list) => http_request_allow_list
+                        .iter()
+                        .cloned()
+                        .collect::<BTreeSet<_>>(),
+                },
path: linera-service/src/linera/main.rs
user: login: jvff
body: Optional: here's an alternative, not sure if it's better :thinking: 

```suggestion
                http_request_allow_list: http_request_allow_list
                    .as_ref()
                    .map(|list| list.iter().cloned().collect())
                    .unwrap_or(existing_policy.http_request_allow_list),
```
created_at: 2025-03-19T15:01:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -551,10 +551,22 @@ pub enum ClientCommand {
         #[arg(long)]
         message_byte: Option<Amount>,
 
+        /// Set the price per query to a service as an oracle.
+        #[arg(long)]
+        service_as_oracle_query: Option<Amount>,
+
+        /// Set the price for a performing an HTTP request.
path: linera-client/src/client_options.rs
user: login: MathieuDutSik
body: Ok, done.
created_at: 2025-03-19T16:03:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1430,94 +1417,76 @@ async fn run(options: &ClientOptions) -> Result<i32, anyhow::Error> {
             operation_byte_price,
             message_price,
             message_byte_price,
+            service_as_oracle_query_price,
+            http_request_price,
             maximum_fuel_per_block,
+            maximum_service_oracle_execution_ms,
             maximum_executed_block_size,
             maximum_blob_size,
             maximum_published_blobs,
             maximum_bytecode_size,
             maximum_block_proposal_size,
             maximum_bytes_read_per_block,
             maximum_bytes_written_per_block,
+            maximum_http_response_bytes,
+            http_request_timeout_ms,
+            http_request_allow_list,
             testing_prng_seed,
             network_name,
-            http_allow_list,
         } => {
             let start_time = Instant::now();
             let committee_config: CommitteeConfig = util::read_json(committee_config_path)
                 .expect("Unable to read committee config file");
-            let mut policy = policy_config.into_policy();
-            if let Some(block_price) = block_price {
-                policy.block = *block_price;
-            }
-            if let Some(fuel_unit_price) = fuel_unit_price {
-                policy.fuel_unit = *fuel_unit_price;
-            }
-            if let Some(read_operation_price) = read_operation_price {
-                policy.read_operation = *read_operation_price;
-            }
-            if let Some(write_operation_price) = write_operation_price {
-                policy.write_operation = *write_operation_price;
-            }
-            if let Some(byte_read_price) = byte_read_price {
-                policy.byte_read = *byte_read_price;
-            }
-            if let Some(byte_written_price) = byte_written_price {
-                policy.byte_written = *byte_written_price;
-            }
-            if let Some(blob_read_price) = blob_read_price {
-                policy.blob_read = *blob_read_price;
-            }
-            if let Some(blob_published_price) = blob_published_price {
-                policy.blob_published = *blob_published_price;
-            }
-            if let Some(blob_byte_read_price) = blob_byte_read_price {
-                policy.blob_byte_read = *blob_byte_read_price;
-            }
-            if let Some(blob_byte_published_price) = blob_byte_published_price {
-                policy.blob_byte_published = *blob_byte_published_price;
-            }
-            if let Some(byte_stored_price) = byte_stored_price {
-                policy.byte_stored = *byte_stored_price;
-            }
-            if let Some(operation_price) = operation_price {
-                policy.operation = *operation_price;
-            }
-            if let Some(operation_byte_price) = operation_byte_price {
-                policy.operation_byte = *operation_byte_price;
-            }
-            if let Some(message_price) = message_price {
-                policy.message = *message_price;
-            }
-            if let Some(message_byte_price) = message_byte_price {
-                policy.message_byte = *message_byte_price;
-            }
-            if let Some(maximum_fuel_per_block) = maximum_fuel_per_block {
-                policy.maximum_fuel_per_block = *maximum_fuel_per_block;
-            }
-            if let Some(maximum_executed_block_size) = maximum_executed_block_size {
-                policy.maximum_executed_block_size = *maximum_executed_block_size;
-            }
-            if let Some(maximum_blob_size) = maximum_blob_size {
-                policy.maximum_blob_size = *maximum_blob_size;
-            }
-            if let Some(maximum_published_blobs) = maximum_published_blobs {
-                policy.maximum_published_blobs = *maximum_published_blobs;
-            }
-            if let Some(maximum_bytecode_size) = maximum_bytecode_size {
-                policy.maximum_bytecode_size = *maximum_bytecode_size;
-            }
-            if let Some(maximum_block_proposal_size) = maximum_block_proposal_size {
-                policy.maximum_block_proposal_size = *maximum_block_proposal_size;
-            }
-            if let Some(maximum_bytes_read_per_block) = maximum_bytes_read_per_block {
-                policy.maximum_bytes_read_per_block = *maximum_bytes_read_per_block;
-            }
-            if let Some(maximum_bytes_written_per_block) = maximum_bytes_written_per_block {
-                policy.maximum_bytes_written_per_block = *maximum_bytes_written_per_block;
-            }
-            if let Some(http_allow_list) = http_allow_list {
-                policy.http_request_allow_list = BTreeSet::from_iter(http_allow_list.clone());
-            }
+            let existing_policy = policy_config.into_policy();
+            let policy = linera_execution::ResourceControlPolicy {
+                block: block_price.unwrap_or(existing_policy.block),
+                fuel_unit: fuel_unit_price.unwrap_or(existing_policy.fuel_unit),
+                read_operation: read_operation_price.unwrap_or(existing_policy.read_operation),
+                write_operation: write_operation_price.unwrap_or(existing_policy.write_operation),
+                byte_read: byte_read_price.unwrap_or(existing_policy.byte_read),
+                byte_written: byte_written_price.unwrap_or(existing_policy.byte_written),
+                blob_read: blob_read_price.unwrap_or(existing_policy.blob_read),
+                blob_published: blob_published_price.unwrap_or(existing_policy.blob_published),
+                blob_byte_read: blob_byte_read_price.unwrap_or(existing_policy.blob_byte_read),
+                blob_byte_published: blob_byte_published_price
+                    .unwrap_or(existing_policy.blob_byte_published),
+                byte_stored: byte_stored_price.unwrap_or(existing_policy.byte_stored),
+                operation: operation_price.unwrap_or(existing_policy.operation),
+                operation_byte: operation_byte_price.unwrap_or(existing_policy.operation_byte),
+                message: message_price.unwrap_or(existing_policy.message),
+                message_byte: message_byte_price.unwrap_or(existing_policy.message_byte),
+                service_as_oracle_query: service_as_oracle_query_price
+                    .unwrap_or(existing_policy.service_as_oracle_query),
+                http_request: http_request_price.unwrap_or(existing_policy.http_request),
+                maximum_fuel_per_block: maximum_fuel_per_block
+                    .unwrap_or(existing_policy.maximum_fuel_per_block),
+                maximum_service_oracle_execution_ms: maximum_service_oracle_execution_ms
+                    .unwrap_or(existing_policy.maximum_service_oracle_execution_ms),
+                maximum_executed_block_size: maximum_executed_block_size
+                    .unwrap_or(existing_policy.maximum_executed_block_size),
+                maximum_bytecode_size: maximum_bytecode_size
+                    .unwrap_or(existing_policy.maximum_bytecode_size),
+                maximum_blob_size: maximum_blob_size.unwrap_or(existing_policy.maximum_blob_size),
+                maximum_published_blobs: maximum_published_blobs
+                    .unwrap_or(existing_policy.maximum_published_blobs),
+                maximum_block_proposal_size: maximum_block_proposal_size
+                    .unwrap_or(existing_policy.maximum_block_proposal_size),
+                maximum_bytes_read_per_block: maximum_bytes_read_per_block
+                    .unwrap_or(existing_policy.maximum_bytes_read_per_block),
+                maximum_bytes_written_per_block: maximum_bytes_written_per_block
+                    .unwrap_or(existing_policy.maximum_bytes_written_per_block),
+                maximum_http_response_bytes: maximum_http_response_bytes
+                    .unwrap_or(existing_policy.maximum_http_response_bytes),
+                http_request_timeout_ms: http_request_timeout_ms
+                    .unwrap_or(existing_policy.http_request_timeout_ms),
+                http_request_allow_list: match http_request_allow_list {
+                    None => existing_policy.http_request_allow_list,
+                    Some(http_request_allow_list) => http_request_allow_list
+                        .iter()
+                        .cloned()
+                        .collect::<BTreeSet<_>>(),
+                },
path: linera-service/src/linera/main.rs
user: login: MathieuDutSik
body: Amazing, take it as it is shorter. Also, not sure if it is better.

created_at: 2025-03-19T16:07:15Z
author_association: CONTRIBUTOR

PR comments:
user: login: jvff
created_at: 2025-03-19T11:51:07Z
body: Related issue: I was thinking about future proofing this by forcing compiler errors when new fields are added to `ResourceControlPolicy`: #3532.
author_association: CONTRIBUTOR
user: login: MathieuDutSik
created_at: 2025-03-19T13:05:18Z
body: > Related issue: I was thinking about future proofing this by forcing compiler errors when new fields are added to `ResourceControlPolicy`: #3532.

Thanks, done as requested. Doing that I found another forgotten entry.
author_association: CONTRIBUTOR