1
0
mirror of https://github.com/oceanprotocol/ocean.js.git synced 2024-11-26 20:39:05 +01:00

Merge pull request #441 from oceanprotocol/feature/pool_logs_history_speed_optimisation

logs/history speed optimizations
This commit is contained in:
Alex Coseru 2020-11-10 22:06:47 +02:00 committed by GitHub
commit 9e265912d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 177 additions and 92 deletions

View File

@ -1,6 +1,6 @@
import Web3 from 'web3' import Web3 from 'web3'
import { AbiItem } from 'web3-utils/types' import { AbiItem } from 'web3-utils/types'
import { TransactionReceipt } from 'web3-core' import { TransactionReceipt, Log } from 'web3-core'
import { Pool } from './Pool' import { Pool } from './Pool'
import { EventData, Filter } from 'web3-eth-contract' import { EventData, Filter } from 'web3-eth-contract'
import BigNumber from 'bignumber.js' import BigNumber from 'bignumber.js'
@ -54,6 +54,7 @@ export enum PoolCreateProgressStep {
export class OceanPool extends Pool { export class OceanPool extends Pool {
public oceanAddress: string = null public oceanAddress: string = null
public dtAddress: string = null public dtAddress: string = null
public startBlock: number
constructor( constructor(
web3: Web3, web3: Web3,
@ -62,12 +63,14 @@ export class OceanPool extends Pool {
poolABI: AbiItem | AbiItem[] = null, poolABI: AbiItem | AbiItem[] = null,
factoryAddress: string = null, factoryAddress: string = null,
oceanAddress: string = null, oceanAddress: string = null,
gaslimit?: number startBlock?: number
) { ) {
super(web3, logger, factoryABI, poolABI, factoryAddress, gaslimit) super(web3, logger, factoryABI, poolABI, factoryAddress)
if (oceanAddress) { if (oceanAddress) {
this.oceanAddress = oceanAddress this.oceanAddress = oceanAddress
} }
if (startBlock) this.startBlock = startBlock
else this.startBlock = 0
} }
/** /**
@ -168,6 +171,7 @@ export class OceanPool extends Pool {
const tokens = await this.getCurrentTokens(poolAddress) const tokens = await this.getCurrentTokens(poolAddress)
let token: string let token: string
if (tokens != null)
for (token of tokens) { for (token of tokens) {
// TODO: Potential timing attack, left side: true // TODO: Potential timing attack, left side: true
if (token !== this.oceanAddress) this.dtAddress = token if (token !== this.oceanAddress) this.dtAddress = token
@ -855,7 +859,7 @@ export class OceanPool extends Pool {
const factory = new this.web3.eth.Contract(this.factoryABI, this.factoryAddress) const factory = new this.web3.eth.Contract(this.factoryABI, this.factoryAddress)
const events = await factory.getPastEvents('BPoolRegistered', { const events = await factory.getPastEvents('BPoolRegistered', {
filter: {}, filter: {},
fromBlock: BPFACTORY_DEPLOY_BLOCK, fromBlock: this.startBlock,
toBlock: 'latest' toBlock: 'latest'
}) })
events.sort((a, b) => (a.blockNumber > b.blockNumber ? 1 : -1)) events.sort((a, b) => (a.blockNumber > b.blockNumber ? 1 : -1))
@ -920,7 +924,7 @@ export class OceanPool extends Pool {
const events = await factory.getPastEvents('BPoolRegistered', { const events = await factory.getPastEvents('BPoolRegistered', {
filter: account ? { registeredBy: account } : {}, filter: account ? { registeredBy: account } : {},
fromBlock: BPFACTORY_DEPLOY_BLOCK, fromBlock: this.startBlock,
toBlock: 'latest' toBlock: 'latest'
}) })
for (let i = 0; i < events.length; i++) { for (let i = 0; i < events.length; i++) {
@ -930,6 +934,21 @@ export class OceanPool extends Pool {
return result return result
} }
private async getResult(account: string, event: EventData): Promise<PoolShare> {
const shares = await super.sharesBalance(account, event.returnValues[0])
if (parseFloat(shares) > 0) {
const dtAddress = await this.getDTAddress(event.returnValues[0])
if (dtAddress) {
const onePool: PoolShare = {
shares,
poolAddress: event.returnValues[0],
did: didPrefixed(didNoZeroX(dtAddress))
}
return onePool
}
}
}
/** /**
* Search all pools in which a user has shares * Search all pools in which a user has shares
* @param {String} account * @param {String} account
@ -941,23 +960,20 @@ export class OceanPool extends Pool {
const events = await factory.getPastEvents('BPoolRegistered', { const events = await factory.getPastEvents('BPoolRegistered', {
filter: {}, filter: {},
fromBlock: BPFACTORY_DEPLOY_BLOCK, fromBlock: this.startBlock,
toBlock: 'latest' toBlock: 'latest'
}) })
for (let i = 0; i < events.length; i++) { let results = await Promise.all(
const shares = await super.sharesBalance(account, events[i].returnValues[0]) events.map((event) => {
if (parseFloat(shares) > 0) { return this.getResult(account, event)
const dtAddress = await this.getDTAddress(events[i].returnValues[0]) })
if (dtAddress) { )
const onePool: PoolShare = { results = results.filter((share) => {
shares, return share !== undefined
poolAddress: events[i].returnValues[0], })
did: didPrefixed(didNoZeroX(dtAddress))
} result.push(...results)
result.push(onePool)
}
}
}
return result return result
} }
@ -984,43 +1000,55 @@ export class OceanPool extends Pool {
account?: string account?: string
): Promise<PoolTransaction[]> { ): Promise<PoolTransaction[]> {
const results: PoolTransaction[] = [] const results: PoolTransaction[] = []
const pool = new this.web3.eth.Contract(this.poolABI, poolAddress)
const dtAddress = await this.getDTAddress(poolAddress) const dtAddress = await this.getDTAddress(poolAddress)
const filter: Filter = account ? { caller: account } : {} if (startBlock === 0) startBlock = this.startBlock
let events: EventData[] const swapTopic = super.getSwapEventSignature()
const joinTopic = super.getJoinEventSignature()
events = await pool.getPastEvents('LOG_SWAP', { const exitTopic = super.getExitEventSignature()
filter, let addressTopic
if (account)
addressTopic = '0x000000000000000000000000' + account.substring(2).toLowerCase()
else addressTopic = null
const events = await this.web3.eth.getPastLogs({
address: poolAddress,
topics: [[swapTopic, joinTopic, exitTopic], addressTopic],
fromBlock: startBlock, fromBlock: startBlock,
toBlock: 'latest' toBlock: 'latest'
}) })
for (let i = 0; i < events.length; i++) { let eventResults = await Promise.all(
if (!account || events[i].returnValues[0].toLowerCase() === account.toLowerCase()) events.map((event) => {
results.push(await this.getEventData('swap', poolAddress, dtAddress, events[i])) switch (event.topics[0]) {
case swapTopic:
return this.getEventData('swap', poolAddress, dtAddress, event)
break
case joinTopic:
return this.getEventData('join', poolAddress, dtAddress, event)
break
case exitTopic:
return this.getEventData('exit', poolAddress, dtAddress, event)
break
} }
events = await pool.getPastEvents('LOG_JOIN', {
filter,
fromBlock: startBlock,
toBlock: 'latest'
}) })
)
for (let i = 0; i < events.length; i++) { eventResults = eventResults.filter((share) => {
if (!account || events[i].returnValues[0].toLowerCase() === account.toLowerCase()) return share !== undefined
results.push(await this.getEventData('join', poolAddress, dtAddress, events[i]))
}
events = await pool.getPastEvents('LOG_EXIT', {
filter,
fromBlock: startBlock,
toBlock: 'latest'
}) })
for (let i = 0; i < events.length; i++) { results.push(...eventResults)
if (!account || events[i].returnValues[0].toLowerCase() === account.toLowerCase())
results.push(await this.getEventData('exit', poolAddress, dtAddress, events[i]))
}
// for (let i = 0; i < events.length; i++) {
// switch (events[i].topics[0]) {
// case swapTopic:
// results.push(await this.getEventData('swap', poolAddress, dtAddress, events[i]))
// break
// case joinTopic:
// results.push(await this.getEventData('join', poolAddress, dtAddress, events[i]))
// break
// case exitTopic:
// results.push(await this.getEventData('exit', poolAddress, dtAddress, events[i]))
// break
// }
// }
return results return results
} }
@ -1034,17 +1062,19 @@ export class OceanPool extends Pool {
const factory = new this.web3.eth.Contract(this.factoryABI, this.factoryAddress) const factory = new this.web3.eth.Contract(this.factoryABI, this.factoryAddress)
const events = await factory.getPastEvents('BPoolRegistered', { const events = await factory.getPastEvents('BPoolRegistered', {
filter: {}, filter: {},
fromBlock: BPFACTORY_DEPLOY_BLOCK, fromBlock: this.startBlock,
toBlock: 'latest' toBlock: 'latest'
}) })
for (let i = 0; i < events.length; i++) {
const logs = await this.getPoolLogs( const eventsResults = await Promise.all(
events[i].returnValues[0], events.map((event) => {
events[i].blockNumber, return this.getPoolLogs(event.returnValues[0], event.blockNumber, account)
account })
) )
for (let j = 0; j < logs.length; j++) results.push(logs[j])
} const eventResults = eventsResults.reduce((elem1, elem2) => elem1.concat(elem2))
results.push(...eventResults)
return results return results
} }
@ -1052,41 +1082,44 @@ export class OceanPool extends Pool {
type: PoolTransactionType, type: PoolTransactionType,
poolAddress: string, poolAddress: string,
dtAddress: string, dtAddress: string,
data: EventData data: Log
): Promise<PoolTransaction> { ): Promise<PoolTransaction> {
const blockDetails = await this.web3.eth.getBlock(data.blockNumber) const blockDetails = await this.web3.eth.getBlock(data.blockNumber)
let result: PoolTransaction = { let result: PoolTransaction = {
poolAddress, poolAddress,
dtAddress, dtAddress,
caller: data.returnValues[0], caller: data.topics[1],
transactionHash: data.transactionHash, transactionHash: data.transactionHash,
blockNumber: data.blockNumber, blockNumber: data.blockNumber,
timestamp: parseInt(String(blockDetails.timestamp)), timestamp: parseInt(String(blockDetails.timestamp)),
type type
} }
let params
switch (type) { switch (type) {
case 'swap': case 'swap':
params = this.web3.eth.abi.decodeParameters(['uint256', 'uint256'], data.data)
result = { result = {
...result, ...result,
tokenIn: data.returnValues[1], tokenIn: '0x' + data.topics[2].substring(data.topics[2].length - 40),
tokenOut: data.returnValues[2], tokenOut: '0x' + data.topics[2].substring(data.topics[3].length - 40),
tokenAmountIn: this.web3.utils.fromWei(data.returnValues[3]), tokenAmountIn: this.web3.utils.fromWei(params[0]),
tokenAmountOut: this.web3.utils.fromWei(data.returnValues[4]) tokenAmountOut: this.web3.utils.fromWei(params[1])
} }
break break
case 'join': case 'join':
params = this.web3.eth.abi.decodeParameters(['uint256'], data.data)
result = { result = {
...result, ...result,
tokenIn: data.returnValues[1], tokenIn: '0x' + data.topics[2].substring(data.topics[2].length - 40),
tokenAmountIn: this.web3.utils.fromWei(data.returnValues[2]) tokenAmountIn: this.web3.utils.fromWei(params[0])
} }
break break
case 'exit': case 'exit':
params = this.web3.eth.abi.decodeParameters(['uint256'], data.data)
result = { result = {
...result, ...result,
tokenOut: data.returnValues[1], tokenOut: '0x' + data.topics[2].substring(data.topics[2].length - 40),
tokenAmountOut: this.web3.utils.fromWei(data.returnValues[2]) tokenAmountOut: this.web3.utils.fromWei(params[0])
} }
break break
} }

View File

@ -26,10 +26,9 @@ export class Pool extends PoolFactory {
logger: Logger, logger: Logger,
factoryABI: AbiItem | AbiItem[] = null, factoryABI: AbiItem | AbiItem[] = null,
poolABI: AbiItem | AbiItem[] = null, poolABI: AbiItem | AbiItem[] = null,
factoryAddress: string = null, factoryAddress: string = null
gaslimit?: number
) { ) {
super(web3, logger, factoryABI, factoryAddress, gaslimit) super(web3, logger, factoryABI, factoryAddress)
if (poolABI) this.poolABI = poolABI if (poolABI) this.poolABI = poolABI
else this.poolABI = jsonpoolABI.abi as AbiItem[] else this.poolABI = jsonpoolABI.abi as AbiItem[]
} }
@ -1150,4 +1149,43 @@ export class Pool extends PoolFactory {
} }
return amount return amount
} }
/**
* Get LOG_SWAP encoded topic
* @return {String}
*/
public getSwapEventSignature(): string {
const abi = this.poolABI as AbiItem[]
const eventdata = abi.find(function (o) {
if (o.name === 'LOG_SWAP' && o.type === 'event') return o
})
const topic = this.web3.eth.abi.encodeEventSignature(eventdata as any)
return topic
}
/**
* Get LOG_JOIN encoded topic
* @return {String}
*/
public getJoinEventSignature(): string {
const abi = this.poolABI as AbiItem[]
const eventdata = abi.find(function (o) {
if (o.name === 'LOG_JOIN' && o.type === 'event') return o
})
const topic = this.web3.eth.abi.encodeEventSignature(eventdata as any)
return topic
}
/**
* Get LOG_EXIT encoded topic
* @return {String}
*/
public getExitEventSignature(): string {
const abi = this.poolABI as AbiItem[]
const eventdata = abi.find(function (o) {
if (o.name === 'LOG_EXIT' && o.type === 'event') return o
})
const topic = this.web3.eth.abi.encodeEventSignature(eventdata as any)
return topic
}
} }

View File

@ -15,8 +15,7 @@ export class PoolFactory {
web3: Web3, web3: Web3,
logger: Logger, logger: Logger,
factoryABI: AbiItem | AbiItem[] = null, factoryABI: AbiItem | AbiItem[] = null,
factoryAddress: string = null, factoryAddress: string = null
gaslimit?: number
) { ) {
this.web3 = web3 this.web3 = web3
@ -25,7 +24,6 @@ export class PoolFactory {
if (factoryAddress) { if (factoryAddress) {
this.factoryAddress = factoryAddress this.factoryAddress = factoryAddress
} }
if (gaslimit) this.GASLIMIT_DEFAULT = gaslimit
this.logger = logger this.logger = logger
} }

View File

@ -39,6 +39,7 @@ export class OceanFixedRateExchange {
public contract: Contract = null public contract: Contract = null
private logger: Logger private logger: Logger
public datatokens: DataTokens public datatokens: DataTokens
public startBlock: number
/** /**
* Instantiate FixedRateExchange * Instantiate FixedRateExchange
@ -53,10 +54,13 @@ export class OceanFixedRateExchange {
fixedRateExchangeAddress: string = null, fixedRateExchangeAddress: string = null,
fixedRateExchangeABI: AbiItem | AbiItem[] = null, fixedRateExchangeABI: AbiItem | AbiItem[] = null,
oceanAddress: string = null, oceanAddress: string = null,
datatokens: DataTokens datatokens: DataTokens,
startBlock?: number
) { ) {
this.web3 = web3 this.web3 = web3
this.fixedRateExchangeAddress = fixedRateExchangeAddress this.fixedRateExchangeAddress = fixedRateExchangeAddress
if (startBlock) this.startBlock = startBlock
else this.startBlock = 0
this.fixedRateExchangeABI = this.fixedRateExchangeABI =
fixedRateExchangeABI || (defaultFixedRateExchangeABI.abi as AbiItem[]) fixedRateExchangeABI || (defaultFixedRateExchangeABI.abi as AbiItem[])
this.oceanAddress = oceanAddress this.oceanAddress = oceanAddress
@ -359,7 +363,7 @@ export class OceanFixedRateExchange {
const result: FixedPriceExchange[] = [] const result: FixedPriceExchange[] = []
const events = await this.contract.getPastEvents('ExchangeCreated', { const events = await this.contract.getPastEvents('ExchangeCreated', {
filter: { datatoken: dataTokenAddress.toLowerCase() }, filter: { datatoken: dataTokenAddress.toLowerCase() },
fromBlock: 0, fromBlock: this.startBlock,
toBlock: 'latest' toBlock: 'latest'
}) })
for (let i = 0; i < events.length; i++) { for (let i = 0; i < events.length; i++) {
@ -388,7 +392,7 @@ export class OceanFixedRateExchange {
const result: FixedPriceExchange[] = [] const result: FixedPriceExchange[] = []
const events = await this.contract.getPastEvents('ExchangeCreated', { const events = await this.contract.getPastEvents('ExchangeCreated', {
filter: {}, filter: {},
fromBlock: 0, fromBlock: this.startBlock,
toBlock: 'latest' toBlock: 'latest'
}) })
for (let i = 0; i < events.length; i++) { for (let i = 0; i < events.length; i++) {
@ -411,7 +415,7 @@ export class OceanFixedRateExchange {
const result: FixedPriceSwap[] = [] const result: FixedPriceSwap[] = []
const events = await this.contract.getPastEvents('Swapped', { const events = await this.contract.getPastEvents('Swapped', {
filter: { exchangeId: exchangeId }, filter: { exchangeId: exchangeId },
fromBlock: 0, fromBlock: this.startBlock,
toBlock: 'latest' toBlock: 'latest'
}) })
for (let i = 0; i < events.length; i++) { for (let i = 0; i < events.length; i++) {
@ -430,7 +434,7 @@ export class OceanFixedRateExchange {
const result: FixedPriceSwap[] = [] const result: FixedPriceSwap[] = []
const events = await this.contract.getPastEvents('ExchangeCreated', { const events = await this.contract.getPastEvents('ExchangeCreated', {
filter: {}, filter: {},
fromBlock: 0, fromBlock: this.startBlock,
toBlock: 'latest' toBlock: 'latest'
}) })
for (let i = 0; i < events.length; i++) { for (let i = 0; i < events.length; i++) {

View File

@ -96,6 +96,11 @@ export class Config {
* @type {any} * @type {any}
*/ */
public metadataContractABI?: AbiItem | AbiItem[] public metadataContractABI?: AbiItem | AbiItem[]
/**
* block number of the deployment
* @type {number}
*/
public startBlock?: number
/** /**
* Log level. * Log level.
* @type {boolean | LogLevel} * @type {boolean | LogLevel}

View File

@ -59,7 +59,8 @@ export class Ocean extends Instantiable {
instanceConfig.config.poolFactoryABI, instanceConfig.config.poolFactoryABI,
instanceConfig.config.poolABI, instanceConfig.config.poolABI,
instanceConfig.config.poolFactoryAddress, instanceConfig.config.poolFactoryAddress,
instanceConfig.config.oceanTokenAddress instanceConfig.config.oceanTokenAddress,
instanceConfig.config.startBlock
) )
instance.fixedRateExchange = new OceanFixedRateExchange( instance.fixedRateExchange = new OceanFixedRateExchange(
instanceConfig.config.web3Provider, instanceConfig.config.web3Provider,
@ -67,7 +68,8 @@ export class Ocean extends Instantiable {
instanceConfig.config.fixedRateExchangeAddress, instanceConfig.config.fixedRateExchangeAddress,
instanceConfig.config.fixedRateExchangeAddressABI, instanceConfig.config.fixedRateExchangeAddressABI,
instanceConfig.config.oceanTokenAddress, instanceConfig.config.oceanTokenAddress,
instance.datatokens instance.datatokens,
instanceConfig.config.startBlock
) )
instance.OnChainMetadataCache = new OnChainMetadataCache( instance.OnChainMetadataCache = new OnChainMetadataCache(
instanceConfig.config.web3Provider, instanceConfig.config.web3Provider,

View File

@ -27,7 +27,8 @@ const configs: ConfigHelperConfig[] = [
factoryAddress: '0x1234', factoryAddress: '0x1234',
poolFactoryAddress: null, poolFactoryAddress: null,
fixedRateExchangeAddress: null, fixedRateExchangeAddress: null,
metadataContractAddress: null metadataContractAddress: null,
startBlock: 0
}, },
{ {
// barge // barge
@ -40,7 +41,8 @@ const configs: ConfigHelperConfig[] = [
factoryAddress: null, factoryAddress: null,
poolFactoryAddress: null, poolFactoryAddress: null,
fixedRateExchangeAddress: null, fixedRateExchangeAddress: null,
metadataContractAddress: null metadataContractAddress: null,
startBlock: 0
}, },
{ {
networkId: 4, networkId: 4,
@ -52,7 +54,8 @@ const configs: ConfigHelperConfig[] = [
factoryAddress: null, factoryAddress: null,
poolFactoryAddress: null, poolFactoryAddress: null,
fixedRateExchangeAddress: null, fixedRateExchangeAddress: null,
metadataContractAddress: null metadataContractAddress: null,
startBlock: 7294090
}, },
{ {
networkId: 1, networkId: 1,
@ -64,7 +67,8 @@ const configs: ConfigHelperConfig[] = [
factoryAddress: null, factoryAddress: null,
poolFactoryAddress: null, poolFactoryAddress: null,
fixedRateExchangeAddress: null, fixedRateExchangeAddress: null,
metadataContractAddress: null metadataContractAddress: null,
startBlock: 11105522
} }
] ]

View File

@ -109,7 +109,8 @@ describe('Balancer flow', () => {
OceanPoolFactory.abi as AbiItem[], OceanPoolFactory.abi as AbiItem[],
OceanSPool.abi as AbiItem[], OceanSPool.abi as AbiItem[],
OceanPoolFactoryAddress, OceanPoolFactoryAddress,
oceanTokenAddress oceanTokenAddress,
0
) )
assert(Pool !== null) assert(Pool !== null)
}) })