Skip to content

Commit 10cd61a

Browse files
feat(cast): block -f to accept multiple fields (#12427)
* feat(cast): added custom polling interval args * feat(cast): added a custom alias for poll interval * feat(cast): updated with clippy suggestion * feat(cast): added multi fields to cast block * feat(cast): num of args needed for fields in block set to 0 * chore: updated with formatting * feat(cast): added long field to cast block * doc(cast): updated docs to match change in fields * test(cast): Remove trailing whitespace from block output
1 parent 12be76f commit 10cd61a

File tree

4 files changed

+54
-48
lines changed

4 files changed

+54
-48
lines changed

crates/cast/src/args.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,17 +338,16 @@ pub async fn run_command(args: CastArgs) -> Result<()> {
338338
Cast::new(provider).base_fee(block.unwrap_or(BlockId::Number(Latest))).await?
339339
)?
340340
}
341-
CastSubcommand::Block { block, full, field, raw, rpc } => {
341+
CastSubcommand::Block { block, full, fields, raw, rpc } => {
342342
let config = rpc.load_config()?;
343343
let provider = utils::get_provider(&config)?;
344-
345344
// Can use either --raw or specify raw as a field
346-
let raw = raw || field.as_ref().is_some_and(|f| f == "raw");
345+
let raw = raw || fields.contains(&"raw".into());
347346

348347
sh_println!(
349348
"{}",
350349
Cast::new(provider)
351-
.block(block.unwrap_or(BlockId::Number(Latest)), full, field, raw)
350+
.block(block.unwrap_or(BlockId::Number(Latest)), full, fields, raw)
352351
.await?
353352
)?
354353
}

crates/cast/src/lib.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ impl<P: Provider<AnyNetwork>> Cast<P> {
339339
/// let provider =
340340
/// ProviderBuilder::<_, _, AnyNetwork>::default().connect("http://localhost:8545").await?;
341341
/// let cast = Cast::new(provider);
342-
/// let block = cast.block(5, true, None, false).await?;
342+
/// let block = cast.block(5, true, vec![], false).await?;
343343
/// println!("{}", block);
344344
/// # Ok(())
345345
/// # }
@@ -348,14 +348,11 @@ impl<P: Provider<AnyNetwork>> Cast<P> {
348348
&self,
349349
block: B,
350350
full: bool,
351-
field: Option<String>,
351+
fields: Vec<String>,
352352
raw: bool,
353353
) -> Result<String> {
354354
let block = block.into();
355-
if let Some(ref field) = field
356-
&& field == "transactions"
357-
&& !full
358-
{
355+
if fields.contains(&"transactions".into()) && !full {
359356
eyre::bail!("use --full to view transactions")
360357
}
361358

@@ -369,9 +366,17 @@ impl<P: Provider<AnyNetwork>> Cast<P> {
369366
Ok(if raw {
370367
let header: Header = block.into_inner().header.inner.try_into_header()?;
371368
format!("0x{}", hex::encode(alloy_rlp::encode(&header)))
372-
} else if let Some(ref field) = field {
373-
get_pretty_block_attr(&block, field)
374-
.unwrap_or_else(|| format!("{field} is not a valid block field"))
369+
} else if !fields.is_empty() {
370+
let mut result = String::new();
371+
for field in fields {
372+
result.push_str(
373+
&get_pretty_block_attr(&block, &field)
374+
.unwrap_or_else(|| format!("{field} is not a valid block field")),
375+
);
376+
377+
result.push('\n');
378+
}
379+
result.trim_end().to_string()
375380
} else if shell::is_json() {
376381
serde_json::to_value(&block).unwrap().to_string()
377382
} else {
@@ -385,7 +390,7 @@ impl<P: Provider<AnyNetwork>> Cast<P> {
385390
block.into(),
386391
false,
387392
// Select only select field
388-
Some(field),
393+
vec![field],
389394
false,
390395
)
391396
.await?
@@ -414,14 +419,15 @@ impl<P: Provider<AnyNetwork>> Cast<P> {
414419
0,
415420
false,
416421
// Select only block hash
417-
Some(String::from("hash")),
422+
vec![String::from("hash")],
418423
false,
419424
)
420425
.await?;
421426

422427
Ok(match &genesis_hash[..] {
423428
"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" => {
424-
match &(Self::block(self, 1920000, false, Some("hash".to_string()), false).await?)[..]
429+
match &(Self::block(self, 1920000, false, vec![String::from("hash")], false)
430+
.await?)[..]
425431
{
426432
"0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f" => {
427433
"etclive"
@@ -464,7 +470,7 @@ impl<P: Provider<AnyNetwork>> Cast<P> {
464470
"0x6d3c66c5357ec91d5c43af47e234a939b22557cbb552dc45bebbceeed90fbe34" => "bsctest",
465471
"0x0d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5b" => "bsc",
466472
"0x31ced5b9beb7f8782b014660da0cb18cc409f121f408186886e1ca3e8eeca96b" => {
467-
match &(Self::block(self, 1, false, Some(String::from("hash")), false).await?)[..] {
473+
match &(Self::block(self, 1, false, vec![String::from("hash")], false).await?)[..] {
468474
"0x738639479dc82d199365626f90caa82f7eafcfe9ed354b456fb3d294597ceb53" => {
469475
"avalanche-fuji"
470476
}

crates/cast/src/opts.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ use crate::cmd::{
99
use alloy_ens::NameOrAddress;
1010
use alloy_primitives::{Address, B256, Selector, U256};
1111
use alloy_rpc_types::BlockId;
12-
use clap::{Parser, Subcommand, ValueHint};
12+
use clap::{ArgAction, Parser, Subcommand, ValueHint};
1313
use eyre::Result;
1414
use foundry_cli::opts::{EtherscanOpts, GlobalArgs, RpcOpts};
1515
use foundry_common::version::{LONG_VERSION, SHORT_VERSION};
1616
use std::{path::PathBuf, str::FromStr};
17-
1817
/// A Swiss Army knife for interacting with Ethereum applications from the command line.
1918
#[derive(Parser)]
2019
#[command(
@@ -379,11 +378,11 @@ pub enum CastSubcommand {
379378
block: Option<BlockId>,
380379

381380
/// If specified, only get the given field of the block.
382-
#[arg(long, short)]
383-
field: Option<String>,
381+
#[arg(short, long = "field", aliases = ["fields"], num_args = 0.., action = ArgAction::Append, value_delimiter = ',')]
382+
fields: Vec<String>,
384383

385384
/// Print the raw RLP encoded block header.
386-
#[arg(long, conflicts_with = "field")]
385+
#[arg(long, conflicts_with = "fields")]
387386
raw: bool,
388387

389388
#[arg(long, env = "CAST_FULL_BLOCK")]

crates/cast/tests/cli/main.rs

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,17 @@ transactions: [
142142
"#]]);
143143

144144
// <https://etherscan.io/block/15007840>
145-
cmd.cast_fuse().args(["block", "15007840", "-f", "hash", "--rpc-url", eth_rpc_url.as_str()]);
145+
cmd.cast_fuse().args([
146+
"block",
147+
"15007840",
148+
"-f",
149+
"hash,timestamp",
150+
"--rpc-url",
151+
eth_rpc_url.as_str(),
152+
]);
146153
cmd.assert_success().stdout_eq(str![[r#"
147154
0x950091817a57e22b6c1f3b951a15f52d41ac89b299cc8f9c89bb6d185f80c415
155+
1655904485
148156
149157
"#]]);
150158
});
@@ -1312,6 +1320,7 @@ casttest!(to_base, |_prj, cmd| {
13121320
});
13131321

13141322
// tests that revert reason is only present if transaction has reverted.
1323+
13151324
casttest!(receipt_revert_reason, |_prj, cmd| {
13161325
let rpc = next_http_archive_rpc_url();
13171326

@@ -1323,27 +1332,25 @@ casttest!(receipt_revert_reason, |_prj, cmd| {
13231332
rpc.as_str(),
13241333
])
13251334
.assert_success()
1326-
.stdout_eq(str![[r#"
1327-
1335+
.stdout_eq(format!(r#"
13281336
blockHash 0x2cfe65be49863676b6dbc04d58176a14f39b123f1e2f4fea0383a2d82c2c50d0
13291337
blockNumber 16239315
1330-
contractAddress
1338+
contractAddress {}
13311339
cumulativeGasUsed 10743428
13321340
effectiveGasPrice 10539984136
13331341
from 0x199D5ED7F45F4eE35960cF22EAde2076e95B253F
13341342
gasUsed 21000
13351343
logs []
13361344
logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1337-
root
1345+
root {}
13381346
status 1 (success)
13391347
transactionHash 0x44f2aaa351460c074f2cb1e5a9e28cbc7d83f33e425101d2de14331c7b7ec31e
13401348
transactionIndex 116
13411349
type 0
1342-
blobGasPrice
1343-
blobGasUsed
1350+
blobGasPrice {}
1351+
blobGasUsed {}
13441352
to 0x91da5bf3F8Eb72724E6f50Ec6C3D199C6355c59c
1345-
1346-
"#]]);
1353+
"#,"", "", "", ""));
13471354

13481355
let rpc = next_http_archive_rpc_url();
13491356

@@ -1356,30 +1363,27 @@ to 0x91da5bf3F8Eb72724E6f50Ec6C3D199C6355c59c
13561363
rpc.as_str(),
13571364
])
13581365
.assert_success()
1359-
.stdout_eq(str![[r#"
1360-
1366+
.stdout_eq(format!(r#"
13611367
blockHash 0x883f974b17ca7b28cb970798d1c80f4d4bb427473dc6d39b2a7fe24edc02902d
13621368
blockNumber 14839405
1363-
contractAddress
1369+
contractAddress {}
13641370
cumulativeGasUsed 20273649
13651371
effectiveGasPrice 21491736378
13661372
from 0x3cF412d970474804623bb4e3a42dE13F9bCa5436
13671373
gasUsed 24952
13681374
logs []
13691375
logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1370-
root
1376+
root {}
13711377
status 0 (failed)
13721378
transactionHash 0x0e07d8b53ed3d91314c80e53cf25bcde02084939395845cbb625b029d568135c
13731379
transactionIndex 173
13741380
type 2
1375-
blobGasPrice
1376-
blobGasUsed
1381+
blobGasPrice {}
1382+
blobGasUsed {}
13771383
to 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45
13781384
revertReason [..]Transaction too old, data: "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000135472616e73616374696f6e20746f6f206f6c6400000000000000000000000000"
1379-
1380-
"#]]);
1385+
"#,"","","",""));
13811386
});
1382-
13831387
// tests that the revert reason is loaded using the correct `from` address.
13841388
casttest!(revert_reason_from, |_prj, cmd| {
13851389
let rpc = next_rpc_endpoint(NamedChain::Sepolia);
@@ -1391,28 +1395,26 @@ casttest!(revert_reason_from, |_prj, cmd| {
13911395
rpc.as_str(),
13921396
])
13931397
.assert_success()
1394-
.stdout_eq(str![[r#"
1395-
1398+
.stdout_eq(format!(r#"
13961399
blockHash 0x32663d7730c9ea8e1de6d99854483e25fcc05bb56c91c0cc82f9f04944fbffc1
13971400
blockNumber 7823353
1398-
contractAddress
1401+
contractAddress {}
13991402
cumulativeGasUsed 7500797
14001403
effectiveGasPrice 14296851013
14011404
from 0x3583fF95f96b356d716881C871aF7Eb55ea34a93
14021405
gasUsed 25815
14031406
logs []
14041407
logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
1405-
root
1408+
root {}
14061409
status 0 (failed)
14071410
transactionHash 0x10ee70cf9f5ced5c515e8d53bfab5ea9f5c72cd61b25fba455c8355ee286c4e4
14081411
transactionIndex 96
14091412
type 0
1410-
blobGasPrice
1411-
blobGasUsed
1413+
blobGasPrice {}
1414+
blobGasUsed {}
14121415
to 0x91b5d4111a4C038153b24e31F75ccdC47123595d
14131416
revertReason Counter is too large, data: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000014436f756e74657220697320746f6f206c61726765000000000000000000000000"
1414-
1415-
"#]]);
1417+
"#, "", "", "", ""));
14161418
});
14171419

14181420
// tests that `cast --parse-bytes32-address` command is working correctly.

0 commit comments

Comments
 (0)