lotion-state-machine
Advanced tools
Comparing version 0.0.2 to 0.0.3
@@ -7,14 +7,15 @@ /// <reference types="node" /> | ||
export interface StateMachine { | ||
initialize(initialState?: any, initialInfo?: any): void | Promise<void>; | ||
initialize(initialState?: any, initialContext?: any): void | Promise<void>; | ||
transition(action: any): any; | ||
check?(action: any): any; | ||
query(query?: any): any; | ||
info?(): any; | ||
validators?(): any; | ||
commit(): string | Buffer | Promise<string | Buffer>; | ||
} | ||
export declare type TransactionHandler = (state: any, tx: any, info?: any) => any; | ||
export declare type BlockHandler = (state: any, info?: any) => any; | ||
export declare type Initializer = (state: any, info?: any) => any; | ||
export declare type TransactionHandler = (state: any, tx: any, context?: any) => any; | ||
export declare type BlockHandler = (state: any, context?: any) => any; | ||
export declare type Initializer = (state: any, context?: any) => any; | ||
export interface Application { | ||
use(txHandler: TransactionHandler | Middleware | Middleware[]): any; | ||
use(txHandler: string, route: TransactionHandler | Middleware | Middleware[]): any; | ||
useTx(txHandler: TransactionHandler): any; | ||
@@ -21,0 +22,0 @@ useBlock(blockHandler: BlockHandler): any; |
@@ -6,2 +6,13 @@ "use strict"; | ||
var muta = require("muta"); | ||
var Router = require("lotion-router"); | ||
// defines an FSM to ensure state machine transitions | ||
// are called in the proper order | ||
var validTransitions = { | ||
'none': new Set(['initialize']), | ||
'initialize': new Set(['begin-block']), | ||
'begin-block': new Set(['transaction', 'block']), | ||
'transaction': new Set(['transaction', 'block']), | ||
'block': new Set(['commit']), | ||
'commit': new Set(['begin-block']) | ||
}; | ||
function LotionStateMachine(opts) { | ||
@@ -11,5 +22,19 @@ var transactionHandlers = []; | ||
var blockHandlers = []; | ||
var routes; | ||
var appMethods = { | ||
use: function (middleware) { | ||
if (middleware instanceof Array) { | ||
use: function (middleware, route) { | ||
if (typeof middleware === 'string') { | ||
if (routes == null) { | ||
routes = {}; | ||
} | ||
var routeName = middleware; | ||
if (routeName in routes) { | ||
throw Error("Route \"" + routeName + "\" already exists"); | ||
} | ||
if (route == null) { | ||
throw Error('Expected middleware for route'); | ||
} | ||
routes[routeName] = route; | ||
} | ||
else if (middleware instanceof Array) { | ||
middleware.forEach(appMethods.use); | ||
@@ -29,2 +54,5 @@ } | ||
} | ||
else { | ||
throw Error('Unknown middleware type'); | ||
} | ||
return appMethods; | ||
@@ -42,9 +70,14 @@ }, | ||
compile: function () { | ||
var appState = opts.initialState; | ||
if (routes != null) { | ||
var router = Router(routes); | ||
appMethods.use(router); | ||
} | ||
var appState = opts.initialState || {}; | ||
var mempoolState = muta(appState); | ||
var nextState, nextInfo; | ||
var chainInfo, mempoolInfo; | ||
function applyTx(state, tx, info) { | ||
var nextState, nextValidators, nextContext; | ||
var chainValidators, mempoolValidators, mempoolContext; | ||
var prevOp = 'none'; | ||
function applyTx(state, tx, context) { | ||
/** | ||
* wrap the state and info for this one tx. | ||
* wrap the state and context for this one tx. | ||
* try applying this transaction. | ||
@@ -56,5 +89,6 @@ * if an error is thrown, transaction is invalid. | ||
var txState = muta(state); | ||
var txInfo = muta(info); | ||
var txValidators = muta(context.validators); | ||
context = Object.assign({}, context, { validators: txValidators }); | ||
try { | ||
transactionHandlers.forEach(function (m) { return m(txState, tx, txInfo); }); | ||
transactionHandlers.forEach(function (m) { return m(txState, tx, context); }); | ||
/** | ||
@@ -64,3 +98,3 @@ * tx was applied without error. | ||
*/ | ||
if (wasMutated(txState) || wasMutated(txInfo)) { | ||
if (wasMutated(txState) || wasMutated(txValidators)) { | ||
/** | ||
@@ -71,3 +105,3 @@ * valid tx. | ||
muta.commit(txState); | ||
muta.commit(txInfo); | ||
muta.commit(txValidators); | ||
return {}; | ||
@@ -87,12 +121,25 @@ } | ||
} | ||
// check FSM to ensure consumer is transitioning us in the right order | ||
function checkTransition(type) { | ||
var valid = validTransitions[prevOp].has(type); | ||
if (!valid) { | ||
throw Error("Invalid transition: type=" + type + " prev=" + prevOp); | ||
} | ||
prevOp = type; | ||
} | ||
return { | ||
initialize: function (initialState, initialInfo) { | ||
chainInfo = initialInfo; | ||
mempoolInfo = muta(chainInfo); | ||
initialize: function (initialState, initialContext) { | ||
if (initialContext === void 0) { initialContext = {}; } | ||
checkTransition('initialize'); | ||
nextContext = initialContext; | ||
chainValidators = initialContext.validators || {}; | ||
mempoolValidators = muta(chainValidators); | ||
Object.assign(appState, initialState); | ||
// TODO: should this get the initial context? | ||
initializers.forEach(function (m) { return m(appState); }); | ||
}, | ||
transition: function (action) { | ||
checkTransition(action.type); | ||
if (action.type === 'transaction') { | ||
applyTx(nextState, action.data, nextInfo); | ||
applyTx(nextState, action.data, nextContext); | ||
} | ||
@@ -105,3 +152,3 @@ else if (action.type === 'block') { | ||
*/ | ||
blockHandlers.forEach(function (m) { return m(nextState, nextInfo); }); | ||
blockHandlers.forEach(function (m) { return m(nextState, nextContext); }); | ||
} | ||
@@ -114,15 +161,18 @@ else if (action.type === 'begin-block') { | ||
*/ | ||
chainInfo.time = action.data.time; | ||
nextState = muta(appState); | ||
nextInfo = muta(chainInfo); | ||
nextValidators = muta(chainValidators); | ||
nextContext = Object.assign({}, action.data, { | ||
validators: nextValidators | ||
}); | ||
} | ||
}, | ||
commit: function () { | ||
checkTransition('commit'); | ||
/** | ||
* reset mempool state/info on commit | ||
* reset mempool state/ctx on commit | ||
*/ | ||
muta.commit(nextState); | ||
muta.commit(nextInfo); | ||
muta.commit(nextValidators); | ||
mempoolState = muta(appState); | ||
mempoolInfo = muta(chainInfo); | ||
mempoolValidators = muta(chainValidators); | ||
return crypto_1.createHash('sha256') | ||
@@ -133,3 +183,6 @@ .update(djson.stringify(appState)) | ||
check: function (tx) { | ||
applyTx(mempoolState, tx, mempoolInfo); | ||
var context = Object.assign({}, nextContext, { | ||
validators: mempoolValidators, | ||
}); | ||
applyTx(mempoolState, tx, context); | ||
}, | ||
@@ -139,4 +192,4 @@ query: function (path) { | ||
}, | ||
info: function () { | ||
return chainInfo; | ||
validators: function () { | ||
return chainValidators; | ||
} | ||
@@ -143,0 +196,0 @@ }; |
{ | ||
"name": "lotion-state-machine", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "", | ||
"main": "dist/lotion-state-machine.js", | ||
"scripts": { | ||
"test": "tape test/*.js" | ||
"test": "nyc -r text -r html tape test/*.js" | ||
}, | ||
@@ -15,7 +15,9 @@ "keywords": [], | ||
"deterministic-json": "^1.0.5", | ||
"lotion-router": "^1.0.0", | ||
"muta": "^0.4.0" | ||
}, | ||
"devDependencies": { | ||
"nyc": "^13.0.1", | ||
"tape": "^4.9.1" | ||
} | ||
} |
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
25428
4
2
5
223
1
+ Addedlotion-router@^1.0.0
+ Addedlotion-router@1.0.0(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedold@0.2.0(transitive)