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

Commit

Permalink
feat: fetch minimal data and cache where possible
Browse files Browse the repository at this point in the history
  • Loading branch information
satello committed Aug 13, 2018
1 parent d994aac commit 0d7a1c6
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 26 deletions.
6 changes: 6 additions & 0 deletions src/contracts/implementations/arbitrable/Arbitrable.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ class Arbitrable extends ContractImplementation {
*/
constructor(web3Provider, contractArtifact, contractAddress) {
super(web3Provider, contractArtifact, contractAddress)

this.metaEvidenceCache = {}
}

/**
Expand All @@ -23,6 +25,9 @@ class Arbitrable extends ContractImplementation {
* and make an http request to the resource.
*/
getMetaEvidence = async () => {
if (this.metaEvidenceCache[this.contractAddress])
return this.metaEvidenceCache[this.contractAddress]

const metaEvidenceLog = await EventListener.getEventLogs(
this,
'MetaEvidence',
Expand All @@ -43,6 +48,7 @@ class Arbitrable extends ContractImplementation {
if (metaEvidenceResponse.status >= 400)
throw new Error(`Unable to fetch meta-evidence at ${metaEvidenceUri}`)

this.metaEvidenceCache[this.contractAddress] = metaEvidenceResponse.body || metaEvidenceResponse
return metaEvidenceResponse.body || metaEvidenceResponse
}

Expand Down
60 changes: 40 additions & 20 deletions src/contracts/implementations/arbitrator/Kleros.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ class Kleros extends ContractImplementation {
*/
constructor(web3Provider, contractAddress, artifact = klerosArtifact) {
super(web3Provider, artifact, contractAddress)
this._disputeDeadlineCache = {}
this._appealCreationTimestamp = {}
this._appealRuledAtTimestamp = {}
this._openDisputesCache = {}
}

/**
Expand Down Expand Up @@ -348,7 +352,7 @@ class Kleros extends ContractImplementation {
* @param {number} disputeId - The index of the dispute.
* @returns {object} - The dispute data from the contract.
*/
getDispute = async disputeId => {
getDispute = async (disputeId, withVoteCount = false) => {
await this.loadContract()

try {
Expand All @@ -357,22 +361,21 @@ class Kleros extends ContractImplementation {
const rulingChoices = dispute[3].toNumber()

let voteCounters = []
let status
for (let appeal = 0; appeal <= numberOfAppeals; appeal++) {
const voteCounts = []
for (let choice = 0; choice <= rulingChoices; choice++)
voteCounts.push(
this.contractInstance
.getVoteCount(disputeId, appeal, choice)
.then(v => v.toNumber())
)
voteCounters.push(voteCounts)
}
const status = await this.contractInstance.disputeStatus(disputeId)
if (withVoteCount) {
for (let appeal = 0; appeal <= numberOfAppeals; appeal++) {
const voteCounts = []
for (let choice = 0; choice <= rulingChoices; choice++)
voteCounts.push(
this.contractInstance
.getVoteCount(disputeId, appeal, choice)
.then(v => v.toNumber())
)
voteCounters.push(voteCounts)
}

;[voteCounters, status] = await Promise.all([
Promise.all(voteCounters.map(voteCounts => Promise.all(voteCounts))),
this.contractInstance.disputeStatus(disputeId)
])
voteCounters = await Promise.all(voteCounters.map(voteCounts => Promise.all(voteCounts)))
}

return {
arbitratorAddress: this.contractAddress,
Expand All @@ -385,7 +388,7 @@ class Kleros extends ContractImplementation {
arbitrationFeePerJuror: this._Web3Wrapper.fromWei(dispute[5], 'ether'),
state: dispute[6].toNumber(),
voteCounters,
status: status.toNumber()
status: status ? status.toNumber() : null
}
// eslint-disable-next-line no-unused-vars
} catch (err) {
Expand Down Expand Up @@ -580,6 +583,8 @@ class Kleros extends ContractImplementation {
await this.loadContract()

const currentSession = await this.getSession()
if (this._openDisputesCache[currentSession])
return this._openDisputesCache[currentSession]
const openDisputes = []

let disputeId = 0
Expand All @@ -588,6 +593,7 @@ class Kleros extends ContractImplementation {
// Iterate over all the disputes
// TODO: Implement a more performant solution
try {
// get without voteCounts to speed it up
dispute = await this.getDispute(disputeId)
} catch (err) {
// Dispute out of range, break
Expand All @@ -607,6 +613,7 @@ class Kleros extends ContractImplementation {
disputeId++
}

this._openDisputesCache[currentSession] = openDisputes
return openDisputes
}

Expand Down Expand Up @@ -659,6 +666,8 @@ class Kleros extends ContractImplementation {
* @returns {number[]} an array of timestamps
*/
getAppealRuledAtTimestamp = async session => {
if (this._appealRuledAtTimestamp[session])
return this._appealRuledAtTimestamp[session]
const eventLog = await this._getNewPeriodEventLogForSession(
session,
arbitratorConstants.PERIOD.APPEAL
Expand All @@ -670,7 +679,9 @@ class Kleros extends ContractImplementation {
eventLog.blockNumber
)

return ruledAtTimestamp * 1000
const timestamp = ruledAtTimestamp * 1000
this._appealRuledAtTimestamp[session] = timestamp
return timestamp
}

/**
Expand All @@ -679,6 +690,9 @@ class Kleros extends ContractImplementation {
* @returns {number[]} an array of timestamps
*/
getDisputeDeadlineTimestamp = async session => {
if (this._disputeDeadlineCache[session])
return this._disputeDeadlineCache[session]

const eventLog = await this._getNewPeriodEventLogForSession(
session,
arbitratorConstants.PERIOD.VOTE
Expand All @@ -695,7 +709,9 @@ class Kleros extends ContractImplementation {
eventLog.blockNumber
)

return (periodLength + periodStartTimestamp) * 1000
const deadline = (periodLength + periodStartTimestamp) * 1000
this._disputeDeadlineCache[session] = deadline
return deadline
}

/**
Expand All @@ -704,6 +720,8 @@ class Kleros extends ContractImplementation {
* @returns {number[]} an array of timestamps
*/
getAppealCreationTimestamp = async session => {
if (this._appealCreationTimestamp[session])
return this._appealCreationTimestamp[session]
const eventLog = await this._getNewPeriodEventLogForSession(
session,
arbitratorConstants.PERIOD.EXECUTE
Expand All @@ -716,7 +734,9 @@ class Kleros extends ContractImplementation {
eventLog.blockNumber
)

return createdAtTimestamp * 1000
const timestamp = createdAtTimestamp * 1000
this._appealCreationTimestamp[session] = timestamp
return timestamp
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/resources/Disputes.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ class Disputes {
const arbitratorAddress = this._ArbitratorInstance.getContractAddress()
// Get dispute data from contract. Also get the current session and period.
const [dispute, period, session] = await Promise.all([
this._ArbitratorInstance.getDispute(disputeId),
this._ArbitratorInstance.getDispute(disputeId, true),
this._ArbitratorInstance.getPeriod(),
this._ArbitratorInstance.getSession()
])
Expand Down Expand Up @@ -347,9 +347,9 @@ class Disputes {
const lastSession = dispute.firstSession + dispute.numberOfAppeals
const appealJuror = []
const appealRulings = []

for (let appeal = 0; appeal <= dispute.numberOfAppeals; appeal++) {
const isLastAppeal = dispute.firstSession + appeal === lastSession

// Get appeal data
const draws = appealDraws[appeal] || []
let canRule = false
Expand Down Expand Up @@ -378,7 +378,7 @@ class Disputes {
// Wait for parallel requests to complete
;[ruling, canRule] = await Promise.all(rulingPromises)

let jurorRuling = []
let jurorRuling = null
// if can't rule that means they already did or they missed it
if (!canRule) {
jurorRuling = await this._ArbitratorInstance.getVoteForJuror(
Expand Down
13 changes: 10 additions & 3 deletions src/utils/StoreProviderWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class StoreProviderWrapper {
constructor(storeProviderUri) {
this._storeUri = storeProviderUri
this._storeQueue = new PromiseQueue()
this._cachedProfiles = {}
}

/**
Expand All @@ -25,10 +26,15 @@ class StoreProviderWrapper {
* @param {string} uri uri to call
* @returns {promise} promise that returns result of request. wait on this if you need it to be syncronous
*/
queueWriteRequest = (getBodyFn, verb, uri = null) =>
this._storeQueue.fetch(() =>
queueWriteRequest = (getBodyFn, verb, uri = null, userAddress) => {
// Clear cache on write TODO update cache after every write
this._cachedProfiles[userAddress] = null

return this._storeQueue.fetch(() =>
getBodyFn().then(result => httpRequest(verb, uri, result))
)
}


/**
* If we know we are waiting on some other write before we want to read we can add a read request to the end of the queue.
Expand Down Expand Up @@ -57,11 +63,12 @@ class StoreProviderWrapper {
* @param {string} userAddress - Address of user.
* @returns {object} - a response object.
*/
getUserProfile = async userAddress => {
getUserProfile = async (userAddress) => {
const httpResponse = await httpRequest(
'GET',
`${this._storeUri}/${userAddress}`
)
this._cachedProfiles[userAddress] = httpResponse.body

return httpResponse.body
}
Expand Down

0 comments on commit 0d7a1c6

Please sign in to comment.