Open ehildenb opened 4 years ago
sneak-tx-tracking
.Jug
.end.sol
will be modelled, which "changes the game" by changing which types of interactions are allowed in the actual data modules.dai.k
actually should be rolled into collateral.k
. But dai
does have mint
and burn
which makes it behave slightly differently than other collateral.stubs
.dump
risk parameter, and automated increase in value of auction at tick
intervals.stubs
PR merged.dai-semantics
merged.stubs
PR merged, refactored semantics builds and passes tests: https://github.com/runtimeverification/mkr-mcd-spec/pull/21Spot
merged: https://github.com/runtimeverification/mkr-mcd-spec/pull/27rat.k
merged into K, semantics switched over to it: https://github.com/kframework/k/pull/779auth
, init
, how call
works vs. transact
, etc...)gem
interface. Do we need to model dai
token directly for example? We aren't planning on modelling MKR token directly, for example, just with a generic gem
.<gem>
? Outside from mint
/burn
, we probably don't need to."Rat
which mark the needed precision of each. Hopefully this helps with being able to do refinement proofs "up to epsilon" of the solidity implementation."MKR"
, "DAI"
, and "WETH"
), rather than contract address, and contract address will be a data field. This will make it more apparent which gems are being manipulated by the contracts inside MCD._^Rat_
for use in #pow
, refinements of use of Rat
in K: kframework/k#785Rat
operators describing precision needed: #58String
type for bytes32
in Solidity: #60Approaching milestone 2 with the above merged and end.sol
implementation.
Develop the K specification of the high-level behaviors of the MCD corecontracts. This will describe entry/exit points of the contracts, and overall state-updates that eachoperation in the system should have.
To claim victory, we need to (i) implement the note
modifier, and (ii) implement the specific GemJoin contracts found in: https://github.com/makerdao/dss-deploy/blob/master/src/join.sol, (iii) implement vow.sol, and (iv) implement end.sol.
From internal meeting:
How can be build more excitement around this model from the MKR side? Potentially we can start working on the future directions part, eg. (i) generating documentation, (ii) statistical model checking, or (iii) fuzzing/test generation for the Solidity code.
pot
? https://github.com/runtimeverification/mkr-mcd-spec/pull/57#discussion_r327856613note
events and contract-specific events.Pot
: #57Join
ers: #61Vow
: #66end.sol
: #69Cat
: #72 sub
reverts on underflow on this line: https://github.com/makerdao/dss/blob/master/src/pot.sol#L139. Maybe a clearer way to do it is to assert that file
doesn't set it too low or something: https://github.com/makerdao/dss/blob/master/src/pot.sol#L122note
modifier log events are emitted now: #75UrnHandler
deployment (will send example of contract deployment verification done for Eth 2.0 deposit contract).Meetings interrupted by DevCon, should be back on track.
file
methods for setting up tests: #80 ward
ing each other in a real world deployment? No, we probably want auth
at the call
boundary, not at the transact
boundary, so that we can model "accidental" updates which end up introducing calls to the wrong internal contracts down the line.lucash-pot-end
example.ward
/authentication scheme implemented: #81lucash-pot
, @ehildenb can take lucash-flip-end
. That leaves lucash-flap-end
.lucash-flap-end
and lucash-flip-end
attacks, flesh out skeleton of how they work.lucash-pot
yet for @malturki. Has been reviewing the KMCD spec so far.wards
authentication scheme with @malturki, caught two bugs, MCStep
typo and *-live
on rely
and deny
.flip-end
bug to @gtrepta .lucash-pot
bug: #89Jug . drip
is in charge of rate-accumulation so that people are charged stability fees. Pot . drip
is for users to accumulate interest on their held Dai. Governance is in charge of periodically calling Jug . drip
, but a user may be able to implement the Pot . drip
attack between calls of Jug . drip
if the calls are not frequent enough.Pot . drip Jug . drip Vat . frob -> Pot . join -> (delayed as much as possible, but not past the next Jug . drip) Pot . drip -> Pot . exit -> Vat . frob Jug . drip
It's important that the Vat . frob
happens on either side so that the dai used to make the attack is not charged the stability fee.
flap-end
bug: #86 flip-end
bug: #85 pot
bug: #83 TimeStep
events: #95Exception
events too: #99End . cage
would be needed for upgrade, since moving the Vat
storage would be too gas-expensive/delicate (esp. translating the Vat . hope/nope
calls that have been made thus far). No plans yet for MCD2.0 launch, but having potential refactorings listed would still be useful so it could be included in an MCD2.0 launch if it happens.assert
construct: #110 <vat-sin>
ever non-zero for a user who is not the Vow
? Just on inspecting the semantics, it looks like it's not the case that <vat-sin>
is ever changed for a user other than Vow
.Flap . kick
was un-auth
ed, what would be a reasonable maximum BID
? This affects the random tester because it looks like the reasonable maximum is however much Gem "MKR"
the Flap
contract currently holds is the maximum, but that seems to have little correspondence to the contract doing the kick
ing. Is there a reasonable scenario where BID
starts as non-zero?<vat-sin>[Vow] == <vat-vice>
pyk
library to better handle KMCD: kframework/k#921frob
and Flip
auctions which don't cover the tab
should not grow by more than DSR - stability fee (and should probably even shrink).Flip
auction. So you could put 10 gem into an urn, and get another 10 gem via a sequence of auctions (a Flap auction to get enough vat-dai to pay back stability fee + to bid on a Flip
auction for the gem), and then exit all 20 gem from the Vat (after closing your CDPs).End . cage
goes through, whatever Dai you have (including vat-dai and dai locked in auctions) represents your total share of the overall gem in the system, and thus how much gem you should be paid out (adjusted for the price of that gem). Narrows possible sequences to only ones which are not require(live)
, can we take this into account in the test generation?End . cage
, the total debt
/dai in system should not increase (except for maybe Flip
auctions?).End . thaw
.End . cage
, a user should not be able to decrease an urns Ink
except via End . skim
or Vat . fork
. Another variation would be that the total amount of ink
does not go down.End . cage
the debt drawn per collateral shouldn't change.<vat-dai>
for the adapter for erc20 dai.<vat-dai>
to ERC20 Dai can be followed by a move back of equal or lesser value (assuming no Dai . ...
calls).From the chat:
Chris Smith10:05 AM https://github.com/runtimeverification/mkr-mcd-spec Gonzalo Balabasquer10:37 AM flux doesn't change ink Andy Chorlian10:41 AM Still trying to make sure I get how this works but could something along the lines of this work? Dai joined to the pot can never exit for less than the amount joined? Chris Smith10:42 AM i like that one @andy Kurt Barry10:42 AM ^I think you could actually set the dsr < 1 Andy Chorlian10:43 AM it is a uint how would that work? Chris Smith10:43 AM you could, but eventually the drip is going to hit a negative here: https://github.com/makerdao/dss/blob/master/src/pot.sol#L143 if you set dsr to more than 0 but less than 1 you get a "negative" DSR Andy Chorlian10:44 AM oh I am dumb Chris Smith10:44 AM and would decrease the Pie per user until you ran out of Chi and then drips would fail Gonzalo Balabasquer10:47 AM not sure if I followed the last part, you never can have dsr set lower to 1 otherwise drip will always fail Chris Smith10:48 AM @gonza, if we let DSR run for a bit, we build up some Chi, then we could set it to less than 1 and decrease the chi for a set period of time, right? Gonzalo Balabasquer10:48 AM nope this "uint chi_ = sub(tmp, chi);" will always fail if dsr is set lower to 1 "tmp = rmul(rpow(dsr, now - rho, ONE), chi);" is always lower than chi if dsr is lower than 1 Chris Smith10:49 AM because tmp would immediately be larger than chi? or yeah i meant smaller Gonzalo Balabasquer10:50 AM right Chris Smith10:51 AM ahh ok, so going back to andy's original suggestion, Dai joined to the pot can never exit for less than the amount joined? Gonzalo Balabasquer10:54 AM I'd phrase it as the amount of DAI taken when joining X amount of pie has to be same or lower than the one returned when exiting X amount of pie. Kurt Barry10:56 AM That should work then. Aside: that is a rather tricky way to enforce dsr > 1... Of course, our code is full of all sorts of important things that are only subtly enforced in safe math checks. Chris Smith10:58 AM 4pm ET: https://meet.google.com/weu-axjy-baz
totalDebtBounded
finds the known bugs with lucash-pot and lucash-pot-end.?
variables: #137 test-random
which runs random tester: #136 --no-sort-collections
. Will allow us to avoid generating Kore directly and still be able to use frontend.Pull request for reporting minimized violations: #145
Dockerfile minimization: #146
@kmbarry1 fixes to sorts of Bit types: #147
Simple fix to PotChiPieDai invariant (discussion, better way to do it?): #150
Some simple usability improvements: #149
Anyone else have a chance to run the tool?
@kmbarry1 get a chance to work on discussed invariants last week?
AddGenerator ( ( ( GenFlapKick | GenFlapTick | GenFlapTend | GenFlapDeal ) ) ; GenEndCage ; ( ( GenFlapTick | GenFlapYank ) ) )
vat.dai(Flap) - sumOfAllLots >= 0 Gem.MKR(Flap) - sumOfAllBids >= 0
// If Flap.deal event adjusts
constant
appropriately: sum(Gem.MKR.balances without Flap) + sumOfAllBids == constant // (deals are handled accordingly)sum(Gem.MKR.balances without Flap) + sumOfAllBids <= Gem.MKR.totalSupply
Bridge between RV Slack and MKR channel? From @godsflaw: perhaps this: https://zapier.com/apps/rocketchat/integrations/slack
Need to work in two directions from here, (1) generalizing the steps that can be generated by kmcd-prelude.md
, and (2) conformance testing. Conformance testing I can output a log of transactions generated by the accounts in some consumable format (JSON?), can someone on the MKR team take care of making a testing harness to feed this into the actual Solidity implementation? If we can turn it into proper signed transactions somehow, we can feed it into any web3 client (including KEVM). Otherwise we can hack something together with KEVM, but it may take longer.
Rough translation:
transact ADMIN Pot . file dsr 23 /Rat 20
TimeStep 1
transact "Bobby" Vat . move "Bobby" Pot 495 /Rat 64
becomes:
admin.Potfile("dsr", 23/20);
hevm.warp(now + 1);
bobby.vatMove(address(bobby), address(Pot), 495 / 64);
assertEq(vat.dai(address(bobby)), SOME_NUMBER);
DEPLOY-PRELUDE (suggested by @kmbarry1 ). Sounds good for now, seems simplest way to do it, also perhaps a bit more transparent than hardcoding into initial configuration.
Solidity code emission #155
Example output (does it look feasible?):
ADMIN.Vat_rely(address(Pot));
ADMIN.Vat_rely(address(End));
ADMIN.Pot_rely(address(End));
ADMIN.Vow_rely(address(Pot));
ADMIN.Vow_rely(address(End));
ADMIN.Cat_rely(address(End));
ADMIN.Flap_rely(address(Vow));
ADMIN.Flop_rely(address(Vow));
ADMIN.Pot_file("vow", address(Vow));
ADMIN.Vat_rely(address(GemJoin_gold));
ADMIN.Spot_setPrice("gold", 1);
ADMIN.Flip_gold_rely(address(End));
ADMIN.Gem_MKR_mint(address(Flap), 20);
ADMIN.Vat_file("Line", 1000000000000);
ADMIN.Vat_file("spot", "gold", 3000000000);
ADMIN.Vat_file("line", "gold", 1000000000000);
ADMIN.Vow_file("bump", 1000000000);
ADMIN.Gem_gold_mint(address(Alice), 20);
ADMIN.Gem_gold_mint(address(Bobby), 20);
Alice.Vat_hope(address(Pot));
Alice.Vat_hope(address(Flip_gold));
Alice.Vat_hope(address(End));
Bobby.Vat_hope(address(Pot));
Bobby.Vat_hope(address(Flip_gold));
Bobby.Vat_hope(address(End));
Alice.Vat_slip("gold", address(Alice), 10);
Alice.Gem_gold_transferFrom(address(Alice), address(GemJoin_gold), 10);
Alice.GemJoin_gold_join(address(Alice), 10);
Bobby.Vat_slip("gold", address(Bobby), 10);
Bobby.Gem_gold_transferFrom(address(Bobby), address(GemJoin_gold), 10);
Bobby.GemJoin_gold_join(address(Bobby), 10);
Alice.Vat_frob("gold", address(Alice), address(Alice), address(Alice), 10, 10);
Bobby.Vat_frob("gold", address(Bobby), address(Bobby), address(Bobby), 10, 10);
Pot.Vat_move(address(Pot), address(Vow), 0);
ADMIN.Vat_cage();
ADMIN.Cat_cage();
Vow.Vat_move(address(Flap), address(Vow), 0);
End.Flap_cage(0);
End.Flop_cage();
End.Vat_heal(0);
ADMIN.Vow_cage();
ADMIN.Pot_cage();
ADMIN.End_cage();
Pot.Vat_hope(address(Alice));
ANYONE.End_cage("gold");
hevm.warp(2);
hevm.warp(1);
ANYONE.End_thaw();
ANYONE.End_flow("gold");
ANYONE.Vat_suck(address(Vow), address(Pot), 0);
ANYONE.Pot_drip();
ANYONE.Vat_grab("gold", address(Bobby), address(End), address(Vow), -10, -10);
ANYONE.End_skim("gold", address(Bobby));
ANYONE.Vat_grab("gold", address(Bobby), address(End), address(Vow), 0, 0);
ANYONE.End_skim("gold", address(Bobby));
Alice.Vat_move(address(Pot), address(Alice), 0);
Alice.Pot_exit(0);
Alice.Vat_move(address(Alice), address(Pot), 625_/Rat_64);
Alice.Pot_join(625_/Rat_64);
hevm.warp(1);
ANYONE.Vat_suck(address(Vow), address(Pot), 0);
ANYONE.Pot_drip();
Alice.Vat_move(address(Pot), address(Alice), 625_/Rat_64);
Alice.Pot_exit(625_/Rat_64);
ACTION Remove intermediate steps, intermediate steps should record caller not transaction initiator.
To regenerate (will add these to the repo README):
find . -name kast.py # grab directory this is in as THAT_DIRECTORY
export PYTHONPATH=THAT_DIRECTORY
find . -name krun # grab the direcotry as KRUN_DIRECTORY
export PATH=$KRUN_DIRECTORY:$PATH
./mcd-pyk.py random-test --help
./mcd-pyk.py random-test 100 1 --emit-solidity
Not sure where to jump in instructions for repo README, make clearer the delineation between setup and running. ACTION: Update readme with clearer innstructions.
Need to filter to only include top-level calls. ACTION: Will drop markers in the trace to say "this is an actual external call" and only keep those external calls.
What to do about fractions and scaling to wad/rad/ray? I think we'll have to manually hardcode those rules into the solidity generator. ACTION Solidity testing harness will handle fractions, just scale them all up by smallest of Rad/Ray/Wad (think 10^18?).
Assertions need to be added. I have local work making a minimized state delta between states (i) after attack prelude, and (ii) after generating steps. Can show what it looks like, discuss what assertions should look like some more. ACTION Actually do best-effort generation of assertions.
2 milestones left, (1) is throughput, and (2) is conformance. Let's discuss and define done for them.
Throughput seems pretty good right now, we know of one more optimization we can make to go from 2s/run to roughly 0.01s/run, which will be a major jump, but it will take a little while to implement (skip KAST format, directly feed input into backend). Right now we can find the known attacks relatively quickly with the existing random tester. ACTION Chris will review and let me know.
Conformance testing needs assertions and a testing harness. Maybe we can pair on someone's machine who has the dss testing harness setup, and we can take the output above and turn it into a test, taking notes about what needs to change in the output to make it work. DEFN: Able to generate solidity and automatically dump it into a template file (just have some string DUMP_CODE_HERE), and it runs in normal testing harness correctly, and if we break it it breaks correctly.
Merged solidity emission from last week #155, has intermediate steps removed.
Documentation/cleanup PR #159.
4x speedup when using KServer observed (documented in PR #159).
Current output of asserting adder:
// Test Run
ADMIN.Vat_rely(PotLike(Pot));
ADMIN.Vat_rely(EndLike(End));
ADMIN.Pot_rely(EndLike(End));
ADMIN.Vow_rely(PotLike(Pot));
ADMIN.Vow_rely(EndLike(End));
ADMIN.Cat_rely(EndLike(End));
ADMIN.Flap_rely(VowLike(Vow));
ADMIN.Flop_rely(VowLike(Vow));
ADMIN.Pot_file("vow", VowLike(Vow));
ADMIN.Vat_rely(GemJoinLike(GemJoin_gold));
ADMIN.Spot_setPrice("gold", 1);
ADMIN.Flip_gold_rely(EndLike(End));
ADMIN.Gem_MKR_mint(FlapLike(Flap), 20);
ADMIN.Vat_file("Line", 1000000000000);
ADMIN.Vat_file("spot", "gold", 3000000000);
ADMIN.Vat_file("line", "gold", 1000000000000);
ADMIN.Vow_file("bump", 1000000000);
ADMIN.Gem_gold_mint(UserLike(Alice), 20);
ADMIN.Gem_gold_mint(UserLike(Bobby), 20);
Alice.Vat_hope(PotLike(Pot));
Alice.Vat_hope(FlipLike(Flip_gold));
Alice.Vat_hope(EndLike(End));
Bobby.Vat_hope(PotLike(Pot));
Bobby.Vat_hope(FlipLike(Flip_gold));
Bobby.Vat_hope(EndLike(End));
Alice.GemJoin_gold_join(UserLike(Alice), 10);
Bobby.GemJoin_gold_join(UserLike(Bobby), 10);
Alice.Vat_frob("gold", UserLike(Alice), UserLike(Alice), UserLike(Alice), 10, 10);
Bobby.Vat_frob("gold", UserLike(Bobby), UserLike(Bobby), UserLike(Bobby), 10, 10);
ADMIN.End_cage();
ANYONE.End_cage("gold");
ANYONE.End_thaw();
ANYONE.End_flow("gold");
// Assertions
CatLike.get_live == false;
EndLike.get_live == false;
EndLike.get_debt == 20;
EndLike.get_tag == "gold" |-> 1;
EndLike.get_art == "gold" |-> 20;
EndLike.get_fix == "gold" |-> 1;
FlapLike.get_live == false;
FlopLike.get_live == false;
VatLike.get_live == false;
VowLike.get_live == false;
ACTIONS
Alice.Vat_hope(PotLike(Pot)); => Alice.Vat_hope(address(Pot));
ADMIN.Gem_gold_mint(UserLike(Bobby), 20); => ADMIN.Gem_gold_mint(address(Bobby), 20);
EndLike.get_live == false; => assertTrue(End.live() == 0);
EndLike.get_debt == 20; => assertTrue(End.debt() == 20);
EndLike.get_tag == "gold" |-> 1; => assertTrue(End.tag("gold") == 1);
// without ABI encoder?
(,uint art) = Vat.urns("gold", address(Alice));
assertTrue(art == 30);
// needs pragma ABI encoder? perhaps needs wrapping of `Vat` in `VatLike`?
pragma experimental ABIEncoderV2;
assertTrue(Vat.urns("gold", address(Alice)).art == 30);
ACTION: Handle the fractions/ratios.
snapshot
of the state more frequently (instead of Measure()
), so that we can go back over the trace and say things like "when it's the case that we would want to be able to Flop
, are we always able to Flop
?". Not really a deadlock property, but some sort of "system is live enough property".note
modifier), (iii) custom events that some functions emit, and (iv) exceptions, generation steps, etc.... It may be nice to clean this up by having a more structured log of the events that occur, specifically we could bundle all generated events with the transaction event that caused them. The one downside is this will make it trickier to specify properties that we want to hold at all intermediate states as well, not just at transaction boundaries. Response: We really only care about transaction-level consistency anyway, so let's go with a bit more structure and only have the properties checked over transaction calls. Later we can add back in ability to handle call-level properties.kmcd-data.md
which defines operators like rmul
and rpow
which handle the arithmetic that the system does, and then (2) we'll switch out underlying implementation in kmcd-data.md
for Int
instead of Rat
.tests/attacks
which represents the failure to call Vow . flop
after minimal setup.GUY
into the conditional, because it makes the K rules much uglier but doesn't actually change the behavior of the model, whereas conditionally calling the Vat . move
does change the behavior).-beg>
and -pad>
are now Wad
, but I don't know if it was the original intention in the code.rmul
like operations where specified: #173.CircleCI PR ready for review: https://github.com/makerdao/mkr-mcd-spec/pull/180
Changes to Auction contracts ready for review: https://github.com/makerdao/mkr-mcd-spec/pull/175
Fixed point representation blocked on issue in K frontend, but also ready for re-review: https://github.com/makerdao/mkr-mcd-spec/pull/184
Now generating Solidity source code like this:
// Test Run
admin.vat_rely(address(goldJoin));
admin.spotter_setPrice("gold", 3000000000000000000000000000);
admin.spotter_file("mat", "gold", 1000000000000000000000000000);
admin.spotter_file("par", 1000000000000000000000000000);
admin.goldFlip_rely(address(end));
admin.vat_file("line", "gold", 1000000000000000000000000000000000000000000000000000000000);
admin.Gem_gold_mint(address(alice), 20000000000000000000);
admin.Gem_gold_mint(address(bobby), 20000000000000000000);
alice.vat_hope(address(pot));
alice.vat_hope(address(goldFlip));
alice.vat_hope(address(end));
alice.vat_hope(address(flop));
bobby.vat_hope(address(pot));
bobby.vat_hope(address(goldFlip));
bobby.vat_hope(address(end));
bobby.vat_hope(address(flop));
alice.goldJoin_join(address(alice), 10000000000000000000);
bobby.goldJoin_join(address(bobby), 10000000000000000000);
bobby.goldJoin_join(address(bobby), 8000000000000000000);
bobby.vat_move(address(bobby), address(alice), 0);
admin.pot_file("dsr", 1000000000000000000000000000);
hevm.warp(1);
bobby.vat_hope(address(alice));
hevm.warp(1);
hevm.warp(1);
// Assertions
// UNIMPLEMENTED << assertTrue( Gems.cell() == GemCellMapItem( <gem-id>
// "gold"
//</gem-id> , <gem>
// <gem-id>
// "gold"
// </gem-id>
// <gem-wards>
// .Set
// </gem-wards>
// <gem-balances>
// "bobby" |-> FInt( 2000000000000000000 , 1000000000000000000 )
// GemJoin "gold" |-> FInt( 28000000000000000000 , 1000000000000000000 )
// "alice" |-> FInt( 10000000000000000000 , 1000000000000000000 )
// </gem-balances>
//</gem> ) ); >>
assertTrue( vat.can(address(bobby), address(pot)) != 0 );
assertTrue( vat.can(address(bobby), address(flop)) != 0 );
assertTrue( vat.can(address(bobby), address(alice)) != 0 );
assertTrue( vat.can(address(bobby), address(goldFlip)) != 0 );
assertTrue( vat.can(address(bobby), address(end)) != 0 );
assertTrue( vat.can(address(alice), address(pot)) != 0 );
assertTrue( vat.can(address(alice), address(flop)) != 0 );
assertTrue( vat.can(address(alice), address(goldFlip)) != 0 );
assertTrue( vat.can(address(alice), address(end)) != 0 );
assertTrue( vat.gem("gold", address(end)) == 0 );
assertTrue( vat.gem("gold", address(alice)) == 10000000000000000000 );
assertTrue( vat.gem("gold", address(goldFlip)) == 0 );
assertTrue( vat.gem("gold", address(bobby)) == 18000000000000000000 );
Can someone make a testing harness that this can be dropped into? Who would be good for this?
pragma solidity ^0.5.12;
import "./MkrMcdSpecSolTests.t.sol";
contract TestExample is MkrMcdSpecSolTestsTest {
function test0() public {
// Test Run
admin.vat_rely(address(goldJoin));
admin.spotter_setPrice("gold", 3000000000000000000000000000);
admin.spotter_file("mat", "gold", 1000000000000000000000000000);
admin.spotter_file("par", 1000000000000000000000000000);
admin.goldFlip_rely(address(end));
admin.vat_file("line", "gold", 1000000000000000000000000000000000000000000000000000000000);
admin.Gem_gold_mint(address(alice), 20000000000000000000);
admin.Gem_gold_mint(address(bobby), 20000000000000000000);
alice.vat_hope(address(pot));
alice.vat_hope(address(goldFlip));
alice.vat_hope(address(end));
alice.vat_hope(address(flop));
bobby.vat_hope(address(pot));
bobby.vat_hope(address(goldFlip));
bobby.vat_hope(address(end));
bobby.vat_hope(address(flop));
alice.goldJoin_join(address(alice), 10000000000000000000);
bobby.goldJoin_join(address(bobby), 10000000000000000000);
alice.vat_move(address(alice), address(alice), 0);
admin.pot_file("dsr", 1000000000000000000000000000);
hevm.warp(1);
bobby.vat_hope(address(alice));
hevm.warp(2);
hevm.warp(1);
// Assertions
assertTrue( vat.can(address(bobby), address(pot)) != 0 );
assertTrue( vat.can(address(bobby), address(flop)) != 0 );
assertTrue( vat.can(address(bobby), address(alice)) != 0 );
assertTrue( vat.can(address(bobby), address(goldFlip)) != 0 );
assertTrue( vat.can(address(bobby), address(end)) != 0 );
assertTrue( vat.can(address(alice), address(pot)) != 0 );
assertTrue( vat.can(address(alice), address(flop)) != 0 );
assertTrue( vat.can(address(alice), address(goldFlip)) != 0 );
assertTrue( vat.can(address(alice), address(end)) != 0 );
}
function test1() public {
// Test Run
admin.vat_rely(address(goldJoin));
admin.spotter_setPrice("gold", 3000000000000000000000000000);
admin.spotter_file("mat", "gold", 1000000000000000000000000000);
admin.spotter_file("par", 1000000000000000000000000000);
admin.goldFlip_rely(address(end));
admin.vat_file("line", "gold", 1000000000000000000000000000000000000000000000000000000000);
admin.Gem_gold_mint(address(alice), 20000000000000000000);
admin.Gem_gold_mint(address(bobby), 20000000000000000000);
alice.vat_hope(address(pot));
alice.vat_hope(address(goldFlip));
alice.vat_hope(address(end));
alice.vat_hope(address(flop));
bobby.vat_hope(address(pot));
bobby.vat_hope(address(goldFlip));
bobby.vat_hope(address(end));
bobby.vat_hope(address(flop));
alice.goldJoin_join(address(alice), 10000000000000000000);
bobby.goldJoin_join(address(bobby), 10000000000000000000);
bobby.vat_move(address(bobby), address(alice), 0);
alice.goldJoin_join(address(alice), 4000000000000000000);
bobby.vat_hope(address(alice));
admin.pot_file("dsr", 1000000000000000000000000000);
hevm.warp(2);
hevm.warp(2);
hevm.warp(2);
// Assertions
// UNIMPLEMENTED << assertTrue( Gems.cell() == GemCellMapItem( <gem-id>
// "gold"
//</gem-id> , <gem>
// <gem-id>
// "gold"
// </gem-id>
// <gem-wards>
// .Set
// </gem-wards>
// <gem-balances>
// "bobby" |-> FInt( 10000000000000000000 , 1000000000000000000 )
// GemJoin "gold" |-> FInt( 24000000000000000000 , 1000000000000000000 )
// "alice" |-> FInt( 6000000000000000000 , 1000000000000000000 )
// </gem-balances>
//</gem> ) ); >>
assertTrue( vat.can(address(bobby), address(pot)) != 0 );
assertTrue( vat.can(address(bobby), address(flop)) != 0 );
assertTrue( vat.can(address(bobby), address(alice)) != 0 );
assertTrue( vat.can(address(bobby), address(goldFlip)) != 0 );
assertTrue( vat.can(address(bobby), address(end)) != 0 );
assertTrue( vat.can(address(alice), address(pot)) != 0 );
assertTrue( vat.can(address(alice), address(flop)) != 0 );
assertTrue( vat.can(address(alice), address(goldFlip)) != 0 );
assertTrue( vat.can(address(alice), address(end)) != 0 );
assertTrue( vat.gem("gold", address(end)) == 0 );
assertTrue( vat.gem("gold", address(alice)) == 14000000000000000000 );
assertTrue( vat.gem("gold", address(goldFlip)) == 0 );
assertTrue( vat.gem("gold", address(bobby)) == 10000000000000000000 );
}
}
dapp test
(pending #191 being merged): #192.Slow week (updates to KEVM needed to be pushed through downstream projects).
constructor
to each contract and have the DEPLOY_PRELUDE
call each constructor as a transaction. Then when generating solidity code we can just ignore any calls to constructor
. Anything hardcoded in the DEPLOY_PRELUDE
which is covered by these constructors can be removed.transact Vow Vat . hope Flap
, which is wishing the Flap
for the Vow
. Removing it only causes one exception in the test-suite, but I couldn't find any indication that this is called in the deploy process?module MY-MODULE
imports oenuthe
....
endmodule
module VERIFICATION
imports MY-MODULE
endmodule
module MY-SPEC
imports VERIFICATION
endmodule
Something to target model at: Once there is more info on new liquidations, maybe we can target test generation with them. Likely a month or so out.
Otherwise focus on CI specs (ordered roughly by priority):
string
instead of bytes32
type). New Solidity versions won't automatically cast bytes32 => string
type. Using bytes32
everywhere for formal verification (because dynamic length string is problematic). Maybe we could try adding length constraints to string
everywhere? ERC20 standard requires the symbol/name
to be string
, so other tokens use that.kompile
ahead of time of kprove
).Let's pick out one such proof to start with:
Discuss trying Firefly on MKR contracts. Requires setting up a Truffle testing harness. May be interesting, because we can generate tests for uncovered code paths, but I doubt they will be very interesting tests since they only do depth 1 transactions, and the ones generated by the mkr-mcd-spec are out to any depth (so they actually can exercise code-paths). But we could setup the Truffle testing harness, and see if the generated test for mkr-mcd-spec increases code coverage, and if it does, add that as a unit test to the actual mkr repo. Definitely some interest, RV will attempt to setup Firefly on dss repo and report the results.
Let's link our chats. Bogdan would like to join in and linking them will just be easier for us to get more people on our team involved.
First PR merged with vat-move-diff spec: https://github.com/kframework/evm-semantics/pull/892/files.
STORAGE => STORAGE [ K1 <- V1' ] [ K2 <- V2' ] requires #lookup(STORAGE, K1) ==Int V1 andBool #lookup(STORAGE, K2) ==Int V2
Second PR merged with cat-exhaustive spec: https://github.com/kframework/evm-semantics/pull/896
EVMC_REVERT_NETWORK
, needed to be EVMC_REVERT
(have modified my KLab for this).#asWord(#take(4, #take(32, VCallData)))
to #asWord(VCallData [ 0 .. 4 ])
, because the newer KEVM has most lemmas/reasoning directly over _[_.._]
.Third PR merged with dstoken-approve-fail-rough
and cat-file-addr-pass-rough
: https://github.com/kframework/evm-semantics/pull/897
#rangeBool
, pow208
, #WordPack*
, #string2Word
, and notAddrMask
.Fourth PR is ready, with proofs dai-adduu-fail-rough
and vat-deny-diff-fail-rough
.
dai
proof from 99s => 48s, and vat
proof from 27.2m => 3.2m
. This did translate to a performance improvement across the entire k-dss as well.Running some of the proofs, there is a marked improvement in performance with newer Z3 versions. I was accidentally running version 4.4.1, and running 4.8.6 resulted in many proofs which were infinitely parsing to parse much quicker.
I've setup my local k-dss to use a KEVM submodule directly (but still a globally installed KLab), and to re-use the lemmas there directly, without adding any. We should also make it use a submodule KLab, because the results I have are only valid for my version of KLab (since I've changed some of the term generation process). Currently, on KEVM master
, in 7 hours, I have 77% of proofs passing (all within 10minute timeout), 3% timing out (longer than 10 minutes), and the remaining 20% are unknown. On my working branch for KEVM, the performance is further improved, and I have another 7% of the proofs passing within the 10 minute timeout. Performance is vastly improved over original k-dss as far as I can tell, on some proofs as much as 5X faster, only a handful are slower (up to 2X slower in some cases).
As far as I can tell, the end-cage-rough
spec does not appear in the staging
branch of k-dss, so not sure where it came from, was it added on another branch?
Steps to go from
make spec
make proofs
# klab get-gas SPEC_NAME/HASH (retrieve gas expressions from rough specs)
# klab solve-gas SPEC_NAME/HASH (build gas expressions, this step may not be needed or used actually)
# klab build (sees that there are accepted rough specs with gas expressions, builds the pass proof with exact gas expressions)
# klab prove PASS_SPEC
# klab build (sees that there are accepted pass specs for _lemmas_ of big proofs, so generate spec for big proofs)
# klab prove BIG_SPEC
#asByteStackInWidth
abstraction (and nthbyteof
stubs).-Xss=512m
).hash2
inequalities as lemmas in verification.k
(which were a little broader than needed), we explicitly generate the key inequalities as side-conditions on the generated specifications. I've already modified KLab to do this.chop
could not be simplified.dapp test
works (RPC?), and (ii) how dapp build
works (with paths like ds-auth/auth.sol
). We figured this out and were able to get the tests to build with Firefly, now working on actually running the tests with Fireflyvat-addui-fail-rough
pass on k-dss repo because the --boundary-cells
option on K semantics is breaking it (and KLab uses --boundary-cells k,pr
, but also --boundary-cells k,callDepth
is not working).REACHPROVED
step in the statelog when doing the rough spec (for collecting gas) makes it 30% faster on the rough specs.klab build SPEC_NAME
would make the whole process much better. Currently we have to recall make spec
a bunch of times in the process, which is (i) slow, and (ii) prone to race conditions. If we run only one proof at a time, it's no problem, but running in parallel is what we want to achieve. We should also have klab build-makefile
, which builds the entire dependency graph of proofs so that it's easy to run them with a Makefile.klab make
command, for autogenerating a Makefile with proof depenedencies made explicit. With this approach, out of 1011 proofs, we can generated 864 of them, and are passing 813 of them (not including yesterday and todays updates). This process takes about 10 hours running 8 at a time._pass
proofs, and then the next stage of _rough
proofs which depend on things like vat_mului...
). The next stage of _rough
proofs have about a 90% pass rate, but some of them are very slow. I need to check that the lemmas are being used, because I'm not sure. In one case the lemmas were being used, in another they weren't.mcd-proofs
branch). This runs in 6hr10min (8 at a time).klab make
: https://github.com/makerdao/klab/pull/6Cmem
or Csstore
, and then having a more intelligent algorithm for building the gas specs. This seems to improve the performance of the pass_rough
specs by about 22% (with state-logging still turned on).
Unfortunately we didn't take meeting notes from the beginning, but hopefully this helps the project owners on the MKR side report progress.