Skip to content
This repository has been archived by the owner on Jun 30, 2022. It is now read-only.

Commit

Permalink
feat(disputes): DRY out fetch open disputes for session and add deadl…
Browse files Browse the repository at this point in the history
…ine event handler
  • Loading branch information
satello committed Mar 5, 2018
1 parent 39e9b2c commit c66548a
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 81 deletions.
212 changes: 135 additions & 77 deletions src/abstractWrappers/Disputes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import _ from 'lodash'
import * as ethConstants from '../constants/eth'
import * as arbitratorConstants from '../constants/arbitrator'
import * as notificationConstants from '../constants/notification'
import * as errorConstants from '../constants/error'

import AbstractWrapper from './AbstractWrapper'

Expand Down Expand Up @@ -125,39 +126,16 @@ class Disputes extends AbstractWrapper {
if (newPeriod === arbitratorConstants.PERIOD.APPEAL) {
this._checkArbitratorWrappersSet()
const userProfile = await this._StoreProvider.getUserProfile(address)
// contract data
const arbitratorData = await this._Arbitrator.getData(
contractAddress,
address
const openDisputes = await this._getOpenDisputesForSession(
arbitratorAddress
)
let disputeId = 0
const currentSession = arbitratorData.session

let dispute
while (1) {
// iterate over all disputes (FIXME inefficient)
try {
try {
dispute = await this._Arbitrator.getDispute(
contractAddress,
disputeId
)
// eslint-disable-next-line no-unused-vars
} catch (err) {
// FIXME standardize
throw new Error('DisputeOutOfRange')
}

if (dispute.arbitratedContract === ethConstants.NULL_ADDRESS) break
// session + number of appeals
const disputeSession =
dispute.firstSession + dispute.numberOfAppeals
// if dispute not in current session skip
if (disputeSession !== currentSession) {
disputeId++
continue
}

await Promise.all(
openDisputes.map(async disputeId => {
const dispute = await this._Arbitrator.getDispute(
arbitratorAddress,
disputeId
)
const ruling = await this._Arbitrator.currentRulingForDispute(
contractAddress,
disputeId,
Expand Down Expand Up @@ -200,13 +178,8 @@ class Disputes extends AbstractWrapper {
notificationCallback(notification[0])
}
}
// check next dispute
disputeId += 1
} catch (err) {
if (err === 'DisputeOutOfRange') break
throw err
}
}
})
)
}
}

Expand All @@ -216,6 +189,64 @@ class Disputes extends AbstractWrapper {
)
}

/**
* Event listener that sets the deadline for an appeal
* @param {string} arbitratorAddress - The arbitrator contract's address.
* @param {string} account - The users eth account.
* @param {function} callback - <optional> function to be called when event is triggered.
*/
addDisputeDeadlineHandler = async (arbitratorAddress, account) => {
if (!this._eventListener) return

const _disputeDeadlineHandler = async (
event,
contractAddress = arbitratorAddress,
address = account
) => {
const newPeriod = event.args._period.toNumber()
// send appeal possible notifications
if (newPeriod === arbitratorConstants.PERIOD.VOTE) {
this._checkArbitratorWrappersSet()
const userProfile = await this._StoreProvider.getUserProfile(address)
// contract data
const openDisputes = await this._getOpenDisputesForSession(
arbitratorAddress
)

await Promise.all(
openDisputes.map(async disputeId => {
if (
_.findIndex(
userProfile.disputes,
dispute =>
dispute.disputeId === disputeId &&
dispute.arbitratorAddress === contractAddress
) >= 0
) {
const deadline = await this.getDeadlineForOpenDispute(
arbitratorAddress
)
// add ruledAt to store
await this._updateStoreForDispute(
contractAddress,
disputeId,
address,
null,
null,
deadline
)
}
})
)
}
}

await this._eventListener.registerArbitratorEvent(
'NewPeriod',
_disputeDeadlineHandler
)
}

// **************************** //
// * Public * //
// **************************** //
Expand Down Expand Up @@ -351,36 +382,13 @@ class Disputes extends AbstractWrapper {
// FIXME don't like having to call this every fnc
this._checkArbitratorWrappersSet()
// contract data
const arbitratorData = await this._Arbitrator.getData(
arbitratorAddress,
account
const openDisputes = await this._getOpenDisputesForSession(
arbitratorAddress
)
const myDisputes = []
let disputeId = 0
const currentSession = arbitratorData.session

let dispute
while (1) {
// iterate over all disputes (FIXME inefficient)
// IDEA iterate over DisputeCreated events between last session and this session
try {
dispute = await this._Arbitrator.getDispute(
arbitratorAddress,
disputeId
)
if (dispute.arbitratedContract === ethConstants.NULL_ADDRESS) break
// session + number of appeals
const disputeSession = dispute.firstSession + dispute.numberOfAppeals
// if dispute not in current session skip
if (disputeSession !== currentSession) {
disputeId++
dispute = await this._Arbitrator.getDispute(
arbitratorAddress,
disputeId
)
continue
}

await Promise.all(
openDisputes.map(async disputeId => {
const draws = await this.getDrawsForJuror(
arbitratorAddress,
disputeId,
Expand All @@ -389,13 +397,8 @@ class Disputes extends AbstractWrapper {
if (draws.length > 0) {
myDisputes.push(disputeId)
}
// check next dispute
disputeId += 1
// eslint-disable-next-line no-unused-vars
} catch (err) {
break
}
}
})
)

return myDisputes
}
Expand Down Expand Up @@ -464,7 +467,7 @@ class Disputes extends AbstractWrapper {
* @param {number} [period=PERIODS.VOTE] - The period to get the deadline for.
* @returns {number} - epoch timestamp
*/
getDeadlineForDispute = async (
getDeadlineForOpenDispute = async (
arbitratorAddress,
period = arbitratorConstants.PERIOD.VOTE
) => {
Expand All @@ -487,14 +490,16 @@ class Disputes extends AbstractWrapper {
* @param {string} account address of party to update dispute or
* @param {number} createdAt <optional> epoch timestamp of when dispute was created
* @param {number} ruledAt <optional> epoch timestamp of when dispute was ruled on
* @param {number} deadline <optional> epoch timestamp of dispute deadline
* @returns {object} updated dispute object
*/
_updateStoreForDispute = async (
arbitratorAddress,
disputeId,
account,
createdAt,
ruledAt
ruledAt,
deadline
) => {
const disputeData = await this.getDataForDispute(
arbitratorAddress,
Expand All @@ -506,6 +511,8 @@ class Disputes extends AbstractWrapper {
disputeData.appealCreatedAt[disputeData.numberOfAppeals] = createdAt
if (ruledAt)
disputeData.appealRuledAt[disputeData.numberOfAppeals] = ruledAt
if (deadline)
disputeData.appealDeadlines[disputeData.numberOfAppeals] = deadline

// update dispute
const dispute = await this._StoreProvider.updateDispute(
Expand All @@ -520,7 +527,8 @@ class Disputes extends AbstractWrapper {
disputeData.justification,
disputeData.resolutionOptions,
disputeData.appealCreatedAt,
disputeData.appealRuledAt
disputeData.appealRuledAt,
disputeData.appealDeadlines
)

const storedDisputeData = await this._StoreProvider.getDisputeData(
Expand Down Expand Up @@ -674,6 +682,7 @@ class Disputes extends AbstractWrapper {
let netPNK = 0
let appealCreatedAt = []
let appealRuledAt = []
let appealDeadlines = []
if (account) {
try {
const userData = await this._StoreProvider.getDisputeData(
Expand All @@ -685,6 +694,7 @@ class Disputes extends AbstractWrapper {
netPNK = userData.netPNK || 0
appealCreatedAt = userData.appealCreatedAt || []
appealRuledAt = userData.appealRuledAt || []
appealDeadlines = userData.appealDeadlines || []
// eslint-disable-next-line no-unused-vars
} catch (err) {
// fetching dispute will fail if it hasn't been added to the store yet. this is ok we can just not return store data
Expand Down Expand Up @@ -713,7 +723,7 @@ class Disputes extends AbstractWrapper {
ruling,
voteCounter: dispute.voteCounters[appeal],
ruledAt: appealRuledAt[appeal],
deadline: await this.getDeadlineForDispute(arbitratorAddress, appeal)
deadline: appealDeadlines[appeal]
}

const baseFee = dispute.arbitrationFeePerJuror
Expand Down Expand Up @@ -760,9 +770,57 @@ class Disputes extends AbstractWrapper {
evidence,
netPNK,
appealCreatedAt,
appealRuledAt
appealRuledAt,
appealDeadlines
}
}

/** Listener to set dispute deadline when period passes to Vote
* @param {string} arbitratorAddress - address of arbitrator contract
* @returns {int[]} - array of active disputeId
*/
_getOpenDisputesForSession = async arbitratorAddress => {
const openDisputes = []
// contract data
const arbitratorData = await this._Arbitrator.getData(arbitratorAddress)
let disputeId = 0
const currentSession = arbitratorData.session

let dispute
while (1) {
// iterate over all disputes (FIXME inefficient)
try {
try {
dispute = await this._Arbitrator.getDispute(
arbitratorAddress,
disputeId
)
// eslint-disable-next-line no-unused-vars
} catch (err) {
// FIXME standardize
throw new Error(errorConstants.TYPE.DISPUTE_OUT_OF_RANGE)
}

if (dispute.arbitratedContract === ethConstants.NULL_ADDRESS) break
// session + number of appeals
const disputeSession = dispute.firstSession + dispute.numberOfAppeals
// if dispute not in current session skip
if (disputeSession !== currentSession) {
disputeId++
continue
}

openDisputes.push(disputeId)
// check next dispute
disputeId += 1
} catch (err) {
if (err.message === errorConstants.TYPE.DISPUTE_OUT_OF_RANGE) break
throw err
}
}

return openDisputes
}
}

export default Disputes
3 changes: 3 additions & 0 deletions src/constants/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const TYPE = {
DISPUTE_OUT_OF_RANGE: 'Dispute out of range'
}
4 changes: 2 additions & 2 deletions src/constants/eth.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const LOCALHOST_ETH_PROVIDER = 'http://localhost:8545'
// export const LOCALHOST_STORE_PROVIDER = 'https://kleros.in'
export const LOCALHOST_STORE_PROVIDER = 'http://localhost:3001'
export const LOCALHOST_STORE_PROVIDER = 'https://kleros.in'
// export const LOCALHOST_STORE_PROVIDER = 'http://localhost:3001'

export const NULL_ADDRESS = '0x'

Expand Down
1 change: 1 addition & 0 deletions src/kleros.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class Kleros {
account,
callback
)
await this.disputes.addDisputeDeadlineHandler(arbitratorAddress, account)
await this.disputes.addDisputeRulingHandler(
arbitratorAddress,
account,
Expand Down
6 changes: 4 additions & 2 deletions src/utils/StoreProviderWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ class StoreProviderWrapper {
justification,
resolutionOptions,
appealCreatedAt,
appealRuledAt
appealRuledAt,
appealDeadlines
) => {
const httpResponse = await this._makeRequest(
'POST',
Expand All @@ -235,7 +236,8 @@ class StoreProviderWrapper {
justification,
resolutionOptions,
appealCreatedAt,
appealRuledAt
appealRuledAt,
appealDeadlines
})
)
return httpResponse
Expand Down
4 changes: 4 additions & 0 deletions tests/kleros.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,10 @@ describe('Kleros', () => {
drawB.push(i)
}
}

// FIXME bandaid until PR #92 is merged
await delaySecond(2)

expect(drawA.length + drawB.length).toEqual(3)
const disputesForJuror1 = await KlerosInstance.disputes.getDisputesForUser(
klerosCourt.address,
Expand Down

0 comments on commit c66548a

Please sign in to comment.