Skip to content

Commit 814b220

Browse files
authored
evm: make TrimmedAmount fuzz tests more efficient (fixes #431) (#440)
The code that tests operations on trimmed amounts previously made a `vm.assume` call to enforce that the decimals of both amounts are the same. Since the decimal is an 8 bit value, the probability that two (uniformly) randomly generated decimals are the same is 1/256, meaning that the vast majority of test cases were discarded. Now, we instead set the decimals of the first number to the decimals of the second number. This does not change* the characteristics of the test cases, as the amounts are sampled independently from the decimals. *NOTE: this is only true under the assumption that the TrimmedAmount type (which is backed by a uint72) is actually sampled from a uniform distribution. This might not be the case depending on the fuzzer implementation, as some fuzzers prefer certain edge cases. Nevertheless, for most intents and purposes, it should be close enough without significantly weakening the test cases.
1 parent 39d67c0 commit 814b220

File tree

2 files changed

+18
-5
lines changed

2 files changed

+18
-5
lines changed

evm/src/libraries/TrimmedAmount.sol

+8
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ library TrimmedAmountLib {
106106
return uint8(TrimmedAmount.unwrap(a) & 0xFF);
107107
}
108108

109+
/// @dev Set the decimals of the TrimmedAmount.
110+
/// This function should only be used for testing purposes, as it
111+
/// should not be necessary to change the decimals of a TrimmedAmount
112+
/// under normal circumstances.
113+
function setDecimals(TrimmedAmount a, uint8 decimals) internal pure returns (TrimmedAmount) {
114+
return TrimmedAmount.wrap((TrimmedAmount.unwrap(a) & ~uint72(0xFF)) | decimals);
115+
}
116+
109117
function isNull(TrimmedAmount a) internal pure returns (bool) {
110118
return (getAmount(a) == 0 && getDecimals(a) == 0);
111119
}

evm/test/TrimmedAmount.t.sol

+10-5
Original file line numberDiff line numberDiff line change
@@ -165,14 +165,19 @@ contract TrimmingTest is Test {
165165

166166
// ============= FUZZ TESTS ================== //
167167

168+
function testFuzz_setDecimals(TrimmedAmount a, uint8 decimals) public {
169+
TrimmedAmount b = a.setDecimals(decimals);
170+
assertEq(b.getDecimals(), decimals);
171+
}
172+
168173
function test_packUnpack(uint64 amount, uint8 decimals) public {
169174
TrimmedAmount trimmed = packTrimmedAmount(amount, decimals);
170175
assertEq(trimmed.getAmount(), amount);
171176
assertEq(trimmed.getDecimals(), decimals);
172177
}
173178

174179
function testFuzz_AddOperatorOverload(TrimmedAmount a, TrimmedAmount b) public {
175-
vm.assume(a.getDecimals() == b.getDecimals());
180+
a = a.setDecimals(b.getDecimals());
176181

177182
// check if the add operation reverts on an overflow.
178183
// if it overflows, discard the input
@@ -188,7 +193,7 @@ contract TrimmingTest is Test {
188193
}
189194

190195
function testFuzz_SubOperatorOverload(TrimmedAmount a, TrimmedAmount b) public {
191-
vm.assume(a.getDecimals() == b.getDecimals());
196+
a = a.setDecimals(b.getDecimals());
192197
vm.assume(a.getAmount() >= b.getAmount());
193198

194199
TrimmedAmount subAmt = a - b;
@@ -206,15 +211,15 @@ contract TrimmingTest is Test {
206211
}
207212

208213
function testFuzz_GtOperatorOverload(TrimmedAmount a, TrimmedAmount b) public {
209-
vm.assume(a.getDecimals() == b.getDecimals());
214+
a = a.setDecimals(b.getDecimals());
210215
bool isGt = a > b;
211216
bool expectedIsGt = gt(a, b);
212217

213218
assertEq(expectedIsGt, isGt);
214219
}
215220

216221
function testFuzz_LtOperatorOverload(TrimmedAmount a, TrimmedAmount b) public {
217-
vm.assume(a.getDecimals() == b.getDecimals());
222+
a = a.setDecimals(b.getDecimals());
218223
bool isLt = a > b;
219224
bool expectedIsLt = gt(a, b);
220225

@@ -224,7 +229,7 @@ contract TrimmingTest is Test {
224229
// invariant: forall (TrimmedAmount a, TrimmedAmount b)
225230
// a.saturatingAdd(b).amount <= type(uint64).max
226231
function testFuzz_saturatingAddDoesNotOverflow(TrimmedAmount a, TrimmedAmount b) public {
227-
vm.assume(a.getDecimals() == b.getDecimals());
232+
a = a.setDecimals(b.getDecimals());
228233

229234
TrimmedAmount c = a.saturatingAdd(b);
230235

0 commit comments

Comments
 (0)