Skip to content

Commit

Permalink
Merge pull request #47 from freespek/th/instrument-only-monitor-vars
Browse files Browse the repository at this point in the history
Instrument only monitor variables
  • Loading branch information
thpani authored May 6, 2024
2 parents c64a12b + 9b9518f commit b0502fa
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 6 deletions.
26 changes: 25 additions & 1 deletion solarkraft/src/instrument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ type Transaction = {
error: string
}

// Return true iff `o` is a Javascript object.
function isObject(o: any) {
return typeof o === 'object' && !Array.isArray(o) && o !== null
}

// Decode an ITF value `value` into a Javascript value.
// TODO(#46): support composite types (sequence, tuple, record, set, map)
function decodeITFValue(value: any) {
if (
isObject(value) &&
Object.prototype.hasOwnProperty.call(value, '#bigint')
) {
return parseInt(value['#bigint'])
}
return value
}

/**
* Return a `State` from an ITF JSON object.
* @param itf ITF JSON object, see https://apalache.informal.systems/docs/adr/015adr-trace.html
Expand All @@ -27,7 +44,7 @@ export function stateFromItf(itf: any): State {
.filter(([name]) => name != '#meta')
.map(([name, value]) => ({
name: name,
value: value,
value: decodeITFValue(value),
type: 'Tla' + varTypes[name],
}))
return state
Expand All @@ -45,6 +62,13 @@ export function instrumentMonitor(
state: State,
tx: Transaction
): any {
// Only instrument state variables that are delcared in the monitor spec
// (otherwise we provoke type errors in Apalache Snowcat, via undeclared variables)
const declaredMonitorVariables = monitor.modules[0].declarations
.filter(({ kind }) => kind == 'TlaVarDecl')
.map(({ name }) => name)
state = state.filter(({ name }) => declaredMonitorVariables.includes(name))

// Add a special variable `last_error` that tracks error messages of failed transactions
state.push({ name: 'last_error', type: 'TlaStr', value: '' })

Expand Down
2 changes: 1 addition & 1 deletion solarkraft/src/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function verify(args: any) {

if (apalacheParse.status != 0) {
console.error(`Parsing monitor file ${args.monitor} failed:`)
console.error(apalacheParse.stderr)
console.error(apalacheParse.stderr.toString())
return
}

Expand Down
24 changes: 24 additions & 0 deletions solarkraft/test/e2e/tla/timelock_mon2.tla
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(*
* This specification ensures that a token is properly
* deposited and claimed.
*)
---- MODULE timelock_mon2 ----
VARIABLES
\* @type: Int;
balance,
\* @type: Str;
last_error

Deposit(env, from, token, amount, claimants, time_bound) ==
\/ /\ balance' = amount
/\ last_error' = ""
\/ /\ UNCHANGED balance
/\ last_error' = "contract is not initialized"

Claim(env, claimant) ==
\/ /\ UNCHANGED balance
/\ last_error' \in { "", "contract is not initialized" }
\/ /\ balance' = 0
/\ last_error' = ""

=============================
25 changes: 25 additions & 0 deletions solarkraft/test/e2e/tla/timelock_state.itf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{ "#meta": {
"format": "ITF",
"varTypes": {
"balance": "Int",
"is_initialized": "Bool",
"last_error": "Str"
},
"format-description": "https://apalache.informal.systems/docs/adr/015adr-trace.html",
"description": "Created by Apalache on Mon May 06 08:21:52 UTC 2024"
},
"vars": [
"is_initialized",
"last_error"
],
"states": [
{
"#meta": {
"index": 0
},
"balance": { "#bigint": "123" },
"is_initialized": false,
"last_error": ""
}
]
}
13 changes: 11 additions & 2 deletions solarkraft/test/e2e/verify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,19 @@ describe('verify', () => {
.run(done)
})

it('reports success on okay monitor', function (done) {
it('reports success on okay monitor1', function (done) {
this.timeout(50000)
spawn(
'solarkraft verify --txHash mimimi --monitor test/e2e/tla/timelock_mon1_instrumented_okay.tla --state test/e2e/tla/timelock_state.itf.json'
'solarkraft verify --txHash mimimi --monitor test/e2e/tla/timelock_mon1.tla --state test/e2e/tla/timelock_state.itf.json'
)
.wait('[OK]')
.run(done)
})

it('reports success on okay monitor2', function (done) {
this.timeout(50000)
spawn(
'solarkraft verify --txHash mimimi --monitor test/e2e/tla/timelock_mon2.tla --state test/e2e/tla/timelock_state.itf.json'
)
.wait('[OK]')
.run(done)
Expand Down
37 changes: 35 additions & 2 deletions solarkraft/test/unit/instrument.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,42 @@ import { instrumentedMonitor as expected } from './verify.instrumentedMonitor.js

describe('Apalache JSON instrumentor', () => {
it('instruments TLA+ monitors', () => {
const monitor = { modules: [{ declarations: [] }] }
const monitor = {
modules: [
{
declarations: [
{ kind: 'TlaVarDecl', name: 'is_initialized' },
],
},
],
}
const state = [
{ name: 'is_initialized', type: 'TlaBool', value: false },
]
const tx = {
functionName: 'Claim',
functionArgs: [{ type: 'TlaStr', value: 'alice' }],
env: { timestamp: 100 },
error: 'contract is not initialized',
}

const instrumented = instrumentMonitor(monitor, state, tx)
assert.deepEqual(expected, instrumented)
})

it('only instruments variables declared in the monitor', () => {
const monitor = {
modules: [
{
declarations: [
{ kind: 'TlaVarDecl', name: 'is_initialized' },
],
},
],
}
const state = [
{ name: 'is_initialized', type: 'TlaBool', value: false },
{ name: 'additional_variable', type: 'TlaBool', value: false },
]
const tx = {
functionName: 'Claim',
Expand All @@ -21,6 +54,6 @@ describe('Apalache JSON instrumentor', () => {
}

const instrumented = instrumentMonitor(monitor, state, tx)
assert.deepEqual(instrumented, expected)
assert.deepEqual(expected, instrumented)
})
})
4 changes: 4 additions & 0 deletions solarkraft/test/unit/verify.instrumentedMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ const instrumentedMonitor = {
modules: [
{
declarations: [
{
kind: 'TlaVarDecl',
name: 'is_initialized',
},
{
kind: 'TlaOperDecl',
name: 'Init',
Expand Down

0 comments on commit b0502fa

Please sign in to comment.