diff --git a/app/installHelper.js b/app/installHelper.js index ab5eae8..508d8aa 100644 --- a/app/installHelper.js +++ b/app/installHelper.js @@ -21,9 +21,9 @@ export const installs = async (chaincodeId, orgName, peerIndexes = Object.keys(g } const user = helper.getOrgAdmin(orgName); const [result, t1] = await install(peers, {chaincodeId}, user); - const ids = result.responses.map(({response})=> response.package_id) - assert.ok(isEven(ids)) - const packageID = ids[0] + const ids = result.responses.map(({response}) => response.package_id); + assert.ok(isEven(ids)); + const packageID = ids[0]; t1(); for (const peer of peers) { peer.disconnect(); @@ -66,9 +66,11 @@ export class ChaincodeDefinitionOperator { constructor(channelName, admin, peers, init_required) { const channel = helper.prepareChannel(channelName); this.waitForConsensus = 1000; - const chaincodeAction = new ChaincodeAction(peers, admin, channel); + const chaincodeAction = new ChaincodeAction(peers, admin, channel, logger); chaincodeAction.init_required = !!init_required; - Object.assign(this, {chaincodeAction, peers, admin, channel}); + this.forceUpgrade = true; + Object.assign(this, {chaincodeAction, peers, admin, channel, channelName}); + } async init(chaincodeId, orderer) { @@ -80,12 +82,12 @@ export class ChaincodeDefinitionOperator { await tx.submit({init: true}, orderer); } - async approves({sequence, PackageID}, orderer, gate) { + async approves({sequence, package_id}, orderer, gate) { const {waitForConsensus, chaincodeAction} = this; await orderer.connect(); - const {name} = parsePackageID(PackageID); + const {name} = parsePackageID(package_id); const endorsementPolicy = { gate @@ -95,12 +97,19 @@ export class ChaincodeDefinitionOperator { chaincodeAction.setEndorsementPolicy(endorsementPolicy); chaincodeAction.setCollectionsConfig(getCollectionConfig(name)); try { - await chaincodeAction.approve({name, PackageID, sequence}, orderer, waitForConsensus); + await chaincodeAction.approve({name, package_id, sequence}, orderer, waitForConsensus); } finally { orderer.disconnect(); } } + /** + * + * @param sequence + * @param name + * @param orderer + * @param [gate] + */ async commitChaincodeDefinition({sequence, name}, orderer, gate) { const {chaincodeAction} = this; await orderer.connect(); @@ -128,9 +137,14 @@ export class ChaincodeDefinitionOperator { return readyStates[0]; } - async queryDefinition(name) { + async queryDefinition(chaincodeID) { const {chaincodeAction} = this; - return await chaincodeAction.queryChaincodeDefinition(name); + const results = await chaincodeAction.queryChaincodeDefinition(chaincodeID); + if (results) { + results.every(e => assert.deepEqual(e, results[0])); + return results[0]; + } + } async connect() { @@ -147,69 +161,70 @@ export class ChaincodeDefinitionOperator { } } - async queryInstalled(label, packageId) { + async queryInstalled(label) { const {peers, admin} = this; - if (packageId && !label) { - label = parsePackageID(packageId).label; - } + const queryHub = new QueryHub(peers, admin); - const queryResult = await queryHub.chaincodesInstalled(label, packageId); - for (const entry of queryResult) { - const PackageIDs = Object.keys(entry); - if (packageId) { - assert.strictEqual(packageId, PackageIDs[0]); - assert.ok(PackageIDs.length === 1); - } - for (const [_packageid, moreInfo] of Object.entries(entry)) { - if (Object.keys(moreInfo).length === 0) { - logger.info(_packageid, 'installed while not deployed'); - } else { - for (const [channelName, {chaincodes}] of Object.entries(moreInfo)) { + const queryResults = await queryHub.chaincodesInstalled(label); + assert.ok(isEven(queryResults), 'chaincodesInstalled results should be even'); + const queryResult = queryResults[0]; + + const uncommitted = [], committed = []; + for (const [package_id, moreInfo] of Object.entries(queryResult)) { + if (Object.keys(moreInfo).length === 0) { + logger.info(package_id, 'installed while not committed'); + uncommitted.push(package_id); + } else { + + for (const [channelName, {chaincodes}] of Object.entries(moreInfo)) { + if (channelName === this.channelName) { for (const {name, version} of chaincodes) { assert.strictEqual(name, label); - logger.info(_packageid, channelName, {version}); + committed.push({package_id, version}); } - } } - } + } + + return [queryResult, uncommitted, committed]; + } + async queryAndCommit(chaincodeID, orderer) { + const isCommitted = await this.queryDefinition(chaincodeID); + + let sequence = 1; + if (isCommitted) { + sequence = isCommitted.sequence + 1; } - return queryResult; + await this.commitChaincodeDefinition({name: chaincodeID, sequence}, orderer); + } /** * * @param {string} chaincodeId - * @param {number} sequence * @param {Orderer} _orderer * @param {string} [_gate] */ - async queryInstalledAndApprove(chaincodeId, sequence, _orderer, _gate) { + async queryInstalledAndApprove(chaincodeId, _orderer, _gate) { - const {peers, admin} = this; + const [_, uncommitted, committed] = await this.queryInstalled(chaincodeId); - const queryHub = new QueryHub(peers, admin); - const queryResult = await queryHub.chaincodesInstalled(chaincodeId); - let PackageID; - for (const entry of queryResult) { - const PackageIDs = Object.keys(entry); - if (PackageIDs.length > 1) { - logger.error(queryResult); - logger.error({PackageIDs: PackageIDs}); - // TODO to be smarter reducer - throw Error('found multiple installed packageID, could not decide which to approve'); + const isCommitted = await this.queryDefinition(chaincodeId); - } else { - if (PackageID) { - assert.strictEqual(PackageID, PackageIDs[0]); - } - PackageID = PackageIDs[0]; - } + let sequence = 1; + if (isCommitted) { + sequence = isCommitted.sequence + 1; + } + for (const package_id of uncommitted) { + await this.approves({package_id, sequence}, _orderer, _gate); } - if (PackageID) { - await this.approves({PackageID, sequence}, _orderer, _gate); + if (uncommitted.length === 0 && this.forceUpgrade) { + // force update + for (const package_id of committed.map(({package_id}) => package_id)) { + await this.approves({package_id, sequence}, _orderer, _gate); + } } } diff --git a/cc/golang/contracts.js b/cc/golang/contracts.js index 84f1daa..92300b0 100644 --- a/cc/golang/contracts.js +++ b/cc/golang/contracts.js @@ -4,6 +4,7 @@ import {installAll, ChaincodeDefinitionOperator} from '../../app/installHelper.j import FabricGateway from '../../common/nodejs/fabric-gateway/index.js'; import {consoleLogger} from '@davidkhala/logger/log4.js'; import UserBuilder from '../../common/nodejs/admin/user.js'; +import {dev} from '../testutil.js'; const chaincodeID = 'contracts'; const logger = consoleLogger(`chaincode:${chaincodeID}`); @@ -19,33 +20,40 @@ describe('deploy', function () { it('install', async () => { await installAll(chaincodeID); }); - const sequence = 1; + it('dev', async () => { + const orgs = ['icdd', 'astri.org']; + for (const org of orgs) { + await dev(org, chaincodeID); + } + }); it('query installed & approve', async () => { const orgs = ['icdd', 'astri.org']; for (const org of orgs) { + // TODO migrate to testutil.js const admin = helper.getOrgAdmin(org); const peers = helper.newPeers([0, 1], org); const operator = new ChaincodeDefinitionOperator(channel, admin, peers, init_required); await operator.connect(); - await operator.queryInstalledAndApprove(chaincodeID, sequence, orderer); + await operator.queryInstalledAndApprove(chaincodeID, orderer); await operator.disconnect(); } }); it('commit', async () => { + // TODO migrate to testutil.js const org = 'icdd'; const peers = [helper.newPeer(0, 'astri.org'), helper.newPeer(0, 'icdd')]; const admin = helper.getOrgAdmin(org); const operator = new ChaincodeDefinitionOperator(channel, admin, peers, init_required); await operator.connect(); - await operator.commitChaincodeDefinition({name: chaincodeID, sequence}, orderer); + await operator.queryAndCommit(chaincodeID, orderer); await operator.disconnect(); }); }); -describe('invoke', function () { - this.timeout(0) +describe('invoke', function () { + this.timeout(0); const peer = helper.newPeer(0, 'astri.org'); const org = 'icdd'; const user = new UserBuilder(undefined, helper.getOrgAdmin(org)); @@ -60,16 +68,19 @@ describe('invoke', function () { it('who', async () => { contract.subContract = 'SmartContract'; const result = await contract.evaluateTransaction('who'); - console.debug(result); + logger.info(result); }); it('touch submit', async () => { contract.subContract = 'StupidContract'; await contract.submitTransaction('ping'); }); - it('panic', async () => { - assert.throws(async () => { - await contract.evaluateTransaction('StupidContract:panic'); + it('p1e', async () => { + await assert.rejects(async () => { + await contract.evaluateTransaction('StupidContract:P1E'); + }); + await assert.rejects(async () => { + await contract.evaluateTransaction('StupidContract:p1E'); }); diff --git a/cc/testutil.js b/cc/testutil.js new file mode 100644 index 0000000..2c22d21 --- /dev/null +++ b/cc/testutil.js @@ -0,0 +1,17 @@ +import * as helper from '../app/helper.js'; +import {ChaincodeDefinitionOperator} from '../app/installHelper.js'; +import {consoleLogger} from '@davidkhala/logger/log4.js'; + +const channel = 'allchannel'; + +export async function dev(org, chaincodeID, init_required = false) { + const admin = helper.getOrgAdmin(org); + const logger = consoleLogger(`chaincode:${chaincodeID}`); + const peers = helper.newPeers([0, 1], org); + const operator = new ChaincodeDefinitionOperator(channel, admin, peers, init_required); + await operator.connect(); + const [installed, uncommitted, committed] = await operator.queryInstalled(chaincodeID); + const definitions = await operator.queryDefinition(chaincodeID); + logger.debug({installed, uncommitted, committed, definitions}); + await operator.disconnect(); +} diff --git a/test-oneoff/eventHubTest.js b/test-oneoff/eventHubTest.js index d145d42..0939284 100644 --- a/test-oneoff/eventHubTest.js +++ b/test-oneoff/eventHubTest.js @@ -3,30 +3,30 @@ import UserUtil from '../common/nodejs/admin/user.js'; import * as helper from '../app/helper.js'; import {BlockNumberFilterType} from '../common/nodejs/formatter/eventHub.js'; import {consoleLogger} from '@davidkhala/logger/log4.js'; -import BlockDecoder from '../common/nodejs/formatter/blockDecoder.js'; +import {BlockDecoder} from '@hyperledger-twgc/fabric-formatter'; +import assert from 'assert'; const logger = consoleLogger('test:eventHub'); const {NEWEST, OLDEST} = BlockNumberFilterType; const org = 'astri.org'; -describe('eventhub', function () { +describe('eventhub', function () { this.timeout(0); const channelName = 'allchannel'; const user = helper.getOrgAdmin(org, 'peer'); const channel = helper.prepareChannel(channelName); logger.info(channel.toString()); const peer = helper.newPeer(0, org); - const orderers = helper.newOrderers() - const orderer = orderers[0] + const orderers = helper.newOrderers(); + const orderer = orderers[0]; - it('wait for block', async ()=>{ - const eventHub = new EventHub(channel, orderer.eventer); - const identityContext = UserUtil.getIdentityContext(user); - - }) - it('block parser', async ()=> { + it('san check', async () => { + new EventHub(channel, orderer.eventer); + UserUtil.getIdentityContext(user); + assert.ok(typeof BlockDecoder === 'function'); + }); + it('block parser', async () => { const eventHub = new EventHub(channel, peer.eventer); - console.debug(user) const identityContext = UserUtil.getIdentityContext(user); const startBlock = OLDEST; const endBlock = NEWEST; @@ -38,6 +38,7 @@ describe('eventhub', function () { return; } const {block} = event; + console.debug(block) const decoder = new BlockDecoder(block); const {number} = decoder.header(); logger.debug(`---block ${number}---`);