Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: medusa tests #51

Draft
wants to merge 29 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5d5fd14
chore: properties md update
simon-something Oct 29, 2024
3b77715
test(medusa): handlers and working setup
simon-something Nov 10, 2024
1b53763
test(medusa): add lib to crytic compile
simon-something Nov 10, 2024
98de161
test(medusa): prop 0 sanity check ok
simon-something Nov 10, 2024
92a50e3
test(medusa): git ignore corpus
simon-something Nov 10, 2024
1e78bdb
test(medusa): git ignore corpus
simon-something Nov 10, 2024
efc8876
test(medusa): typo medusa json
simon-something Nov 10, 2024
e4cf1e5
test(medusa): rm corpus
simon-something Nov 10, 2024
c0ffee6
test(medusa): natspec
simon-something Nov 11, 2024
c0ffee7
test(medusa): rm non-sensical handlers onlyoracle etc
simon-something Nov 11, 2024
c0ffeed
test(medusa): ghosts refactor
simon-something Nov 13, 2024
c0ffee6
test(medusa): more handler fixes
simon-something Nov 13, 2024
c0ffeee
test(medusa): properties md update
simon-something Nov 20, 2024
9c8dce2
test(medusa): requester properties (#57)
0xJabberwock Nov 28, 2024
c0ffee9
test(medusa): dispute window in prop6
simon-something Nov 28, 2024
c0ffeef
test(medusa): fix approveModule
simon-something Nov 28, 2024
c0ffeeb
test(medusa): fix approveModule
simon-something Nov 28, 2024
97fff3c
test(medusa): rename PropertyDispute to PropertyDisputer
0xJabberwock Nov 29, 2024
80d145f
test(medusa): correct prop-6
0xJabberwock Nov 29, 2024
1d45342
test(medusa): assert prop-7
0xJabberwock Nov 29, 2024
c0ffee6
test(medusa): properties 13
simon-something Nov 30, 2024
c0ffee9
test(medusa): fix prop1 for empty finalized req
simon-something Dec 7, 2024
c0ffee7
test(medusa): fix fp
simon-something Dec 11, 2024
7218056
test(medusa): proposer properties
0xJabberwock Dec 13, 2024
2b8bc63
test(medusa): fix prop8b
simon-something Dec 11, 2024
c0ffee2
test(medusa): false pos fix
simon-something Dec 16, 2024
c0ffeea
test(medusa): false pos fix
simon-something Dec 16, 2024
a3b8f1c
Merge branch 'dev' into test/handler-cov
simon-something Dec 18, 2024
c0ffee8
Revert "Merge branch 'dev' into test/handler-cov"
simon-something Dec 18, 2024
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
7 changes: 3 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ out-via-ir
# Keep the latest deployment only
broadcast/*/*/*

# Out dir
# Medusa files
out
crytic-export

# Echidna corpus
test/invariants/fuzz/echidna_coverage
test/invariants/corpus
test/invariants/fuzz/corpus
2 changes: 1 addition & 1 deletion .solhint.tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"var-name-mixedcase": "off",
"const-name-snakecase": "off",
"no-inline-assembly": "off",
"no-empty-blocks": "error",
"no-empty-blocks": "off",
"definition-name-capwords": "off",
"named-parameters-function": "off",
"no-global-import": "off",
Expand Down
87 changes: 87 additions & 0 deletions medusa.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"fuzzing": {
"workers": 10,
"workerResetLimit": 50,
"timeout": 0,
"testLimit": 0,
"shrinkLimit": 100000,
"callSequenceLength": 100,
"corpusDirectory": "test/invariants/corpus",
"coverageEnabled": true,
"targetContracts": ["FuzzTest"],
"predeployedContracts": { "ValidatorLib": "0xc0ffee" },
"targetContractsBalances": [],
"constructorArgs": {},
"deployerAddress": "0x30000",
"senderAddresses": [
"0x10000",
"0x20000",
"0x30000",
"0x40000",
"0x50000",
"0x60000",
"0x70000",
"0x80000",
"0x90000",
"0xa0000"
],
"blockNumberDelayMax": 60480,
"blockTimestampDelayMax": 604800,
"blockGasLimit": 125000000,
"transactionGasLimit": 12500000,
"testing": {
"stopOnFailedTest": true,
"stopOnFailedContractMatching": false,
"stopOnNoTests": true,
"testAllContracts": false,
"traceAll": false,
"assertionTesting": {
"enabled": true,
"testViewMethods": true,
"panicCodeConfig": {
"failOnCompilerInsertedPanic": false,
"failOnAssertion": true,
"failOnArithmeticUnderflow": false,
"failOnDivideByZero": false,
"failOnEnumTypeConversionOutOfBounds": false,
"failOnIncorrectStorageAccess": false,
"failOnPopEmptyArray": false,
"failOnOutOfBoundsArrayAccess": false,
"failOnAllocateTooMuchMemory": false,
"failOnCallUninitializedVariable": false
}
},
"propertyTesting": {
"enabled": true,
"testPrefixes": ["property_"]
},
"optimizationTesting": {
"enabled": true,
"testPrefixes": ["optimize_"]
},
"targetFunctionSignatures": [],
"excludeFunctionSignatures": [""]
},
"chainConfig": {
"codeSizeCheckDisabled": true,
"cheatCodes": {
"cheatCodesEnabled": true,
"enableFFI": false
}
}
},
"compilation": {
"platform": "crytic-compile",
"platformConfig": {
"target": "test/invariants/FuzzTest.t.sol",
simon-something marked this conversation as resolved.
Show resolved Hide resolved
"solcVersion": "",
"exportDirectory": "",
"args": ["--compile-libraries=(ValidatorLib,0xc0ffee)"]
}
},
"logging": {
"level": "info",
"logDirectory": "",
"noColor": false
}
}
9 changes: 9 additions & 0 deletions test/invariants/FuzzTest.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {PropertyParent} from './properties/PropertyParent.t.sol';

contract FuzzTest is PropertyParent {
//solhint-disable no-empty-blocks
function test_debug() public {}
}
165 changes: 161 additions & 4 deletions test/invariants/PROPERTIES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,161 @@
| Properties | Type |
|---------------------------------------------------|------------|
| Greeting should never be empty | Valid state |
| Only the owner can set the greeting | State transition |
# Properties

## Principles
Precondition for proposing/disputing: stake(token) and provision on Horizon staking contract

Prophet modules in use (some modified from the example repo):
- request: eboRequestCreator -> eboRequestModule
- response: bondedResponseModule
- dispute: bondedDisputeEscalationModule (claimEscalationReward tries to slash, if revert oog (too many users), then has new fn `slash()` is called)
- resolution: arbitratorModule + ArbitratorContract (receive resolution, then calls resolveDispute and tries to finalize)
- finality: eboFinalityModule (emit event and check if request created via eboRequestCreator)
- AccessControl: every external function is gated, for Horizon operators (ie `caller` is either msg.sender or msg.sender is authorized as
operator for `caller`)

## Properties & Invariants

| Id | Properties | Type | Tested |
| --- | ------------------------------------------------------------------------------------------------------------------------------------- | ---- | ------ |
| 1 | requester can always create a request | | [ ] |
| 2 | there can only be one active request per chainId/epoch at a time | | [ ] |
| 3 | a proposer can always propose an answer before the deadline, if no response has been submitted | | [ ] |
| 4 | a proposer can always propose an answer before the deadline, if previous response is disputted and has staked | | [ ] |
| 5 | a proposer or a disputer can escalate max MAX_ESCALATION times, each time creating a new tying buffer | | [ ] |
| 6 | a disputer can always dispute a response before the finalisation, if no previous dispute has been made | | [ ] |
| 7 | a disputer can only escalate the first disputed response | | [ ] |
| 8 | a pledger can only pledge for the correct side for an active dispure or resolution, during the tying buffer or before the deadline | | [ ] |
| 9 | an arbitrator can always settle a dispute if it has not been finalised yet | | [ ] |
| 10 | an answer can only be finalized after the deadline | | [ ] |
| 11 | bonded token can never be used on behalf of someone else, unless allowed by the Horizon staking contract | | [ ] |
| 12 | each bonded amount can only be tied to one requestId | | [ ] |
| 13 | each disputeId and responseId can only be tied to one requestId | | [ ] |

## Handler coverage

EBORequestCreator
| Function | Handler |
| ---------------------------------------------------------------------- | ------- |
| createRequest(uint256,string) | [] |
| addChain(string) | [] |
| removeChain(string) | [] |
| setRequestModuleData(address,IEBORequestModule.RequestParameters) | [] |
| setResponseModuleData(address,IBondedResponseModule.RequestParameters) | [] |
| setDisputeModuleData(address,IBondEscalationModule.RequestParameters) | [] |
| setResolutionModuleData(address,IArbitratorModule.RequestParameters) | [] |
| setFinalityModuleData(address) | [] |
| setEpochManager(IEpochManager) | [] |

EBORequestModule
| Function | Handler |
| ------------------------------------------- | ------- |
| createRequest(bytes32,bytes,address) | onlyOracle |
| addEBORequestCreator(IEBORequestCreator) | [] |
| removeEBORequestCreator(IEBORequestCreator) | [] |

BondedResponseModule
| Function | Handler |
| ----------------------------------------------------------- | ------- |
| propose(IOracle.Request,IOracle.Response,address) | onlyOracle |
| finalizeRequest(IOracle.Request,IOracle.Response,address) | onlyOracle |
| releaseUnutilizedResponse(IOracle.Request,IOracle.Response) | [] |

BondEscalationModule
| Function | Handler |
| ------------------------------------------------------------------------------- | ------- |
| disputeResponse(IOracle.Request,IOracle.Response,IOracle.Dispute) | onlyOracle |
| onDisputeStatusChange(bytes32,IOracle.Request,IOracle.Response,IOracle.Dispute) | onlyOracle |
| pledgeForDispute(IOracle.Request, IOracle.Dispute) | [] |
| pledgeAgainstDispute(IOracle.Request, IOracle.Dispute) | [] |
| settleBondEscalation(IOracle.Request,IOracle.Response,IOracle.Dispute) | [] |

CouncilArbitrator
| Function | Handler |
| --------------------------------------------------------- | ------- |
| resolve(IOracle.Request,IOracle.Response,IOracle.Dispute) | onlyArbitratorModule |
| arbitrateDispute(bytes32,IOracle.DisputeStatus) | [] |

EBOFinalityModule
| Function | Handler |
| --------------------------------------------------------- | ------- |
| finalizeRequest(IOracle.Request,IOracle.Response,address) | onlyOracle |
| amendEpoch(uint256,string[],uint256[]) | [] |
| addEBORequestCreator(IEBORequestCreator) | [] |
| removeEBORequestCreator(IEBORequestCreator) | [] |

HorizonAccountingExtension
| Function | Handler |
| ------------------------------------------------------------------------------ | ------- |
| approveModule(address) | [] |
| revokeModule(address) | [] |
| pledge(address,IOracle.Request,IOracle.Dispute,IERC20,uint256) | [] |
| onSettleBondEscalation(IOracle.Request,IOracle.Dispute,IERC20,uint256,uint256) | [] |
| claimEscalationReward(bytes32,address) | [] |
| pay(bytes32,address,address,IERC20,uint256) | onlyAllowedModule |
| bond(address,bytes32,IERC20,uint256) | onlyAllowedModule |
| bond(address,bytes32,IERC20,uint256,address) | onlyAllowedModule |
| release(address,bytes32,IERC20,uint256) | onlyAllowedModule |
| slash(bytes32,uint256,uint256) | [] |
| setMaxUsersToCheck(uint128) | [] |

Arbitrable
| Function | Handler |
| --------------------------- | ------- |
| setArbitrator(address) | [] |
| setPendingCouncil(address) | [] |
| confirmCouncil() | [] |

Oracle
| Function | Handler |
| -------------------------------------------------------------------- | ------- |
| createRequest(Request,bytes32) external returns (bytes32) | [] |
| createRequests(Request[],bytes32[]) external returns (bytes32[]) | [] |
| listRequestIds(uint256,uint256) external view returns (bytes32[]) | [] |
| proposeResponse(Request,Response) external returns (bytes32) | [] |
| disputeResponse(Request,Response,Dispute) external returns (bytes32) | [] |
| escalateDispute(Request,Response,Dispute) external | [] |
| resolveDispute(Request,Response,Dispute) external | [] |
| finalize(Request,Response) external | [] |




- Requester
- Can always create a request
- only one chainId/epoch can be requested at a time (a tuple can have second request if finalized without answer)

- Proposer
- Can always send answer before the deadline if enough token to bound in Horizon staking contract AND if any previous response is disputed OR no response at all
- Can escalate MAX ESCALATION times
- Every escalation creates a new tying buffer for further escalation (even if past deadline)

- Disputer
- Can always dispute if before finalisation/during dispute window, if enough token to bound in Horizon staking and not previously disputed
- only first disputed response is escalated (others go to resolution)
- Can escalate MAX ESCALATION times
- every escalation creates a new tying buffer for further escalation (even if past deadline)

- Pledgers:
- can pledge on any active dispute or resolution, during tying buffer/before deadline, if it’s that side’s turn
- Can only pledge one pledge at a time (you can only surpass other team by one pledge at a time), first to tie then to out-pledge (always 2 ties by side)

- Protocol
- finalise only after deadline
- no possible way for a given actor to use another one’s bonded token (no bonding or pledging/claiming on behalf of someone else if not allowed in the Horison staking contract)
- bonded amount only accessible by one requestId
- disputeId and responseId can only be tied to a given requestId
- arbitrator: can always settled a dispute if not finalised (can be a no resolution)


- disputer

wins → his money + proposer bonded amt
loose loose all
no resolution his money (when no pledging or max escalation on both side or other resolution module logic if only dispute module)

- pledger
wins → their money + enemy
no resolution -> their money

**winning determined by *pledgers* (b, c)**

bonded dispute goes to resolution if: escalateDispute or tie
Loading
Loading