Skip to content

Commit a27d26a

Browse files
anvacaruehildenb
authored andcommitted
Web3: Create basic coverage report (#526)
* web3.md: store all the opcodes of a contract * web3.md: implement firefly_getCoverageData and #serializeCoverage * web3.md: fix #serializeCoverage * add test for firefly_getCoverageData * web3.md: implement #serializePrograms * web3.md: compute coverage percentages * web3.md: make #parseByteCode tail recursive * move failing test to tests/web3/failing * add test for firefly_getCoverageData * fix test * web3.md:rename List2JSONList * Remove unused `Float` addition * web3.md: more likely to not round towards zero * web3: formatting * tweaks * web3.md: implement qsort * web3.md: formatting
1 parent 5a67a5b commit a27d26a

File tree

3 files changed

+114
-1
lines changed

3 files changed

+114
-1
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"jsonrpc":"2.0","id":1,"result":true},{"jsonrpc":"2.0","id":2,"result":true},{"jsonrpc":"2.0","id":3,"result":"0x0000000000000000000000000000000000000000000000000000000000ffffff"},{"jsonrpc":"2.0","id":3,"result":{"coverages":[{"93758614234106549757282766802448384239213770766359592192750614820519184033004":{"RUNTIME":100}}],"coveredOpcodes":[{"93758614234106549757282766802448384239213770766359592192750614820519184033004":{"RUNTIME":[0,4,6,7,9,11]}}],"programs":[{"93758614234106549757282766802448384239213770766359592192750614820519184033004":{"RUNTIME":[0,4,6,7,9,11]}}]}}]
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
[
2+
{
3+
"jsonrpc": "2.0",
4+
"id": 1,
5+
"method": "firefly_addAccount",
6+
"params": [
7+
{
8+
"key": "0x5fffe36d0218b8b8d45d4e70788096a5e0c289cf89c907f97d1cdecdccaa8b6b",
9+
"balance": "0x56BC75E2D63100000"
10+
}
11+
]
12+
},
13+
{
14+
"jsonrpc": "2.0",
15+
"id": 2,
16+
"method": "firefly_addAccount",
17+
"params": [
18+
{
19+
"address": "0xdf1db454e4dc226da2b0f8d471976180555355e2",
20+
"code": "0x62FFFFFF60005260206000F3"
21+
}
22+
]
23+
},
24+
{
25+
"jsonrpc": "2.0",
26+
"id": 3,
27+
"method": "eth_call",
28+
"params": [
29+
{
30+
"from": "0xee70809B448816B3D2D40C1DB8B44aACf50BAD3a",
31+
"to": "0xdf1db454e4dc226da2b0f8d471976180555355e2"
32+
},
33+
"latest"
34+
]
35+
},
36+
{
37+
"jsonrpc": "2.0",
38+
"id": 3,
39+
"method": "firefly_getCoverageData",
40+
"params": []
41+
}
42+
]

web3.md

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@ WEB3 JSON RPC
315315
<method> "eth_call" </method>
316316
rule <k> #runRPCCall => #eth_estimateGas ... </k>
317317
<method> "eth_estimateGas" </method>
318+
rule <k> #runRPCCall => #firefly_getCoverageData ... </k>
319+
<method> "firefly_getCoverageData" </method>
318320
319321
rule <k> #runRPCCall => #sendResponse( "error": {"code": -32601, "message": "Method not found"} ) ... </k> [owise]
320322
@@ -1072,6 +1074,10 @@ Collecting Coverage Data
10721074
- `<opcodeLists>` cell is a map similar to `<opcodeCoverage>` which stores instead a list containing all the `OpcodeItem`s of the executed bytecode for each contract.
10731075
- `OpcodeItem` is a tuple which contains the Program Counter and the Opcode name.
10741076

1077+
**TODO**: instead of having both `#serializeCoverage` and `#serializePrograms` we could keep only the first rule as `#serializeCoverageMap` if `<opcodeLists>` would store `Sets` instead of `Lists`.
1078+
**TODO**: compute coverage percentages in `Float` instead of `Int`
1079+
**TODO**: `Set2List` won't return `ListItems` in order, causing tests to fail.
1080+
10751081
```k
10761082
syntax Phase ::= ".Phase"
10771083
| "CONSTRUCTOR"
@@ -1126,5 +1132,69 @@ Collecting Coverage Data
11261132
requires notBool PCOUNT in PCS
11271133
[priority(25)]
11281134
1135+
syntax KItem ::= "#firefly_getCoverageData"
1136+
// -------------------------------------------
1137+
rule <k> #firefly_getCoverageData => #sendResponse ("result": #makeCoverageReport(COVERAGE, PGMS)) ... </k>
1138+
<opcodeCoverage> COVERAGE </opcodeCoverage>
1139+
<opcodeLists> PGMS </opcodeLists>
1140+
1141+
syntax JSON ::= #makeCoverageReport ( Map, Map ) [function]
1142+
// -----------------------------------------------------------
1143+
rule #makeCoverageReport (COVERAGE, PGMS) => {
1144+
"coverages": [#coveragePercentages(keys_list(PGMS),COVERAGE,PGMS)],
1145+
"coveredOpcodes": [#serializeCoverage(keys_list(COVERAGE),COVERAGE)],
1146+
"programs": [#serializePrograms(keys_list(PGMS),PGMS)]
1147+
}
1148+
1149+
syntax JSONList ::= #serializeCoverage ( List, Map ) [function]
1150+
// ---------------------------------------------------------------
1151+
rule #serializeCoverage (.List, _ ) => .JSONList
1152+
rule #serializeCoverage ((ListItem({ CODEHASH | EPHASE } #as KEY) KEYS), KEY |-> X:Set COVERAGE:Map ) => { Int2String(CODEHASH):{ Phase2String(EPHASE): [IntList2JSONList(qsort(Set2List(X)))] }}, #serializeCoverage(KEYS, COVERAGE)
1153+
1154+
syntax JSONList ::= #serializePrograms ( List, Map ) [function]
1155+
// ---------------------------------------------------------------
1156+
rule #serializePrograms (.List, _ ) => .JSONList
1157+
rule #serializePrograms ((ListItem({ CODEHASH | EPHASE } #as KEY) KEYS), KEY |-> X:List PGMS:Map ) => { Int2String(CODEHASH):{ Phase2String(EPHASE): [CoverageIDList2JSONList(X)] }}, #serializePrograms(KEYS, PGMS)
1158+
1159+
syntax String ::= Phase2String ( Phase ) [function]
1160+
// ----------------------------------------------------
1161+
rule Phase2String (CONSTRUCTOR) => "CONSTRUCTOR"
1162+
rule Phase2String (RUNTIME) => "RUNTIME"
1163+
1164+
syntax JSONList ::= CoverageIDList2JSONList ( List ) [function]
1165+
// ---------------------------------------------------------------
1166+
rule CoverageIDList2JSONList (.List) => .JSONList
1167+
rule CoverageIDList2JSONList (ListItem({I:Int | _:OpCode }) L) => I, CoverageIDList2JSONList(L)
1168+
1169+
syntax JSONList ::= IntList2JSONList ( List ) [function]
1170+
// --------------------------------------------------------
1171+
rule IntList2JSONList (.List) => .JSONList
1172+
rule IntList2JSONList (ListItem(I:Int) L) => I, IntList2JSONList(L)
1173+
1174+
syntax List ::= getIntElementsSmallerThan ( Int, List, List ) [function]
1175+
// ------------------------------------------------------------------------
1176+
rule getIntElementsSmallerThan (_, .List, RESULTS) => RESULTS
1177+
rule getIntElementsSmallerThan (X, (ListItem(I:Int) L), RESULTS) => getIntElementsSmallerThan (X, L, ListItem(I) RESULTS) requires I <Int X
1178+
rule getIntElementsSmallerThan (X, (ListItem(I:Int) L), RESULTS) => getIntElementsSmallerThan (X, L, RESULTS) requires I >=Int X
1179+
1180+
syntax List ::= getIntElementsGreaterThan ( Int, List, List ) [function]
1181+
// ------------------------------------------------------------------------
1182+
rule getIntElementsGreaterThan (_, .List , RESULTS) => RESULTS
1183+
rule getIntElementsGreaterThan (X, (ListItem(I:Int) L), RESULTS) => getIntElementsGreaterThan (X, L, ListItem(I) RESULTS) requires I >Int X
1184+
rule getIntElementsGreaterThan (X, (ListItem(I:Int) L), RESULTS) => getIntElementsGreaterThan (X, L, RESULTS) requires I <=Int X
1185+
1186+
syntax List ::= qsort ( List ) [function]
1187+
// -----------------------------------------
1188+
rule qsort ( .List ) => .List
1189+
rule qsort (ListItem(I:Int) L) => qsort(getIntElementsSmallerThan(I, L, .List)) ListItem(I) qsort(getIntElementsGreaterThan(I, L, .List))
1190+
1191+
syntax JSONList ::= #coveragePercentages ( List, Map, Map) [function]
1192+
// ---------------------------------------------------------------------
1193+
rule #coveragePercentages (.List, _, _) => .JSONList
1194+
rule #coveragePercentages ((ListItem({ CODEHASH | EPHASE } #as KEY) KEYS), KEY |-> X:Set COVERAGE:Map, KEY |-> Y:List PGMS:Map) => { Int2String(CODEHASH):{ Phase2String(EPHASE): #computePercentage(size(X),size(Y)) }}, #coveragePercentages(KEYS,COVERAGE,PGMS)
1195+
1196+
syntax Int ::= #computePercentage ( Int, Int ) [function]
1197+
// ---------------------------------------------------------
1198+
rule #computePercentage (EXECUTED, TOTAL) => (100 *Int EXECUTED) /Int TOTAL
11291199
endmodule
1130-
```
1200+
```

0 commit comments

Comments
 (0)