integrate DDO more

This commit is contained in:
Sebastian Gerske 2018-11-05 10:01:58 +01:00
parent a32d6cbdbf
commit 6e2b270a1f
21 changed files with 468 additions and 358 deletions

6
package-lock.json generated
View File

@ -120,9 +120,9 @@
}
},
"@oceanprotocol/keeper-contracts": {
"version": "0.3.11",
"resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.3.11.tgz",
"integrity": "sha512-4xJtXc77Rw1pO9yt1NryFypx3KOzQcKX6Iv7c5dKXIh+FigSmrOPgVFtbFj0bwtLwpmt2+2JIYd/iiN943q/fw=="
"version": "0.3.12",
"resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.3.12.tgz",
"integrity": "sha512-mJAldSLxyAhfhEI0IB5o3HVLGeZ65dz69331COPrsOoEsy288bhX1QMwdJS4B1C5nO3cvf41Xgp8qgCpTouNvA=="
},
"@oceanprotocol/secret-store-client": {
"version": "0.0.7",

View File

@ -13,6 +13,7 @@
"build": "npm run clean && npm run lint && tsc && npm run doc",
"build:watch": "tsc -w",
"doc": "typedoc --mode modules --out ./doc/ ./src/",
"run": "ts-node",
"release": "./node_modules/release-it/bin/release-it.js --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"release-minor": "./node_modules/release-it/bin/release-it.js minor --src.tagName='v%s' --github.release --npm.publish --non-interactive",
"release-major": "./node_modules/release-it/bin/release-it.js major --src.tagName='v%s' --github.release --npm.publish --non-interactive",
@ -50,8 +51,8 @@
"node": ">=8 <10"
},
"dependencies": {
"@oceanprotocol/keeper-contracts": "^0.3.11",
"@oceanprotocol/secret-store-client": "^0.0.7",
"@oceanprotocol/keeper-contracts": "^0.3.12",
"@oceanprotocol/secret-store-client": "0.0.7",
"bignumber.js": "^8.0.1",
"eth-crypto": "^1.2.5",
"eth-ecies": "^1.0.3",

6
src/ddo/Condition.ts Normal file
View File

@ -0,0 +1,6 @@
export default class Condition {
public name: string = "lockPayment"
public timeout: number = 0
public conditionKey: string
public parameters: any
}

View File

@ -1,8 +1,13 @@
import Condition from "./Condition"
import MetaData from "./MetaData"
export default class Service {
public type: string = "OpenIdConnectVersion1.0Service"
public serviceDefinitionId?: string
public templateId?: string
public serviceEndpoint: string = "https://openid.example.com/"
public purchaseEndpoint?: string
public description?: string = "My public social inbox"
public metadata?: MetaData = {} as MetaData
public conditions?: Condition[] = []
}

View File

@ -0,0 +1,33 @@
import ServiceAgreement from "../ocean/ServiceAgreement"
import {Account, Asset, Logger, Ocean} from "../squid"
(async () => {
const ocean: Ocean = await Ocean.getInstance({
nodeUri: "http://localhost:8545",
aquariusUri: "http://localhost:5000",
parityUri: "http://localhost:9545",
secretStoreUri: "https://secret-store.dev-ocean.com",
threshold: 2,
password: "unittest",
address: "0xed243adfb84a6626eba46178ccb567481c6e655d",
})
const publisher: Account = (await ocean.getAccounts())[0]
const consumer: Account = (await ocean.getAccounts())[0]
const asset: Asset = new Asset(
"Fancy Car Data",
"nice data",
100, publisher)
const assetDid = await ocean.register(asset)
Logger.log("asset did:", assetDid)
const serviceAgreement: ServiceAgreement = await asset.purchase(consumer)
Logger.log("service defintion id:", serviceAgreement.getId())
const accessGranted: boolean =
await serviceAgreement.grantAccess(asset.getId(), "321721938712931283")
Logger.log("access granted:", accessGranted)
})()

28
src/examples/Purchase.ts Normal file
View File

@ -0,0 +1,28 @@
import {Account, Asset, Logger, Ocean} from "../squid"
import ServiceAgreement from "../ocean/ServiceAgreement"
(async () => {
const ocean: Ocean = await Ocean.getInstance({
nodeUri: "http://localhost:8545",
aquariusUri: "http://localhost:5000",
parityUri: "http://localhost:9545",
secretStoreUri: "https://secret-store.dev-ocean.com",
threshold: 2,
password: "unittest",
address: "0xed243adfb84a6626eba46178ccb567481c6e655d",
})
const publisher: Account = (await ocean.getAccounts())[0]
const consumer: Account = (await ocean.getAccounts())[1]
const asset: Asset = new Asset(
"Fancy Car Data",
"nice data",
100, publisher)
const assetDid = await ocean.register(asset)
Logger.log(assetDid)
const serviceAgreement: ServiceAgreement = await asset.purchase(consumer)
Logger.log(serviceAgreement.getId())
})()

22
src/examples/Register.ts Normal file
View File

@ -0,0 +1,22 @@
import {Account, Asset, Logger, Ocean} from "../squid"
(async () => {
const ocean: Ocean = await Ocean.getInstance({
nodeUri: "http://localhost:8545",
aquariusUri: "http://localhost:5000",
parityUri: "http://localhost:9545",
secretStoreUri: "https://secret-store.dev-ocean.com",
threshold: 2,
password: "unittest",
address: "0xed243adfb84a6626eba46178ccb567481c6e655d",
})
const publisher: Account = (await ocean.getAccounts())[0]
const asset: Asset = new Asset(
"Fancy Car Data",
"nice data", 100,
publisher)
const assetDid = await ocean.register(asset)
Logger.log(assetDid)
})()

View File

@ -24,18 +24,19 @@ export default class ServiceAgreement extends ContractBase {
return this.call("getTemplateStatus", [templateId])
}
public async getAgreementStatus(serviceAgreementId: string) {
public async getAgreementStatus(serviceDefinitionId: string) {
return this.call("getAgreementStatus", ["0x" + serviceAgreementId])
return this.call("getAgreementStatus", [serviceDefinitionId])
}
public async executeAgreement(serviceAgreementTemplateId: string, serviceAgreementSignatureHash: string,
consumerAddress: string, valueHashes: string[], timeoutValues: number[],
serviceAgreementId: string, did: string, publisherAddress: string): Promise<Receipt> {
serviceAgreementId: string, did: string, publisherAddress: string):
Promise<Receipt> {
return this.send("executeAgreement", publisherAddress, [
serviceAgreementTemplateId, serviceAgreementSignatureHash, consumerAddress, valueHashes,
timeoutValues, "0x" + serviceAgreementId, "0x" + did,
timeoutValues, "0x" + serviceAgreementId, "0x" + did.replace("did:op:", ""),
])
}
}

View File

@ -9,10 +9,10 @@ export default class AccessConditions extends ContractBase {
return accessConditions
}
public async grantAccess(serviceAgreementId: any, assetId: any, documentKeyId: any, publisherAddress: string)
public async grantAccess(serviceDefinitionId: any, assetId: any, documentKeyId: any, publisherAddress: string)
: Promise<Receipt> {
return this.send("grantAccess", publisherAddress, [
"0x" + serviceAgreementId, "0x" + assetId, "0x" + documentKeyId,
serviceDefinitionId, "0x" + assetId, "0x" + documentKeyId,
])
}
}

View File

@ -5,9 +5,9 @@ export default class Config {
/* Keeper Config */
// the uri to the node we want to connect to, not need if web3Provider is set
public nodeUri: string
public nodeUri?: string
// from outside eg. metamask
public web3Provider: any
public web3Provider?: any
/* Secret Store Config */
// the uri of the secret store to connect to

View File

@ -1,10 +1,8 @@
import * as EthCrypto from "eth-crypto"
import * as EthjsUtil from "ethereumjs-util"
import Keeper from "../keeper/Keeper"
import Logger from "../utils/Logger"
import AquariusProvider from "../aquarius/AquariusProvider"
import Account from "./Account"
import IdGenerator from "./IdGenerator"
import OceanBase from "./OceanBase"
import Order from "./Order"
import ServiceAgreement from "./ServiceAgreement"
export default class Asset extends OceanBase {
@ -15,42 +13,15 @@ export default class Asset extends OceanBase {
super()
}
public async purchase(consumer: Account, timeout: number): Promise<Order> {
const {token, market, auth} = await Keeper.getInstance()
public async purchase(consumer: Account): Promise<ServiceAgreement> {
const key = EthCrypto.createIdentity()
const publicKey = EthjsUtil.privateToPublic(key.privateKey).toString("hex")
const price = await market.getAssetPrice(this.getId())
const isValid = await market.isAssetActive(this.getId())
const did = `did:op:${this.getId()}`
const ddo = await AquariusProvider.getAquarius().retrieveDDO(did)
Logger.log("The asset:", this.getId(), "is it valid?", isValid, "it's price is:", price)
const serviceAgreementId: string = IdGenerator.generateId()
const serviceAgreement: ServiceAgreement = await ServiceAgreement.createServiceAgreement(this.getId(),
ddo, serviceAgreementId, consumer, this.publisher)
if (!isValid) {
throw new Error("The Asset is not valid!")
}
try {
const marketAddr = market.getAddress()
// Allow market contract to transfer funds on the consumer"s behalf
await token.approve(marketAddr, price, consumer.getId())
Logger.log(`${price} tokens approved on market with id: ${marketAddr}`)
} catch (err) {
Logger.error("token.approve failed", err)
}
let order: Order
try {
// Submit the access request
const initiateAccessRequestReceipt = await auth.initiateAccessRequest(this,
publicKey, timeout, consumer.getId())
const {returnValues} = initiateAccessRequestReceipt.events.AccessConsentRequested
Logger.log(`Keeper AccessConsentRequested event received on asset: ${this.getId()}`)
order = new Order(this, returnValues._timeout, returnValues._pubKey, key)
order.setId(returnValues._id)
} catch (err) {
Logger.error("auth.initiateAccessRequest failed", err)
}
return order
return serviceAgreement
}
}

View File

@ -1,14 +1,16 @@
import AquariusProvider from "../aquarius/AquariusProvider"
import SearchQuery from "../aquarius/query/SearchQuery"
import ConfigProvider from "../ConfigProvider"
import Condition from "../ddo/Condition"
import DDO from "../ddo/DDO"
import Service from "../ddo/Service"
import Keeper from "../keeper/Keeper"
import Web3Provider from "../keeper/Web3Provider"
import Config from "../models/Config"
import SecretStoreProvider from "../secretstore/SecretStoreProvider"
import Logger from "../utils/Logger"
import Account from "./Account"
import Asset from "./Asset"
import IdGenerator from "./IdGenerator"
import Order from "./Order"
import ServiceAgreementTemplate from "./ServiceAgreementTemplate"
export default class Ocean {
@ -37,71 +39,71 @@ export default class Ocean {
return ethAccounts.map((address: string) => new Account(address))
}
public async register(asset: Asset): Promise<string> {
public async register(asset: Asset): Promise<DDO> {
const {market} = this.keeper
const secretStore = SecretStoreProvider.getSecretStore()
const assetId: string = IdGenerator.generateId()
const did: string = `did:op:${assetId}`
const assetId = IdGenerator.generateId()
const methods: string[] = [
"PaymentConditions.lockPayment",
"AccessConditions.grantAccess",
"PaymentConditions.releasePayment",
"PaymentConditions.refundPayment",
]
// tslint:disable
const dependencyMatrix = [0, 1, 4, 1 | 2 ** 4 | 2 ** 5] // dependency bit | timeout bit
const encryptedDocument = await secretStore.encryptDocument(assetId, asset)
const serviceName = "Access"
const saTemplate: ServiceAgreementTemplate =
await ServiceAgreementTemplate.registerServiceAgreementsTemplate(serviceName, methods, dependencyMatrix,
asset.publisher)
const decryptedDocument = await secretStore.decryptDocument(assetId, encryptedDocument)
// get condition keys from template
const conditionKeys: string[] = saTemplate.getConditionKeys()
Logger.log(decryptedDocument, encryptedDocument)
// generate an id
Logger.log(`Registering: ${assetId} with price ${asset.price} for ${asset.publisher.getId()}`)
asset.setId(assetId)
const isAssetActive = await market.isAssetActive(assetId)
// register asset in the market
if (!isAssetActive) {
const result = await market.register(asset.getId(), asset.price, asset.publisher.getId())
Logger.log("Registered:", assetId, "in block", result.blockNumber)
} else {
throw new Error("Asset already registered")
}
return assetId
}
public async getOrdersByAccount(consumer: Account): Promise<Order[]> {
const {auth} = this.keeper
Logger.log("Getting orders")
const accessConsentRequestedData = await auth.getEventData(
"AccessConsentRequested", {
filter: {
_consumer: consumer.getId(),
// create ddo conditions out of the keys
const conditions: Condition[] = conditionKeys.map((conditionKey, i): Condition => {
return {
name: methods[i].split(".")[1],
timeout: 100,
conditionKey: conditionKey,
parameters: {
// todo wtf?
assetId: "bytes32",
price: "integer"
},
fromBlock: 0,
toBlock: "latest",
})
} as Condition
})
const orders = await Promise.all(
accessConsentRequestedData
.map(async (event: any) => {
// create ddo itself
const ddo: DDO = new DDO({
id: did,
service: [
{
type: serviceName,
// tslint:disable
serviceEndpoint: "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
purchaseEndpoint: "http://mybrizo.org/api/v1/brizo/services/access/purchase?",
// the id of the service agreement?
serviceDefinitionId: "0x" + IdGenerator.generateId(),
// the id of the service agreement template
templateId: saTemplate.getId(),
conditions,
} as Service,
],
})
const {returnValues} = event
const order: Order = new Order(
null,
parseInt(returnValues._timeout, 10),
null, null)
await AquariusProvider.getAquarius().storeDDO(ddo)
asset.setId(assetId)
order.setId(returnValues._id)
return order
}),
)
// Logger.log("Got orders:", JSON.stringify(orders, null, 2))
Logger.log(`Got ${Object.keys(orders).length} orders`)
return orders
await market.register(assetId, asset.price, asset.publisher.getId())
return ddo
}
public async searchAssets(query): Promise<any[]> {
public async searchAssets(query: SearchQuery): Promise<any[]> {
return AquariusProvider.getAquarius().queryMetadata(query)
}
}

View File

@ -1,57 +1,86 @@
import DDO from "../ddo/DDO"
import AccessConditions from "../keeper/contracts/conditions/AccessConditions"
import ServiceAgreementContract from "../keeper/contracts/ServiceAgreement"
import Web3Provider from "../keeper/Web3Provider"
import Account from "./Account"
import IdGenerator from "./IdGenerator"
import OceanBase from "./OceanBase"
import ServiceAgreementTemplate from "./ServiceAgreementTemplate"
export default class ServiceAgreement extends OceanBase {
public static async createServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, assetId: string,
did: string, consumer: Account, publisher: Account) {
public static async createServiceAgreement(assetId: string, ddo: DDO, serviceAgreementId: string, consumer: Account,
publisher: Account):
Promise<ServiceAgreement> {
const timeoutValues: number[] = ddo.service[0].conditions.map((condition) => {
return condition.timeout
})
// todo: this should come from ddo
const serviceAgreementId = IdGenerator.generateId()
const timeoutValues = [0, 0, 0, 500] // timeout 500 blocks @ condition 4
const values = [
{type: "bool", value: true},
{type: "bool", value: false},
{type: "uint", value: 120},
{type: "string", value: assetId},
{type: "string", value: serviceAgreementId},
]
const saHashSig = await ServiceAgreement.createSAHashSignature(serviceAgreementTemplate, serviceAgreementId,
values, timeoutValues, consumer)
const serviceAgreementHashSignature = await ServiceAgreement.createSAHashSignature(ddo, serviceAgreementId,
consumer)
const serviceAgreement: ServiceAgreement = await ServiceAgreement.signServiceAgreement(serviceAgreementTemplate,
serviceAgreementId, assetId, did, values, timeoutValues, saHashSig, consumer, publisher)
const serviceAgreement: ServiceAgreement = await ServiceAgreement.signServiceAgreement(ddo,
serviceAgreementId, values, timeoutValues, serviceAgreementHashSignature, consumer, publisher)
return serviceAgreement
}
private static async signServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate,
serviceAgreementId: string, assetId: string, did: string, values: any[],
public static async createSAHashSignature(ddo: DDO, serviceAgreementId: string, consumer: Account):
Promise<string> {
// todo get from ddo
const values = [
{type: "bool", value: true},
{type: "bool", value: false},
{type: "uint", value: 120},
{type: "string", value: serviceAgreementId},
]
const valueHashes = ServiceAgreement.createValueHashes(values)
const conditionKeys: string[] = ddo.service[0].conditions.map((condition) => {
return condition.conditionKey
})
const timeoutValues: number[] = ddo.service[0].conditions.map((condition) => {
return condition.timeout
})
const serviceAgreementHash = ServiceAgreement.hashServiceAgreement(ddo.service[0].templateId,
serviceAgreementId, conditionKeys, valueHashes, timeoutValues)
const serviceAgreementHashSignature =
await Web3Provider.getWeb3().eth.sign(serviceAgreementHash, consumer.getId())
return serviceAgreementHashSignature
}
private static async signServiceAgreement(ddo: DDO, serviceAgreementId: string, values: any[],
timeoutValues: number[], serviceAgreementHashSignature: string,
consumer: Account, publisher: Account):
Promise<ServiceAgreement> {
const valueHashes = ServiceAgreement.createValueHashes(values)
const serviceAgreement: ServiceAgreementContract = await ServiceAgreementContract.getInstance()
const executeAgreementReceipt = await serviceAgreement.executeAgreement(
serviceAgreementTemplate.getId(), serviceAgreementHashSignature, consumer.getId(), valueHashes,
timeoutValues, serviceAgreementId, did, publisher.getId())
ddo.service[0].templateId, serviceAgreementHashSignature, consumer.getId(), valueHashes,
timeoutValues, serviceAgreementId, ddo.id, publisher.getId())
if (executeAgreementReceipt.events.ExecuteAgreement.returnValues.state === false) {
throw new Error("signing service agreement failed.")
}
return new ServiceAgreement(
serviceAgreementId,
executeAgreementReceipt.events.ExecuteAgreement.returnValues.serviceAgreementId,
ddo,
publisher,
serviceAgreementTemplate,
consumer,
executeAgreementReceipt.events.ExecuteAgreement.returnValues.state,
executeAgreementReceipt.events.ExecuteAgreement.returnValues.status,
@ -69,43 +98,30 @@ export default class ServiceAgreement extends OceanBase {
return Web3Provider.getWeb3().utils.soliditySha3(args).toString("hex")
}
private static async createSAHashSignature(serviceAgreementTemplate: ServiceAgreementTemplate,
serviceAgreementId: string, values: any[], timeoutValues: number[],
consumer: Account): Promise<string> {
const valueHashes = ServiceAgreement.createValueHashes(values)
const serviceAgreementHash = ServiceAgreement.hashServiceAgreement(serviceAgreementTemplate, valueHashes,
timeoutValues, serviceAgreementId)
const serviceAgreementHashSignature =
await Web3Provider.getWeb3().eth.sign(serviceAgreementHash, consumer.getId())
return serviceAgreementHashSignature
}
private static hashServiceAgreement(serviceAgreementTemplate: ServiceAgreementTemplate, valueHashes: string[],
timeouts: number[], serviceAgreementId: string) {
private static hashServiceAgreement(serviceAgreementTemplateId: string, serviceAgreementId: string,
conditionKeys: string[], valueHashes: string[], timeouts: number[]) {
const args = [
{type: "bytes32", value: serviceAgreementTemplate.getId()},
{type: "bytes32[]", value: serviceAgreementTemplate.getConditionKeys()},
{type: "bytes32", value: serviceAgreementTemplateId},
{type: "bytes32[]", value: conditionKeys},
{type: "bytes32[]", value: valueHashes},
{type: "uint256[]", value: timeouts},
{type: "bytes32", value: "0x" + serviceAgreementId},
{type: "bytes32", value: serviceAgreementId},
]
return Web3Provider.getWeb3().utils.soliditySha3(...args).toString("hex")
}
private constructor(id: string, private publisher: Account, serviceAgreementTemplate: ServiceAgreementTemplate,
consumer: Account, state: boolean, status: boolean) {
super(id)
private constructor(serviceAgreementId: string, ddo: DDO, private publisher: Account, consumer: Account,
state: boolean, status: boolean) {
super(serviceAgreementId)
}
public async grantAccess(assetId: string, documentId: string): Promise<boolean> {
const accessConditions: AccessConditions = await AccessConditions.getInstance()
const grantAccessReceipt =
await accessConditions.grantAccess(this.getId(), assetId, documentId, this.publisher.getId())
await accessConditions.grantAccess(this.getId(), assetId, documentId,
this.publisher.getId())
return grantAccessReceipt.status
}

View File

@ -25,11 +25,12 @@ export default class ServiceAgreementTemplate extends OceanBase {
Web3Provider.getWeb3().utils.fromAscii(serviceName),
templateOwner.getId())
const id = receipt.events.SetupAgreementTemplate.returnValues.serviceTemplateId
const serviceAgreementTemplateId =
receipt.events.SetupAgreementTemplate.returnValues.serviceTemplateId
return new ServiceAgreementTemplate(
id,
ServiceAgreementTemplate.generateConditionsKeys(id, methodReflections),
serviceAgreementTemplateId,
ServiceAgreementTemplate.generateConditionsKeys(serviceAgreementTemplateId, methodReflections),
templateOwner)
}
@ -47,17 +48,15 @@ export default class ServiceAgreementTemplate extends OceanBase {
return conditions
}
private constructor(id, private conditionKeys: string[], private owner: Account) {
super(id)
private constructor(serviceAgreementTemplateId, private conditionKeys: string[], private owner: Account) {
super(serviceAgreementTemplateId)
}
/**
* gets the status of a service agreement template
*/
public async getStatus(): Promise<boolean> {
const serviceAgreement: ServiceAgreement = await ServiceAgreement.getInstance()
return serviceAgreement.getTemplateStatus(this.getId())
}

View File

@ -8,7 +8,7 @@ export default class SecretStoreProvider {
SecretStoreProvider.secretStore = secretStore
}
public static getSecretStore() {
public static getSecretStore(): SecretStore {
if (!SecretStoreProvider.secretStore) {
SecretStoreProvider.secretStore = new SecretStore(ConfigProvider.getConfig())

View File

@ -1,3 +1,4 @@
import Account from "./ocean/Account"
import Asset from "./ocean/Asset"
import Ocean from "./ocean/Ocean"
import Order from "./ocean/Order"
@ -8,4 +9,5 @@ export {
Order,
Asset,
Logger,
Account,
}

View File

@ -1,25 +1,28 @@
import {assert} from "chai"
import AquariusConnectorProvider from "../../src/aquarius/AquariusConnectorProvider"
import AquariusProvider from "../../src/aquarius/AquariusProvider"
import ConfigProvider from "../../src/ConfigProvider"
import DDO from "../../src/ddo/DDO"
import ContractHandler from "../../src/keeper/ContractHandler"
import Account from "../../src/ocean/Account"
import Asset from "../../src/ocean/Asset"
import Ocean from "../../src/ocean/Ocean"
import Order from "../../src/ocean/Order"
import ServiceAgreement from "../../src/ocean/ServiceAgreement"
import SecretStoreProvider from "../../src/secretstore/SecretStoreProvider"
import config from "../config"
import AquariusMock from "../mocks/Aquarius.mock"
import AquariusConnectorMock from "../mocks/AquariusConnector.mock"
import SecretStoreMock from "../mocks/SecretStore.mock"
const testName = "Test Asset 2"
const testDescription = "This asset is pure owange"
const testPrice = 100
const timeout = 100000
let ocean: Ocean
let testAsset: Asset
let accounts: Account[]
let testPublisher: Account
let ddo: DDO
describe("Asset", () => {
@ -33,17 +36,30 @@ describe("Asset", () => {
testPublisher = accounts[0]
testAsset = new Asset(testName, testDescription, testPrice, testPublisher)
await ocean.register(testAsset)
ddo = await ocean.register(testAsset)
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
})
describe("#purchase()", () => {
it("should purchase an asset", async () => {
// todo
const consumerAccount = accounts[5]
const order: Order = await testAsset.purchase(consumerAccount, timeout)
assert(order)
const serviceAgreement: ServiceAgreement = await testAsset.purchase(consumerAccount)
assert(serviceAgreement)
})
it("should purchase an asset from two different customers", async () => {
const consumerAccount1 = accounts[5]
const serviceAgreement1: ServiceAgreement = await testAsset.purchase(consumerAccount1)
assert(serviceAgreement1)
const consumerAccount2 = accounts[6]
const serviceAgreement2: ServiceAgreement = await testAsset.purchase(consumerAccount2)
assert(serviceAgreement2)
})
})
})

View File

@ -1,11 +1,12 @@
import {assert} from "chai"
import AquariusProvider from "../../src/aquarius/AquariusProvider"
import SearchQuery from "../../src/aquarius/query/SearchQuery"
import ConfigProvider from "../../src/ConfigProvider"
import DDO from "../../src/ddo/DDO"
import ContractHandler from "../../src/keeper/ContractHandler"
import Account from "../../src/ocean/Account"
import Asset from "../../src/ocean/Asset"
import Ocean from "../../src/ocean/Ocean"
import Order from "../../src/ocean/Order"
import SecretStoreProvider from "../../src/secretstore/SecretStoreProvider"
import config from "../config"
import AquariusMock from "../mocks/Aquarius.mock"
@ -13,13 +14,11 @@ import SecretStoreMock from "../mocks/SecretStore.mock"
let ocean: Ocean
let accounts: Account[]
let testAsset: Asset
let testPublisher: Account
const name = "Test Asset 3"
const name = "Test Asset 3" + Math.random().toString()
const description = "This asset is pure owange"
const price = 100
const timeout = 100000000
describe("Ocean", () => {
@ -32,18 +31,16 @@ describe("Ocean", () => {
accounts = await ocean.getAccounts()
testPublisher = accounts[0]
testAsset = new Asset(name, description, price, testPublisher)
})
describe("#getInstance()", () => {
it("should list accounts", async () => {
it("should get an instance of cean", async () => {
const ocn = Ocean.getInstance(config)
const oceanInstance: Ocean = await Ocean.getInstance(config)
assert(ocn)
assert(oceanInstance)
})
})
describe("#getAccounts()", () => {
@ -63,31 +60,13 @@ describe("Ocean", () => {
it("should register an asset", async () => {
const assetId: string = await ocean.register(testAsset)
const asset: Asset = new Asset(name, description, price, testPublisher)
const ddo: DDO = await ocean.register(asset)
assert(assetId.length === 64)
assert(!assetId.startsWith("0x"))
assert(ddo.id.startsWith("did:op:"))
})
})
describe("#getOrdersByConsumer()", () => {
it("should list orders", async () => {
const testConsumer = accounts[1]
const asset: Asset = new Asset("getOrdersByConsumer test", description, price, testPublisher)
await ocean.register(asset)
const order: Order = await asset.purchase(testConsumer, timeout)
const orders = await ocean.getOrdersByAccount(testConsumer)
assert(orders.length === 1)
assert(orders[0].getId() === order.getId())
})
})
describe("#searchAssets()", () => {
it("should search for assets", async () => {
@ -102,7 +81,7 @@ describe("Ocean", () => {
value: 1,
},
text: "Office",
}
} as SearchQuery
const assets: any[] = await ocean.searchAssets(query)

View File

@ -1,104 +0,0 @@
import {assert} from "chai"
import AquariusProvider from "../../src/aquarius/AquariusProvider"
import ConfigProvider from "../../src/ConfigProvider"
import ContractHandler from "../../src/keeper/ContractHandler"
import AccessStatus from "../../src/models/AccessStatus"
import Account from "../../src/ocean/Account"
import Asset from "../../src/ocean/Asset"
import Ocean from "../../src/ocean/Ocean"
import Order from "../../src/ocean/Order"
import config from "../config"
import AquariusMock from "../mocks/Aquarius.mock"
import * as AccessToken from "../testdata/AccessToken.json"
const testName = "Order Test Asset"
const testDescription = "This asset is pure owange"
const testPrice = 100
const timeout = 1000000
let ocean: Ocean
let testAsset: Asset
let accounts: Account[]
let testPublisher: Account
let testConsumer: Account
describe("Order", () => {
before(async () => {
ConfigProvider.setConfig(config)
AquariusProvider.setAquarius(new AquariusMock(config))
await ContractHandler.deployContracts()
ocean = await Ocean.getInstance(config)
accounts = await ocean.getAccounts()
testPublisher = accounts[0]
testConsumer = accounts[1]
// register an asset to play around with
testAsset = new Asset(testName, testDescription, testPrice, testPublisher)
await ocean.register(testAsset)
})
describe("#pay()", async () => {
it("should pay for an order", async () => {
const order: Order = await testAsset.purchase(testConsumer, timeout)
assert(order)
await order.commit(AccessToken.toString())
await testConsumer.requestTokens(testAsset.price)
const paymentId: string = await order.pay(testConsumer)
assert(paymentId)
})
})
describe("#commit()", async () => {
it("should commit the order", async () => {
const order: Order = await testAsset.purchase(testConsumer, timeout)
assert(order)
await order.commit(AccessToken.toString())
})
})
describe("#getStatus()", async () => {
it("should get status Requested on new order", async () => {
const order: Order = await testAsset.purchase(testConsumer, timeout)
assert(order)
const status: AccessStatus = await order.getStatus()
assert(status === AccessStatus.Requested)
})
it("should get status Delivered on commited order", async () => {
const order: Order = await testAsset.purchase(testConsumer, timeout)
assert(order)
await order.commit(AccessToken.toString())
const status: AccessStatus = await order.getStatus()
assert(status === AccessStatus.Delivered)
})
})
describe("#consume()", () => {
it("should consume an asset", async () => {
const consumerAccount = accounts[5]
await consumerAccount.requestTokens(testAsset.price)
// place order - consumer
const order: Order = await testAsset.purchase(consumerAccount, timeout)
// commit order - provider
await order.commit(AccessToken.toString())
// pay order - consumer
await order.pay(consumerAccount)
const url = await order.consume(consumerAccount)
assert(url)
})
})
})

View File

@ -1,5 +1,7 @@
import {assert} from "chai"
import AquariusConnectorProvider from "../../src/aquarius/AquariusConnectorProvider"
import ConfigProvider from "../../src/ConfigProvider"
import DDO from "../../src/ddo/DDO"
import ContractHandler from "../../src/keeper/ContractHandler"
import Account from "../../src/ocean/Account"
import IdGenerator from "../../src/ocean/IdGenerator"
@ -7,6 +9,9 @@ import Ocean from "../../src/ocean/Ocean"
import ServiceAgreement from "../../src/ocean/ServiceAgreement"
import ServiceAgreementTemplate from "../../src/ocean/ServiceAgreementTemplate"
import config from "../config"
import AquariusConnectorMock from "../mocks/AquariusConnector.mock"
import Service from "../../src/ddo/Service"
import Condition from "../../src/ddo/Condition"
let ocean: Ocean
let accounts: Account[]
@ -15,6 +20,7 @@ let templateOwnerAccount: Account
let consumerAccount: Account
let testServiceAgreementTemplate: ServiceAgreementTemplate
let serviceDefintion
describe("ServiceAgreement", () => {
@ -35,42 +41,79 @@ describe("ServiceAgreement", () => {
"PaymentConditions.releasePayment",
"PaymentConditions.refundPayment",
]
// tslint:disable
const dependencyMatrix = [0, 1, 4, 1 | 2 ** 4 | 2 ** 5] // dependency bit | timeout bit
testServiceAgreementTemplate =
await ServiceAgreementTemplate.registerServiceAgreementsTemplate(resourceName, methods,
dependencyMatrix, templateOwnerAccount)
// get condition keys from template
const conditionKeys: string[] = testServiceAgreementTemplate.getConditionKeys()
// create ddo conditions out of the keys
const conditions: Condition[] = conditionKeys.map((conditionKey, i): Condition => {
return {
name: methods[i].split(".")[1],
timeout: 100,
conditionKey: conditionKey,
parameters: {
// todo wtf?
assetId: "bytes32",
price: "integer"
},
} as Condition
})
serviceDefintion = [
{
serviceDefinitionId: IdGenerator.generateId(),
templateId: testServiceAgreementTemplate.getId(),
conditions,
} as Service
]
})
describe("#createServiceAgreement()", () => {
it("should execute an service agreement", async () => {
const did: string = IdGenerator.generateId()
const id: string = IdGenerator.generateId()
const did: string = `did:op:${id}`
const ddo = new DDO({id: did, service: serviceDefintion})
const assetId: string = IdGenerator.generateId()
const serviceAgreementId: string = IdGenerator.generateId()
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const serviceAgreement: ServiceAgreement =
await ServiceAgreement.createServiceAgreement(testServiceAgreementTemplate, assetId, did,
consumerAccount, publisherAccount)
await ServiceAgreement.createServiceAgreement(assetId, ddo, serviceAgreementId, consumerAccount,
publisherAccount)
assert(serviceAgreement)
const id = serviceAgreement.getId()
assert(id)
assert(id !== did)
const serviceDefinitionId = serviceAgreement.getId()
assert(serviceDefinitionId)
assert(serviceDefinitionId !== did)
})
})
describe("#getStatus()", () => {
it("should get the status of a newly created service agreement", async () => {
const did: string = IdGenerator.generateId()
const id: string = IdGenerator.generateId()
const did: string = `did:op:${id}`
const ddo = new DDO({id: did, service: serviceDefintion})
const assetId: string = IdGenerator.generateId()
const serviceAgreementId: string = IdGenerator.generateId()
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const serviceAgreement: ServiceAgreement =
await ServiceAgreement.createServiceAgreement(testServiceAgreementTemplate, assetId, did,
consumerAccount, publisherAccount)
await ServiceAgreement.createServiceAgreement(assetId, ddo, serviceAgreementId, consumerAccount,
publisherAccount)
assert(serviceAgreement)
const status = await serviceAgreement.getStatus()
assert(status === false)
})
@ -79,15 +122,20 @@ describe("ServiceAgreement", () => {
describe("#grantAccess()", () => {
it("should grant access in that service agreement", async () => {
const did: string = IdGenerator.generateId()
const id: string = IdGenerator.generateId()
const did: string = `did:op:${id}`
const ddo = new DDO({id: did, service: serviceDefintion})
const assetId: string = IdGenerator.generateId()
const serviceAgreementId: string = IdGenerator.generateId()
// @ts-ignore
AquariusConnectorProvider.setConnector(new AquariusConnectorMock(ddo))
const serviceAgreement: ServiceAgreement =
await ServiceAgreement.createServiceAgreement(testServiceAgreementTemplate, assetId, did,
consumerAccount, publisherAccount)
await ServiceAgreement.createServiceAgreement(assetId, ddo, serviceAgreementId, consumerAccount,
publisherAccount)
assert(serviceAgreement)
const fulfilled: boolean = await serviceAgreement.grantAccess(did, IdGenerator.generateId())
const fulfilled: boolean = await serviceAgreement.grantAccess(assetId, IdGenerator.generateId())
assert(fulfilled)
})
})

175
test/testdata/ddo.json vendored
View File

@ -1,6 +1,6 @@
{
"@context": "https://w3id.org/future-method/v1",
"id": "did:op:123456789abcdefghi",
"id": "did:op:08a429b8529856d59867503f8056903a680935a76950bb9649785cc97869a43d",
"publicKey": [
{
"id": "did:op:123456789abcdefghi#keys-1",
@ -31,51 +31,135 @@
"publicKey": "did:op:123456789abcdefghi#keys-2"
}
],
"proof": {
"type": "UUIDSignature",
"created": "2016-02-08T16:02:20Z",
"creator": "did:example:8uQhQMGzWxR8vw5P3UWH1ja",
"signatureValue": "QNB13Y7Q9...1tzjn4w=="
},
"service": [
{
"type": "OpenIdConnectVersion1.0Service",
"serviceEndpoint": "https://openid.example.com/"
"type": "Access",
"serviceDefinitionId": "0",
"serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}",
"purchaseEndpoint": "http://mybrizo.org/api/v1/brizo/services/access/purchase?",
"templateId": "044852b2a670ade5407e78fb2863c51000000000000000000000000000000000",
"conditions": [
{
"name": "lockPayment",
"timeout": 0,
"conditionKey": {
"contractAddress": "0x...",
"fingerprint": "0x..."
},
"parameters": {
"assetId": "bytes32",
"price": "integer"
},
"events": {
"PaymentLocked": {
"actorType": [
"publisher"
],
"handlers": [
{
"moduleName": "accessControl",
"functionName": "grantAccess",
"version": "0.1"
}
]
}
}
},
{
"name": "releasePayment",
"timeout": 0,
"conditionKey": {
"contractAddress": "0x...",
"fingerprint": "0xXXXXXXXX"
},
"parameters": {
"assetId": "bytes32",
"price": "integer"
},
"events": {
"PaymentReleased": {
"actorType": [
"publisher"
],
"handlers": [
{
"moduleName": "serviceAgreement",
"functionName": "fulfillAgreement",
"version": "0.1"
}
]
}
}
},
{
"name": "grantAccess",
"timeout": 0,
"conditionKey": {
"contractAddress": "0x",
"fingerprint": "0xXXXXXXXX"
},
"parameters": {
"assetId": "bytes32",
"documentKeyId": "bytes32"
},
"events": {
"AccessGranted": {
"actorType": [
"consumer"
],
"handlers": [
{
"moduleName": "asset",
"functionName": "consumeService",
"version": "0.1"
}
]
}
}
},
{
"name": "refundPayment",
"timeout": 1,
"condition_key": {
"contractAddress": "0x...",
"fingerprint": "0xXXXXXXXX"
},
"parameters": {
"assetId": "bytes32",
"price": "int"
},
"events": {
"PaymentRefund": {
"actorType": [
"consumer"
],
"handlers": [
{
"moduleName": "serviceAgreement",
"functionName": "fulfillAgreement",
"version": "0.1"
}
]
}
}
}
]
},
{
"type": "CredentialRepositoryService",
"serviceEndpoint": "https://repository.example.com/service/8377464"
},
{
"type": "XdiService",
"serviceEndpoint": "https://xdi.example.com/8377464"
},
{
"type": "HubService",
"serviceEndpoint": "https://hub.example.com/.identity/did:op:0123456789abcdef/"
},
{
"type": "MessagingService",
"serviceEndpoint": "https://example.com/messages/8377464"
},
{
"type": "SocialWebInboxService",
"serviceEndpoint": "https://social.example.com/83hfh37dj",
"description": "My public social inbox",
"spamCost": {
"amount": "0.50",
"currency": "USD"
}
},
{
"id": "did:op:123456789abcdefghi;bops",
"type": "BopsService",
"serviceEndpoint": "https://bops.example.com/enterprise/"
},
{
"type": "Consume",
"serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/consume?pubKey=${pubKey}&serviceId={serviceId}&url={url}"
},
{
"type": "Compute",
"serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}"
"type": "CloudCompute",
"serviceDefinitionId": "1",
"serviceEndpoint": "http://mybrizo.org/api/v1/brizo/services/compute?pubKey=${pubKey}&serviceId={serviceId}&algo={algo}&container={container}",
"templateId": "044852b2a670ade5407e78fb2863c51000000000000000000000000000000002"
},
{
"type": "Metadata",
"serviceDefinitionId": "2",
"serviceEndpoint": "http://myaquarius.org/api/v1/provider/assets/metadata/{did}",
"metadata": {
"base": {
@ -96,13 +180,14 @@
],
"links": [
{
"sample1": "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-daily/"
"name": "Sample of Asset Data",
"type": "sample",
"url": "https://foo.com/sample.csv"
},
{
"sample2": "http://data.ceda.ac.uk/badc/ukcp09/data/gridded-land-obs/gridded-land-obs-averages-25km/"
},
{
"fieldsDescription": "http://data.ceda.ac.uk/badc/ukcp09/"
"name": "Data Format Definition",
"type": "format",
"AssetID": "4d517500da0acb0d65a716f61330969334630363ce4a6a9d39691026ac7908ea"
}
],
"inLanguage": "en",
@ -130,4 +215,4 @@
}
}
]
}
}