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

add decentralized DDO

This commit is contained in:
alexcos20 2020-09-15 01:08:47 -07:00
parent 0130295686
commit c37c169d6a
10 changed files with 283 additions and 11 deletions

View File

@ -19,8 +19,10 @@ before_script:
# Barge setup
- git clone https://github.com/oceanprotocol/barge
- cd barge
- git checkout v3
- git checkout feature/ocean-contracts
- export PROVIDER_VERSION=latest
- export ADDRESS_FILE="${HOME}/.ocean/ocean-contracts/artifacts/address.json"
- export AQUARIUS_URI="http://172.15.0.5:5000"
- bash -x start_ocean.sh --no-dashboard 2>&1 > start_ocean.log &
- cd ..
- sleep 300

5
package-lock.json generated
View File

@ -6603,6 +6603,11 @@
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
"dev": true
},
"lzma": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/lzma/-/lzma-2.3.2.tgz",
"integrity": "sha1-N4OySFi5wOdHoN88vx+1/KqSxEE="
},
"macos-release": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.4.1.tgz",

View File

@ -45,6 +45,7 @@
"@oceanprotocol/contracts": "^0.4.1",
"decimal.js": "^10.2.0",
"fs": "0.0.1-security",
"lzma": "^2.3.2",
"node-fetch": "^2.6.1",
"save-file": "^2.3.1",
"uuid": "^8.3.0",

View File

@ -0,0 +1,211 @@
import { DDO } from '../ddo/DDO'
import { TransactionReceipt } from 'web3-core'
import { Contract } from 'web3-eth-contract'
import { AbiItem } from 'web3-utils/types'
import Web3 from 'web3'
import defaultDDOContractABI from '@oceanprotocol/contracts/artifacts/DDO.json'
import { didZeroX } from '../utils'
import { LZMA } from 'lzma'
/**
* Provides an interface with Metadata Store.
* Metadata Store provides an off-chain database store for metadata about data assets.
*/
export class OnChainMetadataStore {
public DDOContractAddress: string
public DDOContractABI: AbiItem | AbiItem[]
public web3: Web3
public DDOContract: Contract = null
/**
* Instantiate OnChainMetadata Store for on-chain interaction.
*/
constructor(
web3: Web3,
DDOContractAddress: string = null,
DDOContractABI: AbiItem | AbiItem[] = null
) {
this.web3 = web3
this.DDOContractAddress = DDOContractAddress
this.DDOContractABI = DDOContractABI || (defaultDDOContractABI.abi as AbiItem[])
if (web3)
this.DDOContract = new this.web3.eth.Contract(
this.DDOContractABI,
this.DDOContractAddress
)
}
/**
* Publish a new DDO
* @param {String} did
* @param {DDO} ddo
* @param {String} consumerAccount
* @return {Promise<TransactionReceipt>} exchangeId
*/
public async publish(
did: string,
ddo: DDO,
consumerAccount: string
): Promise<TransactionReceipt> {
let flags = 0
const data = DDO.serialize(ddo)
const lzma = new LZMA()
// see https://github.com/LZMA-JS/LZMA-JS/issues/44
lzma.disableEndMark = true
let compressed = lzma.compress(data, 9)
compressed = this.getHex(compressed)
flags = flags | 1
return this.publishRaw(didZeroX(did), flags, compressed, consumerAccount)
}
/**
* Update DDO
* @param {String} did
* @param {DDO} ddo
* @param {String} consumerAccount
* @return {Promise<TransactionReceipt>} exchangeId
*/
public async update(
did: string,
ddo: DDO,
consumerAccount: string
): Promise<TransactionReceipt> {
let flags = 0
const data = DDO.serialize(ddo)
const lzma = new LZMA()
// see https://github.com/LZMA-JS/LZMA-JS/issues/44
lzma.disableEndMark = true
let compressed = lzma.compress(data, 9)
compressed = this.getHex(compressed)
flags = flags | 1
return this.updateRaw(didZeroX(did), flags, compressed, consumerAccount)
}
/**
* Raw publish ddo
* @param {String} did
* @param {Any} flags
* @param {Any} ddo
* @param {String} consumerAccount
* @return {Promise<TransactionReceipt>} exchangeId
*/
public async publishRaw(
did: string,
flags: any,
data: any,
consumerAccount: string
): Promise<TransactionReceipt> {
if (!this.DDOContract) {
console.error('Missing DDOContract')
return null
}
try {
// const data = this.web3.utils.bytesToHex(ddo)
const estGas = await this.DDOContract.methods
.create(did, flags, data)
.estimateGas(function (err, estGas) {
if (err) console.log('OnChainMetadataStore: ' + err)
return estGas
})
const trxReceipt = await this.DDOContract.methods
.create(did, flags, data)
.send({ from: consumerAccount, gas: estGas + 1 })
return trxReceipt
} catch (e) {
console.error(e)
return null
}
}
/**
* Raw update of a ddo
* @param {String} did
* @param {Any} flags
* @param {Any} ddo
* @param {String} consumerAccount
* @return {Promise<TransactionReceipt>} exchangeId
*/
public async updateRaw(
did: string,
flags: any,
ddo: any,
consumerAccount: string
): Promise<TransactionReceipt> {
if (!this.DDOContract) {
console.error('Missing DDOContract')
return null
}
try {
const data = this.web3.utils.bytesToHex(ddo)
const estGas = await this.DDOContract.methods
.update(did, flags, data)
.estimateGas(function (err, estGas) {
if (err) console.log('OnChainMetadataStore: ' + err)
return estGas
})
const trxReceipt = await this.DDOContract.methods
.update(did, flags, data)
.send({ from: consumerAccount, gas: estGas + 1 })
return trxReceipt
} catch (e) {
console.error(e)
return null
}
}
/**
* Transfer Ownership of a DDO
* @param {String} did
* @param {String} newOwner
* @param {String} consumerAccount
* @return {Promise<TransactionReceipt>} exchangeId
*/
public async transferOwnership(
did: string,
newOwner: string,
consumerAccount: string
): Promise<TransactionReceipt> {
if (!this.DDOContract) return null
try {
const trxReceipt = await this.DDOContract.methods
.transferOwnership(didZeroX(did), newOwner)
.send({
from: consumerAccount
})
return trxReceipt
} catch (e) {
console.error(e)
return null
}
}
public getHex(message: any) {
const hexChar = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F'
]
let hex = ''
try {
for (let i = 0; i < message.length; i++) {
hex += '' + hexChar[(message[i] >> 4) & 0x0f] + hexChar[message[i] & 0x0f]
}
} catch (e) {
console.error(e)
}
const hexMessage = '0x' + hex
return hexMessage
}
}

View File

@ -85,6 +85,17 @@ export class Config {
* @type {any}
*/
public fixedRateExchangeAddressABI?: AbiItem | AbiItem[]
/**
* DDOContractAddress
* @type {string}
*/
public DDOContractAddress?: string
/**
* DDOContractABI
* @type {any}
*/
public DDOContractABI?: AbiItem | AbiItem[]
/**
* Log level.
* @type {boolean | LogLevel}

View File

@ -161,10 +161,16 @@ export class Assets extends Instantiable {
observer.next(CreateProgressStep.ProofGenerated)
this.logger.log('Storing DDO')
observer.next(CreateProgressStep.StoringDdo)
const storedDdo = await this.ocean.metadatastore.storeDDO(ddo)
// const storedDdo = await this.ocean.metadatastore.storeDDO(ddo)
const storeTx = await this.ocean.OnChainMetadataStore.publish(
ddo.id,
ddo,
publisher.getId()
)
this.logger.log('DDO stored')
observer.next(CreateProgressStep.DdoStored)
return storedDdo
if (storeTx) return ddo
else return null
})
}

View File

@ -3,6 +3,7 @@ import { Assets } from './Assets'
import { Versions } from './Versions'
import { OceanUtils } from './utils/Utils'
import { MetadataStore } from '../metadatastore/MetadataStore'
import { OnChainMetadataStore } from '../metadatastore/OnChainMetaData'
import { Provider } from '../provider/Provider'
import { DataTokens } from '../datatokens/Datatokens'
import { Network } from '../datatokens/Network'
@ -64,6 +65,11 @@ export class Ocean extends Instantiable {
instanceConfig.config.fixedRateExchangeAddressABI,
instanceConfig.config.oceanTokenAddress
)
instance.OnChainMetadataStore = new OnChainMetadataStore(
instanceConfig.config.web3Provider,
instanceConfig.config.DDOContractAddress,
instanceConfig.config.DDOContractABI
)
instance.versions = await Versions.getInstance(instanceConfig)
instance.network = new Network()
return instance
@ -92,7 +98,11 @@ export class Ocean extends Instantiable {
* @type {MetadataStore}
*/
public metadatastore: MetadataStore
/**
* OnChainMetadataStore instance.
* @type {OnChainMetadataStore}
*/
public OnChainMetadataStore: OnChainMetadataStore
/**
* Ocean account submodule
* @type {Accounts}

View File

@ -1,5 +1,6 @@
import Config from '../models/Config'
import { Logger } from '../lib'
import fs from 'fs'
export declare type ConfigHelperNetworkName =
| 'mainnet'
@ -23,7 +24,8 @@ const configs: ConfigHelperConfig[] = [
metadataStoreUri: 'http://127.0.0.1:5000',
providerUri: 'http://127.0.0.1:8030',
poolFactoryAddress: null,
fixedRateExchangeAddress: null
fixedRateExchangeAddress: null,
DDOContractAddress: null
},
{
chainId: 4,
@ -34,7 +36,8 @@ const configs: ConfigHelperConfig[] = [
metadataStoreUri: 'https://aquarius.rinkeby.v3.dev-ocean.com',
providerUri: 'https://provider.rinkeby.v3.dev-ocean.com',
poolFactoryAddress: '0x9B90A1358fbeEC1C4bB1DA7D4E85C708f87556Ec',
fixedRateExchangeAddress: '0x991c08bD00761A299d3126a81a985329096896D4'
fixedRateExchangeAddress: '0x991c08bD00761A299d3126a81a985329096896D4',
DDOContractAddress: '0xEfA25E39192b3175d451D79C1c0a41Fa3C32c87d'
},
{
chainId: 1,
@ -45,15 +48,34 @@ const configs: ConfigHelperConfig[] = [
metadataStoreUri: null,
providerUri: null,
poolFactoryAddress: null,
fixedRateExchangeAddress: null
fixedRateExchangeAddress: null,
DDOContractAddress: null
}
]
export class ConfigHelper {
/* Load config from env ADDRESS_FILE (generated by ocean-contracts) */
public loadAddressesFromEnv() {
try {
const data = JSON.parse(fs.readFileSync(process.env.ADDRESS_FILE, 'utf8'))
if (data) {
if (data.ganache) {
if (data.ganache.DTFactory) configs[0].factoryAddress = data.ganache.DTFactory
if (data.ganache.BFactory) configs[0].poolFactoryAddress = data.ganache.BFactory
if (data.ganache.FixedRateExchange)
configs[0].fixedRateExchangeAddress = data.ganache.FixedRateExchange
if (data.ganache.DDO) configs[0].DDOContractAddress = data.ganache.DDO
}
}
if (process.env.AQUARIUS_URI) configs[0].metadataStoreUri = process.env.AQUARIUS_URI
} catch (e) {}
}
public getConfig(
network: ConfigHelperNetworkName | ConfigHelperNetworkId,
infuraProjectId?: string
): Config {
if (network === 'development') this.loadAddressesFromEnv()
const filterBy = typeof network === 'string' ? 'network' : 'chainId'
const config = configs.find((c) => c[filterBy] === network)

View File

@ -2,7 +2,8 @@ import { AbiItem } from 'web3-utils/types'
import { TestContractHandler } from '../TestContractHandler'
import { DataTokens } from '../../src/datatokens/Datatokens'
import { Ocean } from '../../src/ocean/Ocean'
import config from './config'
import { ConfigHelper } from '../../src/utils/ConfigHelper'
import { assert } from 'console'
import { ServiceComputePrivacy } from '../../src/ddo/interfaces/Service'
import Web3 from 'web3'
@ -61,7 +62,8 @@ describe('Compute flow', () => {
factory.bytecode,
web3
)
const config = new ConfigHelper().getConfig('development')
config.web3Provider = web3
ocean = await Ocean.getInstance(config)
owner = (await ocean.accounts.list())[0]
alice = (await ocean.accounts.list())[1]

View File

@ -2,7 +2,8 @@ import { AbiItem } from 'web3-utils/types'
import { TestContractHandler } from '../TestContractHandler'
import { DataTokens } from '../../src/datatokens/Datatokens'
import { Ocean } from '../../src/ocean/Ocean'
import config from './config'
import { ConfigHelper } from '../../src/utils/ConfigHelper'
// import config from './config'
import { assert } from 'console'
import Web3 from 'web3'
@ -38,7 +39,8 @@ describe('Marketplace flow', () => {
factory.bytecode,
web3
)
const config = new ConfigHelper().getConfig('development')
config.web3Provider = web3
ocean = await Ocean.getInstance(config)
owner = (await ocean.accounts.list())[0]
alice = (await ocean.accounts.list())[1]