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

Commit

Permalink
test: move stateful notification tests to dispute resolution. Test ev…
Browse files Browse the repository at this point in the history
…ent listener in its own test
  • Loading branch information
satello committed Apr 5, 2018
1 parent 20ed58c commit 5ffd7af
Show file tree
Hide file tree
Showing 12 changed files with 350 additions and 382 deletions.
14 changes: 7 additions & 7 deletions src/contracts/AbstractContract.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ class AbstractContract {
* services such as an off chain store, as well as the functionality of the underlying
* implementation.
* @param {object} implementationInstance - Contract Implementation object to extend
* @param {object} storeProviderWrapperInstance - StoreProvider wrapper object.
* @param {object} storeProviderInstance - StoreProvider wrapper object.
*/
constructor(
implementationInstance = isRequired('implementationInstance'),
storeProviderWrapperInstance = isRequired('storeProviderWrapperInstance')
storeProviderInstance = isRequired('storeProviderInstance')
) {
this._StoreProvider = storeProviderWrapperInstance
this._StoreProvider = storeProviderInstance
this._contractImplementation = implementationInstance
delegateCalls(this, implementationInstance)
}

/**
* Set the store wrapper
* @param {object} storeProviderWrapperInstance wrapper for store
* Set store provider instance.
* @param {object} storeProviderInstance - instance of store provider wrapper.
*/
setStoreProvider = storeProviderWrapperInstance => {
this._StoreProvider = storeProviderWrapperInstance
setStoreProviderInstance = storeProviderInstance => {
this._StoreProvider = storeProviderInstance
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/contracts/abstractions/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Arbitrator from './Arbitrator'
import ArbitrableContracts from './Arbitrable'
import Arbitrable from './Arbitrable'

export { Arbitrator, ArbitrableContracts }
export { Arbitrator, Arbitrable }
42 changes: 23 additions & 19 deletions src/kleros.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Kleros {

storeWrapper = {}

eventListener = null

/**
* Instantiates a new Kelros instance that provides the public interface
* to Kleros contracts and library. All params are required. To use an individual
Expand Down Expand Up @@ -57,23 +59,16 @@ class Kleros {
_arbitrableTransaction,
this.storeWrapper
)
// EVENT LISTENER
this.eventListener = new EventListener([
this.arbitrator._contractImplementation.contractInstance,
this.arbitrable._contractImplementation.contractInstance
])
// DISPUTES
this.disputes = new resources.Disputes(
this.arbitrator,
this.arbitrableContracts,
this.eventListener,
this.storeWrapper
)
// NOTIFICATIONS
this.notifications = new resources.Notifications(
this.arbitrator,
this.arbitrableContracts,
this.eventListener,
this.storeWrapper
)
}
Expand All @@ -90,16 +85,26 @@ class Kleros {
account,
callback // for notification callback
) => {
this.eventListener.clearArbitratorHandlers()
await this.disputes.addNewDisputeEventListener()
await this.disputes.addTokenShiftToJurorProfileEventListener(
// stop current event listeners
if (this.eventListener) {
this.eventListener.stopWatchingForEvents()
}
// reinitialize with current arbitrator contract instance
this.eventListener = new EventListener([
this.arbitrator.getContractInstance()
])
// add handlers for notifications
this.notifications.registerArbitratorNotifications(
account,
this.eventListener,
callback
)
await this.disputes.addDisputeDeadlineHandler(account)
await this.disputes.addDisputeRulingHandler(account, callback)
await this.notifications.registerNotificationListeners(account, callback)
await this.eventListener.watchForArbitratorEvents(account)
// add handlers for event driven store updates
this.disputes.registerStoreUpdateEventListeners(account, this.eventListener)
// fetch last block for user
const fromBlock = await this.storeWrapper.getLastBlock(account)
// start event listener
this.eventListener.watchForEvents(fromBlock)
}

/**
Expand All @@ -109,11 +114,10 @@ class Kleros {
setStoreProvider = storeUri => {
this.storeWrapper = new StoreProviderWrapper(storeUri)

this.eventListener.setStoreProvider(this.storeWrapper)
this.disputes.setStoreProvider(this.storeWrapper)
this.arbitrableContract.setStoreProvider(this.storeWrapper)
this.arbitrator.setStoreProvider(this.storeWrapper)
this.notifications.setStoreProvider(this.storeWrapper)
this.disputes.setStoreProviderInstance(this.storeWrapper)
this.arbitrableContract.setStoreProviderInstance(this.storeWrapper)
this.arbitrator.setStoreProviderInstance(this.storeWrapper)
this.notifications.setStoreProviderInstance(this.storeWrapper)
}
}

Expand Down
21 changes: 21 additions & 0 deletions src/resources/Disputes.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,27 @@ class Disputes {
this._ArbitrableInstance = arbitrableInstance
this._StoreProviderInstance = storeProviderInstance
}
/**
* Set arbitrator instance.
* @param {object} arbitratorInstance - instance of an arbitrator contract.
*/
setArbitratorInstance = arbitratorInstance => {
this._ArbitratorInstance = arbitratorInstance
}
/**
* Set arbitrable instance.
* @param {object} arbitrableInstance - instance of an arbitrable contract.
*/
setArbitrableInstance = arbitrableInstance => {
this._ArbitrableInstance = arbitrableInstance
}
/**
* Set store provider instance.
* @param {object} storeProviderInstance - instance of store provider wrapper.
*/
setStoreProviderInstance = storeProviderInstance => {
this._StoreProviderInstance = storeProviderInstance
}

// **************************** //
// * Events * //
Expand Down
2 changes: 1 addition & 1 deletion src/resources/Notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Notifications {
* @param {object} eventListener - Event Listener that will fetch logs and call callbacks
* @param {function} callback - If we want notifications to be "pushed" provide a callback function to call when a new notification is created.
*/
registerArbitratorNotifications = async (
registerArbitratorNotifications = (
account = isRequired('account'),
eventListener = isRequired('eventListener'),
callback
Expand Down
74 changes: 46 additions & 28 deletions src/utils/EventListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ import * as errorConstants from '../constants/error'
class EventListener {
/**
* Listen for events in contract and handles callbacks with registered event handlers.
* @param {object[]} contractInstances - truffle-contract instances to fetch event logs for.
* @param {object[]} _contractInstances - truffle-contract instances to fetch event logs for.
*/
constructor(contractInstances = []) {
this.contractInstances = contractInstances
constructor(_contractInstances = []) {
this.contractInstances = []
// map address -> { event: [handlers], ... }
this.contractEventHandlerMap = {}
// map address -> watcher instance
this.watcherInstances = {}
// event handler queue
this.eventHandlerQueue = new PromiseQueue()
// initialize class variables for new contract instances
_contractInstances.forEach(instance => {
this.addContractInstance(instance)
})
}

/**
Expand Down Expand Up @@ -86,13 +93,15 @@ class EventListener {
// remove instance from this.contractInstances
const removedInstance = _.remove(
this.contractInstances,
instance => instance.contractAddress === contractAddress
instance => instance.address === contractAddress
)
// if we didn't remove anything throw error
if (removedInstance.length === 0)
throw new Error(errorConstants.MISSING_CONTRACT_INSTANCE(contractAddress))
// stop watching on these instances
removedInstance.forEach(instance => instance.stopWatching())
removedInstance.forEach(instance =>
this.stopWatchingForEvents(instance.address)
)
// remove handlers for contract instance
delete this.contractEventHandlerMap[contractAddress]
}
Expand All @@ -118,34 +127,43 @@ class EventListener {
* @param {number} fromBlock - A block number can be passed to catch up on missed logs
*/
watchForEvents = (fromBlock = 'latest') => {
Promise.all(
this.contractInstances.forEach(instance => {
instance
.allEvents({
fromBlock: fromBlock,
lastBlock: 'latest'
})
.watch((error, result) => {
if (!error) {
const handlers = this.contractEventHandlerMap[instance.address][
result.event
]
if (handlers) {
handlers.forEach(handler => {
this._queueEvent(handler, result)
})
}
}
})
this.contractInstances.forEach(instance => {
const newWatcherInstance = instance.allEvents({
fromBlock: fromBlock,
lastBlock: 'latest'
})
)

// NOTE: should we allow more than one listener per contract instance?
if (this.watcherInstances[instance.address])
this.watcherInstances[instance.address].stopWatching()

this.watcherInstances[instance.address] = newWatcherInstance

newWatcherInstance.watch((error, result) => {
if (!error) {
const handlers = this.contractEventHandlerMap[instance.address][
result.event
]
if (handlers) {
handlers.forEach(handler => {
this._queueEvent(handler, result)
})
}
}
})
})
}

/**
* Stop listening on contract.
* Stop listening on contract. If no contractAddress supplied it stops all listeners
* @param {string} contractAddress - Address of the contract to stop watching
*/
stopWatchingForEvents = () => {
this.contractInstances.forEach(instance => instance.stopWatching())
stopWatchingForEvents = contractAddress => {
if (contractAddress) this.watcherInstances[contractAddress].stopWatching()
else
this.contractInstances.forEach(instance => {
this.watcherInstances[instance.address].stopWatching()
})
}

/**
Expand Down
Loading

0 comments on commit 5ffd7af

Please sign in to comment.