Skip to content

Commit 77aae90

Browse files
authored
Use TryFrom traits for YAML for better error handling (#27)
1 parent b2f93a5 commit 77aae90

File tree

1 file changed

+103
-65
lines changed

1 file changed

+103
-65
lines changed

src/main.rs

Lines changed: 103 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use primitive_types::U256;
1111
use rustc_hex::{FromHex, ToHex};
1212
use serde::{Deserialize, Serialize};
1313
use ssz::{Decode, Encode};
14+
use std::convert::{TryFrom, TryInto};
1415
use std::env;
1516
use std::error::Error;
1617
use std::fmt;
@@ -34,6 +35,22 @@ impl From<std::io::Error> for ScoutError {
3435
}
3536
}
3637

38+
impl From<rustc_hex::FromHexError> for ScoutError {
39+
fn from(error: rustc_hex::FromHexError) -> Self {
40+
ScoutError {
41+
0: error.description().to_string(),
42+
}
43+
}
44+
}
45+
46+
impl From<serde_yaml::Error> for ScoutError {
47+
fn from(error: serde_yaml::Error) -> Self {
48+
ScoutError {
49+
0: error.description().to_string(),
50+
}
51+
}
52+
}
53+
3754
impl From<wasmi::Error> for ScoutError {
3855
fn from(error: wasmi::Error) -> Self {
3956
ScoutError {
@@ -705,117 +722,131 @@ struct TestFile {
705722
deposit_receipts: Vec<TestDeposit>,
706723
}
707724

708-
fn hex_to_slice(input: &str, output: &mut [u8]) {
709-
let tmp = input.from_hex().expect("invalid hex data");
710-
assert!(tmp.len() == output.len());
725+
fn hex_to_slice(input: &str, output: &mut [u8]) -> Result<(), ScoutError> {
726+
let tmp = input.from_hex()?;
727+
if tmp.len() != output.len() {
728+
return Err(ScoutError("Length mismatch from hex input".to_string()));
729+
}
711730
output.copy_from_slice(&tmp[..]);
731+
Ok(())
712732
}
713733

714-
impl From<&String> for Bytes32 {
715-
fn from(input: &String) -> Self {
734+
impl TryFrom<&String> for Bytes32 {
735+
type Error = ScoutError;
736+
fn try_from(input: &String) -> Result<Self, Self::Error> {
716737
let mut ret = Bytes32::default();
717-
hex_to_slice(input, &mut ret.bytes);
718-
ret
738+
hex_to_slice(input, &mut ret.bytes)?;
739+
Ok(ret)
719740
}
720741
}
721742

722-
impl From<String> for Hash {
723-
fn from(input: String) -> Self {
743+
impl TryFrom<String> for Hash {
744+
type Error = ScoutError;
745+
fn try_from(input: String) -> Result<Self, Self::Error> {
724746
let mut ret = Hash::default();
725-
hex_to_slice(&input, &mut ret.0);
726-
ret
747+
hex_to_slice(&input, &mut ret.0)?;
748+
Ok(ret)
727749
}
728750
}
729751

730-
impl From<String> for BLSPubKey {
731-
fn from(input: String) -> Self {
752+
impl TryFrom<String> for BLSPubKey {
753+
type Error = ScoutError;
754+
fn try_from(input: String) -> Result<Self, Self::Error> {
732755
let mut ret = BLSPubKey::default();
733-
hex_to_slice(&input, &mut ret.0);
734-
ret
756+
hex_to_slice(&input, &mut ret.0)?;
757+
Ok(ret)
735758
}
736759
}
737760

738-
impl From<String> for BLSSignature {
739-
fn from(input: String) -> Self {
761+
impl TryFrom<String> for BLSSignature {
762+
type Error = ScoutError;
763+
fn try_from(input: String) -> Result<Self, Self::Error> {
740764
let mut ret = BLSSignature::default();
741-
hex_to_slice(&input, &mut ret.0);
742-
ret
765+
hex_to_slice(&input, &mut ret.0)?;
766+
Ok(ret)
743767
}
744768
}
745769

746-
impl From<TestBeaconState> for BeaconState {
747-
fn from(input: TestBeaconState) -> Self {
748-
BeaconState {
749-
execution_scripts: input
750-
.execution_scripts
751-
.iter()
752-
.map(|filename| ExecutionScript {
753-
code: std::fs::read(filename).expect("to load file"),
770+
impl TryFrom<TestBeaconState> for BeaconState {
771+
type Error = ScoutError;
772+
fn try_from(input: TestBeaconState) -> Result<Self, Self::Error> {
773+
let scripts: Result<Vec<ExecutionScript>, ScoutError> = input
774+
.execution_scripts
775+
.iter()
776+
.map(|filename| {
777+
Ok(ExecutionScript {
778+
code: std::fs::read(filename)?,
754779
})
755-
.collect(),
756-
}
780+
})
781+
.collect();
782+
Ok(BeaconState {
783+
execution_scripts: scripts?,
784+
})
757785
}
758786
}
759787

760-
impl From<TestShardBlock> for ShardBlock {
761-
fn from(input: TestShardBlock) -> Self {
762-
ShardBlock {
788+
impl TryFrom<TestShardBlock> for ShardBlock {
789+
type Error = ScoutError;
790+
fn try_from(input: TestShardBlock) -> Result<Self, Self::Error> {
791+
Ok(ShardBlock {
763792
env: input.env,
764793
data: ShardBlockBody {
765-
data: input.data.from_hex().expect("invalid hex data"),
794+
data: input.data.from_hex()?,
766795
},
767-
}
796+
})
768797
}
769798
}
770799

771-
impl From<TestShardState> for ShardState {
772-
fn from(input: TestShardState) -> Self {
773-
ShardState {
774-
exec_env_states: input
775-
.exec_env_states
776-
.iter()
777-
.map(|state| state.into())
778-
.collect(),
800+
impl TryFrom<TestShardState> for ShardState {
801+
type Error = ScoutError;
802+
fn try_from(input: TestShardState) -> Result<Self, Self::Error> {
803+
let states: Result<Vec<Bytes32>, ScoutError> = input
804+
.exec_env_states
805+
.iter()
806+
.map(|state| state.try_into())
807+
.collect();
808+
809+
Ok(ShardState {
810+
exec_env_states: states?,
779811
slot: 0,
780812
parent_block: ShardBlockHeader {},
781-
}
813+
})
782814
}
783815
}
784816

785-
impl From<TestDeposit> for Deposit {
786-
fn from(input: TestDeposit) -> Self {
787-
Deposit {
788-
pubkey: input.pubkey.into(),
789-
withdrawal_credentials: input.withdrawal_credentials.into(),
817+
impl TryFrom<TestDeposit> for Deposit {
818+
type Error = ScoutError;
819+
fn try_from(input: TestDeposit) -> Result<Self, Self::Error> {
820+
Ok(Deposit {
821+
pubkey: input.pubkey.try_into()?,
822+
withdrawal_credentials: input.withdrawal_credentials.try_into()?,
790823
amount: input.amount,
791-
signature: input.signature.into(),
792-
}
824+
signature: input.signature.try_into()?,
825+
})
793826
}
794827
}
795828

796-
fn process_yaml_test(filename: &str) {
829+
fn process_yaml_test(filename: &str) -> Result<(), ScoutError> {
797830
info!("Processing {}...", filename);
798-
let content = std::fs::read(&filename).expect("to load file");
799-
let test_file: TestFile =
800-
serde_yaml::from_slice::<TestFile>(&content[..]).expect("expected valid yaml");
831+
let content = std::fs::read(&filename)?;
832+
let test_file: TestFile = serde_yaml::from_slice::<TestFile>(&content[..])?;
801833
debug!("{:#?}", test_file);
802834

803-
let beacon_state: BeaconState = test_file.beacon_state.into();
804-
let pre_state: ShardState = test_file.shard_pre_state.into();
805-
let post_state: ShardState = test_file.shard_post_state.into();
806-
let expected_deposit_receipts: Vec<Deposit> = test_file
835+
let beacon_state: BeaconState = test_file.beacon_state.try_into()?;
836+
let pre_state: ShardState = test_file.shard_pre_state.try_into()?;
837+
let post_state: ShardState = test_file.shard_post_state.try_into()?;
838+
let expected_deposit_receipts: Result<Vec<Deposit>, ScoutError> = test_file
807839
.deposit_receipts
808840
.into_iter()
809-
.map(|deposit| deposit.into())
841+
.map(|deposit| deposit.try_into())
810842
.collect();
843+
let expected_deposit_receipts = expected_deposit_receipts?;
811844

812845
let mut shard_state = pre_state;
813846
let mut deposit_receipts = Vec::new();
814847
for block in test_file.shard_blocks {
815848
deposit_receipts.append(
816-
process_shard_block(&mut shard_state, &beacon_state, Some(block.into()))
817-
.expect("processing shard block to succeed")
818-
.as_mut(),
849+
process_shard_block(&mut shard_state, &beacon_state, Some(block.try_into()?))?.as_mut(),
819850
);
820851
}
821852

@@ -827,26 +858,33 @@ fn process_yaml_test(filename: &str) {
827858
} else {
828859
println!("Expected deposit receipts: {:?}", expected_deposit_receipts);
829860
println!("Got deposit receipts: {:?}", deposit_receipts);
830-
std::process::exit(1);
861+
// TODO: make this an error?
862+
return Ok(());
831863
}
832864

833865
debug!("{}", shard_state);
834866
if shard_state != post_state {
835867
println!("Expected state: {}", post_state);
836868
println!("Got state: {}", shard_state);
837-
std::process::exit(1);
869+
// TODO: make this an error?
870+
return Ok(());
838871
} else {
839872
println!("Matching state.");
840873
}
874+
875+
Ok(())
841876
}
842877

843878
fn main() {
844879
env_logger::init();
845880

846881
let args: Vec<String> = env::args().collect();
847-
process_yaml_test(if args.len() != 2 {
882+
let ret = process_yaml_test(if args.len() != 2 {
848883
"test.yaml"
849884
} else {
850885
&args[1]
851886
});
887+
if ret.is_err() {
888+
println!("Unexpected test failure: {:?}", ret.err().unwrap())
889+
}
852890
}

0 commit comments

Comments
 (0)