fabric-contract-api
Advanced tools
Comparing version 1.3.0-snapshot.6 to 1.3.0-snapshot.7
@@ -13,4 +13,4 @@ /* | ||
module.exports.Contract = require('./lib/contract.js'); | ||
module.exports.Context = require('./lib/context.js'); | ||
@@ -9,7 +9,10 @@ /* | ||
const ClientIdentity = require('fabric-shim').ClientIdentity; | ||
const Context = require('./context'); | ||
/** | ||
* The main Contact class that all code working within a Chaincode Container must be extending. Provides indentification | ||
* and helper functions to work with | ||
* The main Contact class that all code working within a Chaincode Container must be extending. | ||
* | ||
* Overriding of the `beforeTransaction` `afterTransaction` `unknownTransaction` and `createContext` are all optional | ||
* Supplying a namespace within the constructor is also option and will default to '' | ||
* | ||
* @memberof fabric-contract-api | ||
@@ -20,94 +23,69 @@ */ | ||
/** | ||
* If no namespace given, or it is whitespace default to 'contract' | ||
* Constructor - supplying a namespace is recommended but is not mandatory. | ||
* | ||
* @param {String} namespace namespace for the logic within this contract | ||
*/ | ||
constructor(namespace, metadata = {}){ | ||
constructor(namespace){ | ||
if (namespace && namespace.trim() !== '' ){ | ||
this.namespace = namespace.trim(); | ||
} else { | ||
this.namespace = 'contract'; | ||
this.namespace = ''; | ||
} | ||
this.metadata = metadata; | ||
this.unknownFn = () => { | ||
throw new Error('You\'ve asked to invoke a function that does not exist'); | ||
}; | ||
} | ||
/** Is the object a function? | ||
* @ignore | ||
* @param {function} fn to be checked | ||
* @return {boolean} true if function | ||
*/ | ||
_isFunction(fn){ | ||
return !!(fn && fn.constructor && fn.call && fn.apply); | ||
} | ||
/** | ||
* Sets the fn to call if something unknown comes in; | ||
* If function is not passed a error will be thrown | ||
* | ||
* @param {function} fn fn - | ||
*/ | ||
setUnknownFn(fn){ | ||
if (this._isFunction(fn)){ | ||
this.unknownFn = fn; | ||
} else { | ||
throw new Error('Argument is not a function'); | ||
} | ||
* 'beforeTransaction' will be called before any of the transaction functions within your contract | ||
* Override this method to implement your own processing. Examples of what you may wish to code | ||
* are Logging, Event Publishing or Permissions checks | ||
* | ||
* If an error is thrown, the whole transaction will be rejected | ||
* | ||
* @param {Context} ctx the transactional context | ||
*/ | ||
async beforeTransaction(ctx){ // eslint-disable-line | ||
// default implementation is do nothing | ||
} | ||
/** | ||
* Gets the fn to call to use if nothing specified | ||
* @return {function} function | ||
*/ | ||
getUnknownFn(){ | ||
return this.unknownFn; | ||
* 'afterTransaction' will be called before any of the transaction functions within your contract | ||
* Override this method to implement your own processing. Examples of what you may wish to code | ||
* are Logging, Event Publishing | ||
* | ||
* If an error is thrown, the whole transaction will be rejected | ||
* | ||
* @param {Context} ctx the transactional context | ||
* @param {Object} result value that is returned from the transaction function | ||
*/ | ||
async afterTransaction(ctx,result){ // eslint-disable-line no-unused-vars | ||
// default implementation is do nothing | ||
} | ||
/** | ||
* This is invoked before each function | ||
* | ||
* @param {function} fn fn to invoke prior to the transaction function being called | ||
*/ | ||
setBeforeFn(fn){ | ||
if (this._isFunction(fn)){ | ||
this.beforeFn = fn; | ||
} else { | ||
throw new Error('Argument is not a function'); | ||
} | ||
* 'unknownTransaction' will be called if the required transaction function requested does not exist | ||
* Override this method to implement your own processing. | ||
* * | ||
* If an error is thrown, the whole transaction will be rejected | ||
* | ||
* @param {Context} ctx the transactional context | ||
*/ | ||
async unknownTransaction(ctx) { | ||
const { fcn } = ctx.stub.getFunctionAndParameters(); | ||
throw new Error(`You've asked to invoke a function that does not exist: ${fcn}`); | ||
} | ||
/** | ||
* Get the function that would be invoked before | ||
* | ||
* @return {function} fn | ||
*/ | ||
getBeforeFn(){ | ||
return this.beforeFn; | ||
* 'createContext' is called before any after, before, unknown or user defined transaction function. This permits contracts | ||
* to use their own subclass of context to add additinal processing. | ||
* | ||
* After this function returns, the chaincodeStub and client identity objects will be injected. | ||
* No chaincode apis are available for calling directly within this function. Nor should the constructor of the subclasses context assume | ||
* any other setup. | ||
* | ||
* @return {Context} a context implementation that must subclass context | ||
*/ | ||
createContext(){ | ||
return new Context(); | ||
} | ||
/** | ||
* Get the function that would be invoked after | ||
* | ||
* @return {function} fn | ||
*/ | ||
getAfterFn(){ | ||
return this.afterFn; | ||
} | ||
/** | ||
* This is invoked after each function | ||
* | ||
* @param {function} fn fn to invoke after the transaction function being called | ||
*/ | ||
setAfterFn(fn){ | ||
if (this._isFunction(fn)){ | ||
this.afterFn = fn; | ||
} else { | ||
throw new Error('Argument is not a function'); | ||
} | ||
} | ||
/** | ||
* @return {String} returns the namepsace | ||
@@ -119,13 +97,4 @@ */ | ||
/** | ||
* Gets meta data about this instance | ||
* | ||
* @return {Object} object with key/value map of metadata | ||
*/ | ||
getMetadata(){ | ||
return this.metadata; | ||
} | ||
} | ||
module.exports = Contract; |
{ | ||
"name": "fabric-contract-api", | ||
"version": "1.3.0-snapshot.6", | ||
"version": "1.3.0-snapshot.7", | ||
"description": "A node.js implementation of Hyperledger Fabric chaincode shim, to allow endorsing peers and user-provided chaincodes to communicate with each other", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -77,3 +77,3 @@ [![NPM](https://nodei.co/npm/fabric-contract-api.svg?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/fabric-contract-api/) | ||
"scripts": { | ||
"start": "startChaincode" | ||
"start": "fabric-chaincode-node start" | ||
} | ||
@@ -80,0 +80,0 @@ ``` |
@@ -10,23 +10,39 @@ "use strict"; | ||
const fabric_contract_api_1 = require("fabric-contract-api"); | ||
class ScenarioContext extends fabric_contract_api_1.Context { | ||
customFunction() { | ||
} | ||
} | ||
exports.ScenarioContext = ScenarioContext; | ||
class TestContractOne extends fabric_contract_api_1.Contract { | ||
constructor() { | ||
super('org.papernet.commercialpaper', { key: 'value' }); | ||
const intermediaryFn = (ctx) => { | ||
return ctx; | ||
}; | ||
this.setBeforeFn(intermediaryFn); | ||
this.setAfterFn(intermediaryFn); | ||
this.setUnknownFn(intermediaryFn); | ||
super('org.papernet.commercialpaper'); | ||
} | ||
beforeTransaction(ctx) { | ||
// test that the context super class properties are available | ||
const stubApi = ctx.stub; | ||
const clientIdentity = ctx.clientIdentity; | ||
// tests that the functions in the subclasses context be called | ||
ctx.customFunction(); | ||
// This proves that typescript is enforcing the | ||
// return type of Promise<void> | ||
return Promise.resolve(); | ||
} | ||
afterTransaction(ctx, result) { | ||
// This proves that typescript is enforcing the | ||
// return type of Promise<void> | ||
return Promise.resolve(); | ||
} | ||
unknownTransaction(ctx) { | ||
// This proves that typescript is enforcing the | ||
// return type of Promise<void> | ||
return Promise.resolve(); | ||
} | ||
createContext() { | ||
return new ScenarioContext(); | ||
} | ||
async Transaction(ctx) { | ||
// test that the context super class properties are available | ||
const stubApi = ctx.stub; | ||
const clientIdentity = ctx.clientIdentity; | ||
const afterFn = this.getAfterFn(); | ||
const testCtxAfter = afterFn(ctx); | ||
const beforeFn = this.getBeforeFn(); | ||
const testCtxBefore = beforeFn(ctx); | ||
const unknownFn = this.getUnknownFn(); | ||
const testCtxUnkown = beforeFn(ctx); | ||
const testCtx = afterFn(ctx); | ||
const data = this.getMetadata(); | ||
// test that the namespace returns a string | ||
const ns = this.getNamespace(); | ||
@@ -38,12 +54,10 @@ } | ||
constructor() { | ||
super('org.papernet.commercialpaper'); | ||
super(); | ||
} | ||
async Transaction(ctx) { | ||
const stubApi = ctx.stub; | ||
const clientIdentity = ctx.clientIdentity; | ||
} | ||
} | ||
exports.TestContractTwo = TestContractTwo; | ||
class TestContractThree extends fabric_contract_api_1.Contract { | ||
constructor() { | ||
super(); | ||
} | ||
} | ||
exports.TestContractThree = TestContractThree; | ||
//# sourceMappingURL=smartcontract.js.map |
@@ -8,31 +8,54 @@ /* | ||
import { Contract, Context, IntermediaryFn } from 'fabric-contract-api'; | ||
import { Contract, Context } from 'fabric-contract-api'; | ||
import { ChaincodeStub, ClientIdentity } from 'fabric-shim'; | ||
export class ScenarioContext extends Context{ | ||
customFunction():void { | ||
} | ||
} | ||
export default class TestContractOne extends Contract { | ||
constructor() { | ||
super('org.papernet.commercialpaper', {key: 'value'}); | ||
super('org.papernet.commercialpaper'); | ||
} | ||
const intermediaryFn: IntermediaryFn = (ctx: Context) => { | ||
return ctx; | ||
} | ||
beforeTransaction(ctx: ScenarioContext){ | ||
this.setBeforeFn(intermediaryFn); | ||
this.setAfterFn(intermediaryFn); | ||
this.setUnknownFn(intermediaryFn); | ||
} | ||
// test that the context super class properties are available | ||
const stubApi: ChaincodeStub = ctx.stub; | ||
const clientIdentity: ClientIdentity = ctx.clientIdentity; | ||
async Transaction(ctx: Context) { | ||
// tests that the functions in the subclasses context be called | ||
ctx.customFunction(); | ||
// This proves that typescript is enforcing the | ||
// return type of Promise<void> | ||
return Promise.resolve(); | ||
} | ||
afterTransaction(ctx: ScenarioContext,result: any){ | ||
// This proves that typescript is enforcing the | ||
// return type of Promise<void> | ||
return Promise.resolve(); | ||
} | ||
unknownTransaction(ctx: ScenarioContext){ | ||
// This proves that typescript is enforcing the | ||
// return type of Promise<void> | ||
return Promise.resolve(); | ||
} | ||
createContext(){ | ||
return new ScenarioContext(); | ||
} | ||
async Transaction(ctx: ScenarioContext) { | ||
// test that the context super class properties are available | ||
const stubApi: ChaincodeStub = ctx.stub; | ||
const clientIdentity: ClientIdentity = ctx.clientIdentity; | ||
const afterFn: IntermediaryFn = this.getAfterFn(); | ||
const testCtxAfter: Context = afterFn(ctx); | ||
const beforeFn: IntermediaryFn = this.getBeforeFn(); | ||
const testCtxBefore: Context = beforeFn(ctx); | ||
const unknownFn: IntermediaryFn = this.getUnknownFn(); | ||
const testCtxUnkown: Context = beforeFn(ctx); | ||
const testCtx: Context = afterFn(ctx); | ||
const data: object = this.getMetadata(); | ||
// test that the namespace returns a string | ||
const ns: string = this.getNamespace(); | ||
@@ -44,10 +67,9 @@ } | ||
constructor() { | ||
super('org.papernet.commercialpaper'); | ||
} | ||
} | ||
super(); | ||
} | ||
export class TestContractThree extends Contract { | ||
constructor() { | ||
super(); | ||
async Transaction(ctx: Context) { | ||
const stubApi: ChaincodeStub = ctx.stub; | ||
const clientIdentity: ClientIdentity = ctx.clientIdentity; | ||
} | ||
} |
@@ -28,7 +28,42 @@ /* | ||
const Contract = require(path.join(pathToRoot,'fabric-contract-api/lib/contract')); | ||
const Context = require(path.join(pathToRoot,'fabric-contract-api/lib/context')); | ||
let beforeStub; | ||
let afterStub; | ||
let unknownStub; | ||
let createContextStub; | ||
/* | ||
* A fake contract class; | ||
*/ | ||
class SCAlpha extends Contract { | ||
/** */ | ||
constructor() { | ||
super('alpha.beta.delta'); | ||
} | ||
async unknownTransaction(ctx){ | ||
unknownStub(ctx); | ||
} | ||
async beforeTransaction(ctx){ | ||
beforeStub(ctx); | ||
} | ||
async afterTransaction(ctx,result){ | ||
afterStub(ctx,result); | ||
} | ||
createContext(){ | ||
createContextStub(); | ||
} | ||
} | ||
describe('contract.js',()=>{ | ||
let sandbox; | ||
@@ -46,21 +81,27 @@ | ||
it('should create with default namespace ',()=>{ | ||
let sc = new Contract(); | ||
expect(sc.namespace).to.equal('contract'); | ||
it('should create with default namespace',()=>{ | ||
let sc0 = new Contract(); | ||
expect(sc0.getNamespace()).to.equal(''); | ||
( ()=>{ | ||
sc.unknownFn(); | ||
}).should.throw(/does not exist/); | ||
// should also create default when the supplied name is empty space | ||
let sc1 = new Contract(''); | ||
expect(sc1.namespace).to.equal('contract'); | ||
expect(sc1.getNamespace()).to.equal('contract'); | ||
expect(sc1.getNamespace()).to.equal(''); | ||
let sc2 = new Contract(' '); | ||
expect(sc2.namespace).to.equal('contract'); | ||
expect(sc2.getNamespace()).to.equal('contract'); | ||
expect(sc2.getNamespace()).to.equal(''); | ||
}); | ||
it('should have default unknownTx fn',()=>{ | ||
let sc0 = new Contract(); | ||
const ctx = { | ||
stub : { | ||
getFunctionAndParameters: 'fn' | ||
} | ||
}; | ||
ctx.stub.getFunctionAndParameters = sandbox.stub().returns({fcn:'wibble'}); | ||
return sc0.unknownTransaction(ctx).should.eventually.be.rejectedWith(/^You've asked to invoke a function that does not exist: wibble$/); | ||
}); | ||
it('should create with the name specified',()=>{ | ||
@@ -75,93 +116,57 @@ let sc1 = new Contract('brain.size.planet.smart'); | ||
}); | ||
}); | ||
describe('#_isFunction',()=>{ | ||
let sc; | ||
beforeEach('create temporary contract',()=>{ | ||
sc = new Contract(); | ||
}); | ||
it('should call the default before/after functions',()=>{ | ||
let sc0 = new Contract(); | ||
it('should return true for functions',()=>{ | ||
sc._isFunction((()=>{})).should.be.true; | ||
return Promise.all([ | ||
sc0.beforeTransaction().should.be.fulfilled, | ||
sc0.afterTransaction().should.be.fulfilled]); | ||
}); | ||
it('should return false for not-functions',()=>{ | ||
sc._isFunction().should.be.false; | ||
sc._isFunction('Hello').should.be.false; | ||
sc._isFunction(25).should.be.false; | ||
sc._isFunction(sc); | ||
it('should call the default createContext functions',()=>{ | ||
let sc0 = new Contract(); | ||
sc0.createContext().should.be.an.instanceOf(Context); | ||
}); | ||
}); | ||
describe('#set/get UnkownFn',()=>{ | ||
let sc; | ||
beforeEach('create temporary contract',()=>{ | ||
sc = new Contract(); | ||
}); | ||
describe('subclass specific functioning',()=>{ | ||
it('should return function passed in',()=>{ | ||
let fn = ()=>{return 42;}; | ||
sc.setUnknownFn(fn); | ||
expect(sc.unknownFn()).to.equal(42); | ||
expect(sc.getUnknownFn()()).to.equal(42); | ||
beforeEach('setup the stubs',()=>{ | ||
beforeStub = sandbox.stub().resolves(); | ||
afterStub = sandbox.stub().resolves(); | ||
unknownStub = sandbox.stub().resolves(); | ||
createContextStub = sandbox.stub().returns(); | ||
}); | ||
it('should throw error with wrong tyupes ',()=>{ | ||
( ()=>{ | ||
sc.setUnknownFn('wibble'); | ||
} ).should.throw(/Argument is not a function/); | ||
}); | ||
}); | ||
describe('#set/get BeforeFn',()=>{ | ||
let sc; | ||
beforeEach('create temporary contract',()=>{ | ||
sc = new Contract(); | ||
it('should set the correct namespace',()=>{ | ||
let sc = new SCAlpha(); | ||
sc.getNamespace().should.equal('alpha.beta.delta'); | ||
}); | ||
it('should return function passed in',()=>{ | ||
let fn = ()=>{return 42;}; | ||
sc.setBeforeFn(fn); | ||
expect(sc.beforeFn()).to.equal(42); | ||
expect(sc.getBeforeFn()()).to.equal(42); | ||
it('should call the correct subclassed fns',()=>{ | ||
let sc = new SCAlpha(); | ||
let ctx = 'a really simple context'; | ||
sc.beforeTransaction(ctx); | ||
sinon.assert.calledOnce(beforeStub); | ||
sinon.assert.calledWith(beforeStub,ctx); | ||
}); | ||
it('should throw error with wrong tyupes ',()=>{ | ||
( ()=>{ | ||
sc.setBeforeFn('wibble'); | ||
} ).should.throw(/Argument is not a function/); | ||
}); | ||
}); | ||
sc.afterTransaction(ctx,'result'); | ||
sinon.assert.calledOnce(afterStub); | ||
sinon.assert.calledWith(afterStub,ctx,'result'); | ||
describe('#set/get AfterFn',()=>{ | ||
let sc; | ||
beforeEach('create temporary contract',()=>{ | ||
sc = new Contract(); | ||
}); | ||
sc.unknownTransaction(ctx); | ||
sinon.assert.calledOnce(unknownStub); | ||
sinon.assert.calledWith(unknownStub,ctx); | ||
it('should return function passed in',()=>{ | ||
let fn = ()=>{return 42;}; | ||
sc.setAfterFn(fn); | ||
expect(sc.afterFn()).to.equal(42); | ||
expect(sc.getAfterFn()()).to.equal(42); | ||
sc.createContext(); | ||
sinon.assert.calledOnce(createContextStub); | ||
}); | ||
it('should throw error with wrong tyupes ',()=>{ | ||
( ()=>{ | ||
sc.setAfterFn('wibble'); | ||
} ).should.throw(/Argument is not a function/); | ||
}); | ||
}); | ||
describe('#getMetadata',()=>{ | ||
let sc; | ||
beforeEach('create temporary contract',()=>{ | ||
sc = new Contract('anamespace',{a:'value',some:'othervalue'}); | ||
}); | ||
it('should return value passed in',()=>{ | ||
let md = sc.getMetadata(); | ||
expect(md).to.deep.equal({a:'value',some:'othervalue'}); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -10,3 +10,3 @@ /* | ||
import { ChaincodeStub, ClientIdentity } from 'fabric-shim'; | ||
export interface Context { | ||
export class Context { | ||
stub: ChaincodeStub; | ||
@@ -16,19 +16,14 @@ clientIdentity: ClientIdentity; | ||
export type IntermediaryFn = (ctx: Context) => Context; | ||
export class Contract { | ||
constructor(namespace?: string, metadata?:object); | ||
constructor(namespace?: string); | ||
setUnknownFn(fn : IntermediaryFn): void; | ||
getUnknownFn(): IntermediaryFn; | ||
beforeTransaction(ctx : Context): Promise<void>; | ||
afterTransaction(ctx : Context,result: any): Promise<void>; | ||
setBeforeFn(fn : IntermediaryFn): void; | ||
getBeforeFn(): IntermediaryFn; | ||
unknownTransaction(ctx : Context): Promise<void>; | ||
setAfterFn(fn : IntermediaryFn): void; | ||
getAfterFn(): IntermediaryFn; | ||
createContext(): Context; | ||
getNamespace(): string; | ||
getNamespace(): string; | ||
getMetadata(): object; | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
20829
13
500
3
1