Skip to content
Permalink
Browse files

feat(disputes): DRY out fetch open disputes for session and add deadl…

…ine event handler
  • Loading branch information...
satello committed Mar 5, 2018
1 parent 66541a6 commit 77b21ce7c70543263f8045c2613b943dfa2b2263
Showing with 149 additions and 81 deletions.
  1. +135 −77 src/abstractWrappers/Disputes.js
  2. +3 −0 src/constants/error.js
  3. +2 −2 src/constants/eth.js
  4. +1 −0 src/kleros.js
  5. +4 −2 src/utils/StoreProviderWrapper.js
  6. +4 −0 tests/kleros.test.js
@@ -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'

@@ -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,
@@ -200,13 +178,8 @@ class Disputes extends AbstractWrapper {
notificationCallback(notification[0])
}
}
// check next dispute
disputeId += 1
} catch (err) {
if (err === 'DisputeOutOfRange') break
throw err
}
}
})
)
}
}

@@ -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 * //
// **************************** //
@@ -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,
@@ -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
}
@@ -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
) => {
@@ -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,
@@ -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(
@@ -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(
@@ -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(
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,3 @@
export const TYPE = {
DISPUTE_OUT_OF_RANGE: 'Dispute out of range'
}
@@ -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'

@@ -88,6 +88,7 @@ class Kleros {
account,
callback
)
await this.disputes.addDisputeDeadlineHandler(arbitratorAddress, account)
await this.disputes.addDisputeRulingHandler(
arbitratorAddress,
account,
@@ -216,7 +216,8 @@ class StoreProviderWrapper {
justification,
resolutionOptions,
appealCreatedAt,
appealRuledAt
appealRuledAt,
appealDeadlines
) => {
const httpResponse = await this._makeRequest(
'POST',
@@ -235,7 +236,8 @@ class StoreProviderWrapper {
justification,
resolutionOptions,
appealCreatedAt,
appealRuledAt
appealRuledAt,
appealDeadlines
})
)
return httpResponse
@@ -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,

0 comments on commit 77b21ce

Please sign in to comment.
You can’t perform that action at this time.