Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,14 @@ dv init --project <PROJECT_PATH> --address <ADDRESS> --contractname <NAME> --ini

Please note that `<B>` must be equal to or larger than the deployment block of the contract. Additionally, it is recommended to use only block numbers of **finalized blocks** in order to prevent the DVF containing wrong data due to possible re-orgs in the future.

Sometimes, you might want to know when a storage variable has been initialized before but then reset back to zero. You can add such variables to the DVF with the `--zerovalue` flag:

```
dv init --project <PROJECT_PATH> --address <ADDRESS> --contractname <NAME> --zerovalue new.dvf.json
```

Attention: In rare edge cases, this can lead to false positives.

#### Step 2 - Validate data and select constraints

After Step 1, a new JSON file has been created that contains the following data:
Expand Down
29 changes: 24 additions & 5 deletions lib/state/contract_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ impl<'a> ContractState<'a> {
table: &mut Table,
pi_storage: &Vec<StateVariable>,
pi_types: &HashMap<String, TypeDescription>,
zerovalue: bool,
) -> Result<Vec<parse::DVFStorageEntry>, ValidationError> {
let default_values = &ForgeInspect::default_values();
// Add default types as we might need them
Expand All @@ -259,6 +260,7 @@ impl<'a> ContractState<'a> {
state_variable,
snapshot,
table,
zerovalue,
)?);
}

Expand All @@ -272,7 +274,8 @@ impl<'a> ContractState<'a> {
// continue;
// }

let new_critical_storage_variables = self.get_critical_variable(sv, snapshot, table)?;
let new_critical_storage_variables =
self.get_critical_variable(sv, snapshot, table, zerovalue)?;
let mut has_nonzero = false;
for crit_var in &new_critical_storage_variables {
if !crit_var.is_zero() {
Expand Down Expand Up @@ -367,6 +370,7 @@ impl<'a> ContractState<'a> {
state_variable: &StateVariable,
snapshot: &mut StorageSnapshot,
table: &mut Table,
zerovalue: bool,
) -> Result<Vec<DVFStorageEntry>, ValidationError> {
if Self::is_basic_type(&state_variable.var_type)
|| Self::is_user_defined_type(&state_variable.var_type)
Expand All @@ -385,7 +389,7 @@ impl<'a> ContractState<'a> {
value_hint: None,
comparison_operator: DVFStorageComparisonOperator::Equal,
};
if !entry.is_zero() {
if zerovalue || !entry.is_zero() {
Self::add_to_table(&entry, table);
if !Self::is_user_defined_type(&state_variable.var_type) {
self.pretty_printer.add_decoded_to_table_from_bytes(
Expand All @@ -402,9 +406,11 @@ impl<'a> ContractState<'a> {
entry.value_hint = Some(short_val);
}
}

return Ok(vec![entry]);
}

return Ok(vec![entry]);
return Ok(vec![]);
}
if Self::is_struct(&state_variable.var_type) {
let mut critical_storage_variables = Vec::<DVFStorageEntry>::new();
Expand All @@ -421,6 +427,7 @@ impl<'a> ContractState<'a> {
&adjusted_member,
snapshot,
table,
zerovalue,
)?);
}
return Ok(critical_storage_variables);
Expand All @@ -444,6 +451,7 @@ impl<'a> ContractState<'a> {
&length_var,
snapshot,
table,
zerovalue,
)?);
}
let mut current_slot = match self.is_dynamic_array(&state_variable.var_type) {
Expand All @@ -459,7 +467,7 @@ impl<'a> ContractState<'a> {
var_type: self.get_base_type(&state_variable.var_type),
};
critical_storage_variables
.extend(self.get_critical_variable(&base, snapshot, table)?);
.extend(self.get_critical_variable(&base, snapshot, table, zerovalue)?);
// Check if we need to skip multiple slots
if base_num_bytes > 32 {
current_slot = current_slot
Expand Down Expand Up @@ -489,6 +497,16 @@ impl<'a> ContractState<'a> {
sorted_keys.sort();
for (sorted_key, target_slot) in &sorted_keys {
let key_type = self.get_key_type(&state_variable.var_type);

// Skip if key is longer than actual key type of the mapping
// this prevents classifiying keccak calls as mapping keys when
// the last 32 bytes correspond to a slot
// we can still have false positives, so the --zerovalue option
// should be used with care
if self.has_inplace_encoding(&key_type) && sorted_key.len() > 64 {
continue;
}

let pretty_key: String = match self.has_inplace_encoding(&key_type) {
true => self
.pretty_printer
Expand All @@ -515,7 +533,7 @@ impl<'a> ContractState<'a> {
var_type: self.get_value_type(&state_variable.var_type),
};
critical_storage_variables
.extend(self.get_critical_variable(&base, snapshot, table)?);
.extend(self.get_critical_variable(&base, snapshot, table, zerovalue)?);
}
return Ok(critical_storage_variables);
}
Expand Down Expand Up @@ -579,6 +597,7 @@ impl<'a> ContractState<'a> {
&length_var,
snapshot,
table,
zerovalue,
)?);
let mut string_length = U256::from_be_slice(&snapshot.get_slot(
&length_var.slot,
Expand Down
23 changes: 23 additions & 0 deletions src/dvf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,13 @@ fn main() {
.help("Folder containing the project artifacts")
.default_value("artifacts"),
)
.arg(
arg!(--zerovalue)
.help(
"Write initialized storage slots that have been reset to 0 to the DVF",
)
.action(clap::ArgAction::SetTrue),
)
.arg(arg!(--buildcache <PATH>).help("Folder containing build-info files"))
.arg(
arg!(--implementationbuildcache <PATH>)
Expand Down Expand Up @@ -530,6 +537,13 @@ fn main() {
.help("The block number used for validation")
.value_parser(is_valid_blocknum),
)
.arg(
arg!(--zerovalue)
.help(
"Write initialized storage slots that have been reset to 0 to the DVF",
)
.action(clap::ArgAction::SetTrue),
)
.arg(arg!(<DVF>).help("The DVF file")),
)
.subcommand(
Expand Down Expand Up @@ -742,6 +756,7 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
let event_topics = sub_m
.get_many::<Vec<B256>>("eventtopics")
.map(|v| v.flat_map(|x| x.clone()).collect::<Vec<_>>());
let zerovalue = sub_m.get_flag("zerovalue");

let mut imp_env = *sub_m.get_one::<Environment>("implementationenv").unwrap();
let imp_project = sub_m.get_one::<PathBuf>("implementationproject");
Expand Down Expand Up @@ -983,6 +998,7 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
&mut storage_var_table,
&storage,
&types,
zerovalue,
)?;

let mut proxy_warning = critical_storage_variables
Expand Down Expand Up @@ -1302,6 +1318,7 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
Some(("update", sub_m)) => {
let input_path: PathBuf =
parse_input_path(&config, sub_m.get_one::<String>("DVF").unwrap())?;
let zerovalue = sub_m.get_flag("zerovalue");

println!("input path {}", input_path.display());
let mut pc = 1_u64;
Expand Down Expand Up @@ -1364,6 +1381,12 @@ fn process(matches: ArgMatches) -> Result<(), ValidationError> {
storage_variable.value_hint = None;
}
}
if !zerovalue {
// Remove storage variables with value 0
updated
.critical_storage_variables
.retain(|var| !var.is_zero());
}

print_progress("Checking Events.", &mut pc, &progress_mode);
// Validate events
Expand Down
1 change: 1 addition & 0 deletions src/gentest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ fn gen_test(matches: &ArgMatches) -> Result<(), ValidationError> {
&mut table,
&vec![],
&HashMap::new(),
true,
)?;

let serialized_res = serde_json::to_string_pretty(&critical_vars)?;
Expand Down
6 changes: 3 additions & 3 deletions tests/ci_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ cd tests/hardhat_2_0 && yarn install -y && npx hardhat compile && cd -
RUST_BACKTRACE=1 cargo test
envsubst < tests/config.json > /tmp/eval_config.json
cargo run --bin fetch-from-etherscan -- -c /tmp/eval_config.json --address 0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f --project /tmp/uni-factory
cargo run --bin dv -- --config /tmp/eval_config.json init --address 0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f --project /tmp/uni-factory --chainid 1 --factory --contractname UniswapV2Factory UniswapV2Factory_0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f.dvf.json
cargo run --bin dv -- --config /tmp/eval_config.json init --address 0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f --project /tmp/uni-factory --chainid 1 --factory --zerovalue --contractname UniswapV2Factory UniswapV2Factory_0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f.dvf.json
# TODO: Parse output
cargo run --bin dv -- -c /tmp/eval_config.json generate-build-cache --project /tmp/uni-factory
cargo run --bin dv -- --verbose --verbose --config /tmp/eval_config.json init --address 0x5e8422345238f34275888049021821e8e08caa1f --contractname frxETH --project examples/frxETH-public --initblock 15728402 examples/dvfs/frx_out.dvf.json
cargo run --bin dv -- --verbose --verbose --config /tmp/eval_config.json init --address 0x5e8422345238f34275888049021821e8e08caa1f --zerovalue --contractname frxETH --project examples/frxETH-public --initblock 15728402 examples/dvfs/frx_out.dvf.json
cargo run --bin dv -- --config /tmp/eval_config.json sign examples/dvfs/frxETH_filtered.dvf.json
cargo run --bin dv -- --config /tmp/eval_config.json validate --validationblock 15729502 examples/dvfs/frxETH_filtered.dvf.json
cargo run --bin dv -- --config /tmp/eval_config.json validate --validationblock 15740402 examples/dvfs/CErc20Delegator_0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643.dvf.json || touch should_fail
Expand All @@ -41,7 +41,7 @@ cargo run --bin dv -- --config /tmp/eval_config.json sign examples/dvfs/CErc20D
cargo run --bin dv -- --config /tmp/eval_config.json validate --validationblock 15740402 examples/dvfs/CErc20Delegator_0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643_updated.dvf.json
# Make sure libraries work
cargo run --bin fetch-from-etherscan -- --config /tmp/eval_config.json --address 0x43506849D7C04F9138D1A2050bbF3A0c054402dd --project /tmp/usdc_implementation2
cargo run --bin dv -- -c /tmp/eval_config.json init --address 0x43506849D7C04F9138D1A2050bbF3A0c054402dd --project /tmp/usdc_implementation2 --chainid 1 --contractname FiatTokenV2_2 FiatTokenV2_2_0x43506849D7C04F9138D1A2050bbF3A0c054402dd.dvf.json
cargo run --bin dv -- -c /tmp/eval_config.json init --address 0x43506849D7C04F9138D1A2050bbF3A0c054402dd --project /tmp/usdc_implementation2 --chainid 1 --zerovalue --contractname FiatTokenV2_2 FiatTokenV2_2_0x43506849D7C04F9138D1A2050bbF3A0c054402dd.dvf.json
# - echo "DAI Tests"
# - cargo run --bin fetch-from-etherscan -- --config tests/test_config.json --project /tmp/dai --address 0x6b175474e89094c44da98b954eedeac495271d0f
# - cargo run --bin dv -- --config tests/test_config.json init --address 0x6b175474e89094c44da98b954eedeac495271d0f --project /tmp/dai --chainid 1 --contractname Dai Dai_0x6b175474e89094c44da98b954eedeac495271d0f.dvf.json
Expand Down
6 changes: 6 additions & 0 deletions tests/data/result_CrazyStruct.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"var_name": "S.D[0]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"value_hint": "0",
"comparison_operator": "Equal"
},
{
Expand All @@ -58,6 +59,7 @@
"var_name": "S.D[2]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"value_hint": "0",
"comparison_operator": "Equal"
},
{
Expand All @@ -66,6 +68,7 @@
"var_name": "S.D[3]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"value_hint": "0",
"comparison_operator": "Equal"
},
{
Expand All @@ -74,6 +77,7 @@
"var_name": "S.D[4]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"value_hint": "0",
"comparison_operator": "Equal"
},
{
Expand All @@ -100,6 +104,7 @@
"var_name": "S.mp[0xe7f1725e7734ce288f8367e1bb143e90bb3f0512][42]",
"var_type": "t_bool",
"value": "0x00",
"value_hint": "false",
"comparison_operator": "Equal"
},
{
Expand All @@ -117,6 +122,7 @@
"var_name": "S.F.length",
"var_type": "t_uint256",
"value": "0x0000000000000000000000000000000000000000000000000000000000000000",
"value_hint": "0",
"comparison_operator": "Equal"
}
]
15 changes: 10 additions & 5 deletions tests/data/result_DynamicArrayOfStaticArray.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,17 @@
"var_name": "dynamicStatic[1][0]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
},
{
"slot": "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565",
"offset": 8,
"var_name": "dynamicStatic[1][1]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
},
{
"slot": "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e565",
Expand All @@ -93,22 +95,25 @@
"var_name": "dynamicStatic[1][3]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
},
{
"slot": "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566",
"offset": 0,
"var_name": "dynamicStatic[1][4]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
},
{
"slot": "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566",
"offset": 8,
"var_name": "dynamicStatic[1][5]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
}
]
12 changes: 8 additions & 4 deletions tests/data/result_StaticArray.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,35 @@
"var_name": "staticArray[0]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
},
{
"slot": "0x0",
"offset": 8,
"var_name": "staticArray[1]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
},
{
"slot": "0x0",
"offset": 16,
"var_name": "staticArray[2]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
},
{
"slot": "0x0",
"offset": 24,
"var_name": "staticArray[3]",
"var_type": "t_uint64",
"value": "0x0000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
},
{
"slot": "0x1",
Expand Down
3 changes: 2 additions & 1 deletion tests/data/result_StaticArrayOfDynamicArray.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"var_name": "staticDynamicAddress[2].length",
"var_type": "t_uint256",
"value": "0x0000000000000000000000000000000000000000000000000000000000000000",
"comparison_operator": "Equal"
"comparison_operator": "Equal",
"value_hint": "0"
}
]
Loading
Loading