- May 20, 2021
-
-
Alexander Theißen authored
* Move public functions up in rent.rs * Added RentStatus * Fix test name for consistency Co-authored-by: Michael Müller <[email protected]> * Mark rent functions as unstable * Add unstable interfaces to README * Fix doc typos Co-authored-by: Andrew Jones <[email protected]> * Use DefaultNoBound * Simplify calc_share(1) * Don't output empty debug messages * Make `seal_debug_message` unstable Co-authored-by: Michael Müller <[email protected]> Co-authored-by: Andrew Jones <[email protected]>
-
- May 19, 2021
-
-
thiolliere authored
* fix and test * fmt
-
thiolliere authored
* improve span for call * fix stderr file paths
-
thiolliere authored
* implement named generic for storages * fix error message on unexpected name for generic
-
- May 18, 2021
-
-
Kian Paimani authored
* Initial version, well tested, should work fine. * Add one last log line * Update frame/election-provider-multi-phase/src/unsigned.rs Co-authored-by: Gavin Wood <[email protected]> * Update frame/election-provider-multi-phase/src/unsigned.rs Co-authored-by: Guillaume Thiolliere <[email protected]> * Update frame/election-provider-multi-phase/src/unsigned.rs Co-authored-by: Guillaume Thiolliere <[email protected]> * Fix a few more things * fix build * rewrite the whole thing with a proper lock * clean * clean some nits * Add unit tests. * Update primitives/runtime/src/offchain/storage_lock.rs Co-authored-by: Peter Goodspeed-Niklaus <[email protected]> * Apply suggestions from code review Co-authored-by: Bastian Köcher <[email protected]> * Fix test * Fix tests Co-authored-by: Gavin Wood <[email protected]> Co-authored-by: Guillaume Thiolliere <[email protected]> Co-authored-by: Peter Goodspeed-Niklaus <[email protected]> Co-authored-by: Bastian Köcher <[email protected]>
-
stanly-johnson authored
* migrate to pallet! * fixes * fix genesis * code review fixes * Update frame/scheduler/src/lib.rs Co-authored-by: Keith Yeung <[email protected]> * Update frame/scheduler/src/lib.rs Co-authored-by: Keith Yeung <[email protected]> * Update frame/scheduler/src/lib.rs Co-authored-by: Keith Yeung <[email protected]> * Update frame/scheduler/src/lib.rs Co-authored-by: Keith Yeung <[email protected]> * Update frame/scheduler/src/lib.rs Co-authored-by: Keith Yeung <[email protected]> * fix metadata Co-authored-by: Keith Yeung <[email protected]>
-
- May 17, 2021
-
-
KingFishDev authored
-
thiolliere authored
* implement max_values + storages info * some formatting + doc * rename StoragesInfo -> PalletStorageInfo * merge both StorageInfoTrait and PalletStorageInfo I think it is more future proof. In the future some storage could make use of multiple prefix. Like one to store how much value has been inserted, etc... * Update frame/support/procedural/src/storage/parse.rs Co-authored-by: Peter Goodspeed-Niklaus <[email protected]> * Update frame/support/procedural/src/storage/storage_struct.rs Co-authored-by: Peter Goodspeed-Niklaus <[email protected]> * Fix max_size using hasher information hasher now expose `max_len` which allows to computes their maximum len. For hasher without concatenation, it is the size of the hash part, for hasher with concatenation, it is the size of the hash part + max encoded len of the key. * fix tests * fix ui tests Co-authored-by: Peter Goodspeed-Niklaus <[email protected]>
-
Keith Yeung authored
* Use StorageNMap for Approvals in assets pallet * Use EncodeLike on HashKeyPrefix trait bounds * Add comments clarifying AccountId roles * Properly document the keys in the Approvals storage * Fix line width
-
- May 15, 2021
-
-
ordian authored
-
- May 14, 2021
-
-
Keith Yeung authored
* Implement StorageNMap * Change copyright date to 2021 * Rewrite keys to use impl_for_tuples instead of recursion * Implement prefix iteration on StorageNMap * Implement EncodeLike for key arguments * Rename KeyGenerator::Arg to KeyGenerator::KArg * Support StorageNMap in decl_storage and #[pallet::storage] macros * Use StorageNMap in assets pallet * Support migrate_keys in StorageNMap * Reduce line characters on select files * Refactor crate imports in decl_storage macros * Some more line char reductions and doc comment update * Update UI test expectations * Revert whitespace changes to untouched files * Generate Key struct instead of a 1-tuple when only 1 pair of key and hasher is provided * Revert formatting changes to unrelated files * Introduce KeyGeneratorInner * Add tests for StorageNMap in FRAMEv2 pallet macro * Small fixes to unit tests for StorageNMap * Bump runtime metadata version * Remove unused import * Update tests to use runtime metadata v13 * Introduce and use EncodeLikeTuple as a trait bound for KArg * Add some rustdocs * Revert usage of StorageNMap in assets pallet * Make use of ext::PunctuatedTrailing * Add rustdoc for final_hash * Fix StorageNMap proc macro expansions for single key cases * Create associated const in KeyGenerator for hasher metadata * Refactor code according to comments from Basti * Add module docs for generator/nmap.rs * Re-export storage::Key as NMapKey in pallet prelude * Seal the EncodeLikeTuple trait * Extract sealing code out of key.rs Co-authored-by: Shawn Tabrizi <[email protected]>
-
- May 13, 2021
-
-
Alexander Theißen authored
* Move `Schedule` from Storage to Config * Updated CHANGELOG * Fix nits from review * Fix migration * Print the debug buffer as tracing message * Use `debug` instead of `trace` and update README * Add additional assert to test * Rename `schedule_version` to `instruction_weights_version` * Fixed typo * Added more comments to wat fixtures * Add clarification for the `debug_message` field
-
- May 12, 2021
-
-
stanly-johnson authored
* update to pallet macro * fixes * fix tests * remove unwanted generic * fix conflict * Fix storage and tabs Co-authored-by: Guillaume Thiolliere <[email protected]>
-
Andrew Jones authored
* Remove grandpa StoredPendingChange shim * Unused import
-
Sergey Pepyakin authored
* emit a custom section from impl_runtime_apis! This change emits a custom section from the impl_runtime_apis! proc macro. Each implemented API will result to emitting a link section `runtime_apis`. During linking all sections with this name will be concatenated and placed into the final wasm binary under the same name. * Introduce `runtime_version` proc macro This macro takes an existing `RuntimeVersion` const declaration, parses it and emits the version information in form of a linking section. Ultimately such a linking section will result into a custom wasm section. * Parse custom wasm section for runtime version * Apply suggestions from code review Co-authored-by: David <[email protected]> * Fix sc-executor integration tests * Nits Co-authored-by: Bastian Köcher <[email protected]> * Refactor apis section deserialization * Fix version decoding * Reuse uncompressed value for CallInWasm * Log on decompression error * Simplify if * Reexport proc-macro from sp_version * Merge ReadRuntimeVersionExt * Export `read_embedded_version` * Fix test * Simplify searching for custom section Co-authored-by: David <[email protected]> Co-authored-by: Bastian Köcher <[email protected]>
-
Shaun Wang authored
* Migrate pallet-recovery to pallet attribute macro. * Fix metadata inconsistency. * Use DispatchResult as call returns. * Apply review suggestions.
-
Shaun Wang authored
* Migrate pallet-lottery to pallet attribute macro. * Fix metadata inconsistency. * fix * Use DispatchResult in call returns.
-
Shaun Wang authored
* frame system: add event util functions for tests. * URemove unused fn. * Apply review suggestions.
-
- May 10, 2021
-
-
Shaun Wang authored
* Update pallet macro migrations. * Revert dispatchable call visibility changes. * fmt
-
Shaun Wang authored
* Add arithmetic dispatch errors. * Replace custom overflow errors. * Replace custom underflow and division by zero errors. * Replace overflow/underflow in token error. * Add token and arithmetic errors in dispatch error equality test. * Trigger CI.
-
Peter Goodspeed-Niklaus authored
* Add `BoundedBTreeSet` Part of https://github.com/paritytech/substrate/issues/8719 * fix copy-pasta errors Co-authored-by: Kian Paimani <[email protected]> Co-authored-by: Kian Paimani <[email protected]>
-
- May 08, 2021
-
-
Shawn Tabrizi authored
-
- May 07, 2021
-
-
Peter Goodspeed-Niklaus authored
* requiring users to maintain an unchecked invariant is unsafe * relax trait restrictions on BoundedVec<T, S> A normal `Vec<T>` can do many things without any particular trait bounds on `T`. This commit relaxes the bounds on `BoundedVec<T, S>` to give it similar capabilities.
-
Alexander Theißen authored
* contracts: Add default implementation for Executable::occupied_storage() * contracts: Refactor the exec module * Let runtime specify the backing type of the call stack This removes the need for a runtime check of the specified `MaxDepth`. We can now garantuee that we don't need to allocate when a new call frame is pushed. * Fix doc typo Co-authored-by: Guillaume Thiolliere <[email protected]> * cargo run --release --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * Review nits * Fix defect in contract info caching behaviour * Add more docs * Fix wording and typos Co-authored-by: Guillaume Thiolliere <[email protected]> Co-authored-by: Parity Benchmarking Bot <[email protected]>
-
Peter Goodspeed-Niklaus authored
* impl #[derive(MaxEncodedLen)] for structs * impl #[derive(MaxEncodedLen)] for enums, unions * break long comments onto multiple lines * add doc for public item * add examples to macro documentation * move MaxEncodedLen macro docs, un-ignore doc-tests
-
- May 06, 2021
-
-
Peter Goodspeed-Niklaus authored
* Add `BoundedBTreeMap` to `frame_support::storage` Part of https://github.com/paritytech/substrate/issues/8719. * max_encoded_len will never encode length > bound * requiring users to maintain an unchecked invariant is unsafe * only impl debug when std * add some marker traits * add tests
-
Peter Goodspeed-Niklaus authored
-
- May 05, 2021
-
-
Shaun Wang authored
* Migrate pallet-nicks to pallet attribute macro. * Fix constants.
-
Shaun Wang authored
* Migrate pallet-im-online to pallet attribute macro. * Move validate_unsigned into pallet macro. * fix metadata * fix test Co-authored-by: Guillaume Thiolliere <[email protected]>
-
Kian Paimani authored
-
- May 04, 2021
-
-
drewstone authored
Make system migrations public.
-
thiolliere authored
-
Peter Goodspeed-Niklaus authored
* implement BoundedEncodedLen * update header * update imports * use impl_for_tuples instead of a custom macro * remove redundant where clause Co-authored-by: Bastian Köcher <[email protected]> * impl for Compact<T> * impl BoundedEncodedLen for BoundedVec (#8727) * impl BoundedEncodedLen for bool * explicitly implement BoundedEncodedLen for each Compact form Turns out that u16 doesn't play nicely with the pattern; those values take two extra bytes, where all other cases take one. :( * rename BoundedEncodedLen -> MaxEncodedLen * add tests of compact encoded length Co-authored-by: Bastian Köcher <[email protected]>
-
Shawn Tabrizi authored
* improve bounded vec api * Update frame/support/src/storage/bounded_vec.rs Co-authored-by: Guillaume Thiolliere <[email protected]> * Update frame/support/src/storage/bounded_vec.rs * Update frame/support/src/storage/bounded_vec.rs Co-authored-by: Guillaume Thiolliere <[email protected]> Co-authored-by: Bastian Köcher <[email protected]>
-
ferrell-code authored
* bump pallet to frame v2 * line width * get benchmarking ot compile * fix benchmarking now * should actually fix benchmark * make docs prettier * add dependency * add metadata * Update frame/identity/src/benchmarking.rs Co-authored-by: Guillaume Thiolliere <[email protected]> Co-authored-by: Shawn Tabrizi <[email protected]> Co-authored-by: Guillaume Thiolliere <[email protected]>
-
- May 03, 2021
-
-
Bastian Köcher authored
* Lol * Yeah * Moare * adaasda * Convert AURA to new pallet macro * AURA: Switch to `CurrentSlot` instead of `LastTimestamp` This switches AURA to use `CurrentSlot` instead of `LastTimestamp`. * Add missing file * Update frame/aura/src/migrations.rs Co-authored-by: André Silva <[email protected]> * Remove the runtime side provide inherent code * Use correct weight * Add TODO * Remove the Inherent from AURA *
🤦 * Remove unused stuff * Update primitives authorship * Fix babe inherent data provider * Fix consensus-uncles * Fix BABE * Do some further changes to authorship primitives... :D * More work * Make it compile the happy path * Make it async! * Take hash * More stuff * Hacks * Revert "Hacks" This reverts commit cfffad88668cfdebf632a59c4fbfada001ef8251. * Fix * Make `execute_block` return the final block header * Move Aura digest stuff * Make it possible to disable equivocation checking * Fix fix fix * Some refactorings * Comment * Fixes fixes fixes * More cleanups * Some love * Better love * Make slot duration being exposed as `Duration` to the outside * Some slot info love * Add `build_aura_worker` utility function * Copy copy copy * Some stuff * Start fixing pow * Fix pow * Remove some bounds * More work * Make grandpa work * Make slots use `async_trait` * Introduce `SharedData` * Add test and fix bugs * Switch to `SharedData` * Make grandpa tests working * More Babe work * Make grandpa work * Introduce `SharedData` * Add test and fix bugs * Switch to `SharedData` * Make grandpa tests working * More Babe work * Make it async * Fix fix * Use `async_trait` in sc-consensus-slots This makes the code a little bit easier to read and also expresses that there can always only be one call at a time to `on_slot`. * Make grandpa tests compile * More Babe tests work * Fix network test * Start fixing service test * Finish service-test * Fix sc-consensus-aura * Fix fix fix * More fixes * Make everything compile *yeah* * Make manual-seal compile * More fixes * Start fixing Aura * Fix Aura tests * Fix Babe tests * Make everything compile * Move code around and switch to async_trait * Fix Babe * Docs docs docs * Move to FRAME * Fix fix fix * Make everything compile * Last cleanups * Fix integration test * Change slot usage of the timestamp * We really need to switch to `impl-trait-for-tuples` * Update primitives/inherents/src/lib.rs Co-authored-by: André Silva <[email protected]> * Update primitives/inherents/src/lib.rs Co-authored-by: André Silva <[email protected]> * Update primitives/inherents/src/lib.rs Co-authored-by: André Silva <[email protected]> * Some extra logging * Remove dbg! * Update primitives/consensus/common/src/import_queue/basic_queue.rs Co-authored-by: André Silva <[email protected]> Co-authored-by: André Silva <[email protected]> -
Peter Goodspeed-Niklaus authored
* not climate * explain the intent of the bool in the unsigned phase * remove glob imports from unsigned.rs * add OffchainRepeat parameter to ElectionProviderMultiPhase * migrate core logic from #7976 This is a much smaller diff than that PR contained, but I think it contains all the essentials. * improve formatting * fix test build failures * cause test to pass * Apply suggestions from code review Co-authored-by: Kian Paimani <[email protected]> * collapse imports * threshold acquired directly within try_acquire_offchain_lock * add test of resubmission after interval * add test that ocw can regenerate a failed cache when resubmitting * ensure that OCW solutions are of the correct round This should help prevent stale cached solutions from persisting past the election for which they are intended. * add test of pre-dispatch round check * use `RawSolution.round` instead of redundantly externally * unpack imports Co-authored-by: Kian Paimani <[email protected]> * rename `OFFCHAIN_HEAD_DB` -> `OFFCHAIN_LOCK` * rename `mine_call` -> `mine_checked_call` * eliminate extraneous comma * check cached call is current before submitting * remove unused consts introduced by bad merge. Co-authored-by: Guillaume Thiolliere <[email protected]> * resubmit when our solution beats queued solution * clear call cache if solution fails to submit * use local storage; clear on ElectionFinalized * Revert "use local storage; clear on ElectionFinalized" This reverts commit 4b46a9388532d0c09b337dc7c7edf76044a6cee8. * BROKEN: try to filter local events in OCW * use local storage; simplify score fetching * fix event filter * mutate storage instead of setting it * StorageValueRef::local isn't actually implemented yet * add logging for some events of interest in OCW miner * rename kill_solution -> kill_ocw_solution to avoid ambiguity * defensive err instead of unreachable given unreachable code * doc punctuation Co-authored-by: Kian Paimani <[email protected]> * distinguish miner errors between "out of date" and "call invalid" * downgrade info logs -> debug * ensure encoded call decodes as a call * fix semantics of validation of pre-dispatch failure for wrong round * move score check within `and_then` * add test that offchain workers clear their cache after election * ensure that bad ocw submissions are not retained for resubmission * simplify fn ocw_solution_exists * add feasibility check when restoring cached solution should address https://github.com/paritytech/substrate/pull/8290/files#r617533358 restructures how the checks are sequenced, which simplifies legibility. * simplify checks again Co-authored-by: Kian Paimani <[email protected]> Co-authored-by: Guillaume Thiolliere <[email protected]>
-
thiolliere authored
-
Lohann Paterno Coutinho Ferreira authored
* Removed can_report api from OnOffenceHandler * Removed DeferredOffences and create a storage migration * Removed missing comments * Mock set_deferred_offences and deferred_offences methods * OnOffenceHandler::on_offence always succeed * Fix benchmark tests * Fix runtime-benchmark cfg methods * Removed 'applied' attribute from Offence event * refactor deprecated deferred offences getter * Validate if offences are submited after on_runtime_upgrade * update changelog * Remove empty lines * Fix remove_deferred_storage weights * Remove Offence::on_runtime_upgrade benchmark * Revert CHANGELOG.md update * Deprecate DeferredOffenceOf type * Update copyright Co-authored-by: Kian Paimani <[email protected]> * Add migration logs Co-authored-by: Kian Paimani <[email protected]> * Fix migration log * Remove unused import * Add migration tests * rustfmt * use generate_storage_alias! macro * Refactor should_resubmit_deferred_offences test * Replace spaces by tabs * Refactor should_resubmit_deferred_offences test * Removed WeightSoftLimit * Removed WeightSoftLimit from tests and mocks * Remove unused imports * Apply suggestions from code review Co-authored-by: Kian Paimani <[email protected]>
-
Peter Goodspeed-Niklaus authored
* Refactor election solution trimming for efficiency The previous version always trimmed the `CompactOf<T>` instance, which was intrinsically inefficient: that's a packed data structure, which is naturally expensive to edit. It's much easier to edit the unpacked data structures: the `voters` and `assignments` lists. * rework length-trim tests to work with the new interface Test suite now compiles. Tests still don't pass because the macro generating the compact structure still generates `unimplemented!()` for the actual `compact_length_of` implementation. * simplify * add a fuzzer which can validate `Compact::encoded_size_for` The `Compact` solution type is generated distinctly for each runtime, and has both three type parameters and a built-in limit to the number of candidates that each voter can vote for. Finally, they have an optional `#[compact]` attribute which changes the encoding behavior. The assignment truncation algorithm we're using depends on the ability to efficiently and accurately determine how much space a `Compact` solution will take once encoded. Together, these two facts imply that simple unit tests are not sufficient to validate the behavior of `Compact::encoded_size_for`. This commit adds such a fuzzer. It is designed such that it is possible to add a new fuzzer to the family by simply adjusting the `generate_solution_type` macro invocation as desired, and making a few minor documentation edits. Of course, the fuzzer still fails for now: the generated implementation for `encoded_size_for` is still `unimplemented!()`. However, once the macro is updated appropriately, this fuzzer family should allow us to gain confidence in the correctness of the generated code. * Revert "add a fuzzer which can validate `Compact::encoded_size_for`" This reverts commit 916038790887e64217c6a46e9a6d281386762bfb. The design of `Compact::encoded_size_for` is flawed. When `#[compact]` mode is enabled, every integer in the dataset is encoded using run- length encoding. This means that it is impossible to compute the final length faster than actually encoding the data structure, because the encoded length of every field varies with the actual value stored. Given that we won't be adding that method to the trait, we won't be needing a fuzzer to validate its performance. * revert changes to `trait CompactSolution` If `CompactSolution::encoded_size_for` can't be implemented in the way that we wanted, there's no point in adding it. * WIP: restructure trim_assignments_length by actually encoding This is not as efficient as what we'd hoped for, but it should still be better than what it's replacing. Overall efficiency of `fn trim_assignments_length` is now `O(edges * lg assignments.len())`. * fix compiler errors * don't sort voters, just assignments Sorting the `voters` list causes lots of problems; an invariant that we need to maintain is that an index into the voters list has a stable meaning. Luckily, it turns out that there is no need for the assignments list to correspond to the voters list. That isn't an invariant, though previously I'd thought that it was. This simplifies things; we can just leave the voters list alone, and sort the assignments list the way that is convenient. * WIP: add `IndexAssignment` type to speed up repeatedly creating `Compact` Next up: `impl<'a, T> From<&'a [IndexAssignmentOf<T>]> for Compact`, in the proc-macro which makes `Compact`. Should be a pretty straightforward adaptation of `from_assignment`. * Add IndexAssignment and conversion method to CompactSolution This involves a bit of duplication of types from `election-provider-multi-phase`; we'll clean those up shortly. I'm not entirely happy that we had to add a `from_index_assignments` method to `CompactSolution`, but we couldn't define `trait CompactSolution: TryFrom<&'a [Self::IndexAssignment]` because that made trait lookup recursive, and I didn't want to propagate `CompactSolutionOf<T> + TryFrom<&[IndexAssignmentOf<T>]>` everywhere that compact solutions are specified. * use `CompactSolution::from_index_assignment` and clean up dead code * get rid of `from_index_assignments` in favor of `TryFrom` * cause `pallet-election-provider-multi-phase` tests to compile successfully Mostly that's just updating the various test functions to keep track of refactorings elsewhere, though in a few places we needed to refactor some test-only helpers as well. * fix infinite binary search loop Turns out that moving `low` and `high` into an averager function is a bad idea, because the averager gets copies of those values, which of course are never updated. Can't use mutable references, because we want to read them elsewhere in the code. Just compute the average directly; life is better that way. * fix a test failure * fix the rest of test failures * remove unguarded subtraction * fix npos-elections tests compilation * ensure we use sp_std::vec::Vec in assignments * add IndexAssignmentOf to sp_npos_elections * move miner types to `unsigned` * use stable sort * rewrap some long comments * use existing cache instead of building a dedicated stake map * generalize the TryFrom bound on CompactSolution * undo adding sp-core dependency * consume assignments to produce index_assignments * Add a test of Assignment -> IndexAssignment -> Compact * fix `IndexAssignmentOf` doc * move compact test from sp-npos-elections-compact to sp-npos-elections This means that we can put the mocking parts of that into a proper mock package, put the test into a test package among other tests. Having the mocking parts in a mock package enables us to create a benchmark (which is treated as a separate crate) import them. * rename assignments -> sorted_assignments * sort after reducing to avoid potential re-sort issues * add runtime benchmark, fix critical binary search error "Why don't you add a benchmark?", he said. "It'll be good practice, and can help demonstrate that this isn't blowing up the runtime." He was absolutely right. The biggest discovery is that adding a parametric benchmark means that you get a bunch of new test cases, for free. This is excellent, because those test cases uncovered a binary search bug. Fixing that simplified that part of the code nicely. The other nice thing you get from a parametric benchmark is data about what each parameter does. In this case, `f` is the size factor: what percent of the votes (by size) should be removed. 0 means that we should keep everything, 95 means that we should trim down to 5% of original size or less. ``` Median Slopes Analysis ======== -- Extrinsic Time -- Model: Time ~= 3846 + v 0.015 + t 0 + a 0.192 + d 0 + f 0 µs Min Squares Analysis ======== -- Extrinsic Time -- Data points distribution: v t a d f mean µs sigma µs % <snip> 6000 1600 3000 800 0 4385 75.87 1.7% 6000 1600 3000 800 9 4089 46.28 1.1% 6000 1600 3000 800 18 3793 36.45 0.9% 6000 1600 3000 800 27 3365 41.13 1.2% 6000 1600 3000 800 36 3096 7.498 0.2% 6000 1600 3000 800 45 2774 17.96 0.6% 6000 1600 3000 800 54 2057 37.94 1.8% 6000 1600 3000 800 63 1885 2.515 0.1% 6000 1600 3000 800 72 1591 3.203 0.2% 6000 1600 3000 800 81 1219 25.72 2.1% 6000 1600 3000 800 90 859 5.295 0.6% 6000 1600 3000 800 95 684.6 2.969 0.4% Quality and confidence: param error v 0.008 t 0.029 a 0.008 d 0.044 f 0.185 Model: Time ~= 3957 + v 0.009 + t 0 + a 0.185 + d 0 + f 0 µs ``` What's nice about this is the clear negative correlation between amount removed and total time. The more we remove, the less total time things take.
-