wallet/light.js
function buildPath(objLaterJoint, objEarlierJoint, arrChain, onDone){
	
	function addJoint(unit, onAdded){
	   storage.readJoint(db, unit, {
			ifNotFound: function(){
				throw Error("unit not found?");
			},
			ifFound: function(objJoint){
				arrChain.push(objJoint);
				onAdded(objJoint);
			}
		});
	 }
	
	function goUp(objChildJoint){
		db.query(
			"SELECT parent.unit, parent.main_chain_index FROM units AS child JOIN units AS parent ON child.best_parent_unit=parent.unit \n\
			WHERE child.unit=?", 
			[objChildJoint.unit.unit],
			function(rows){
				if (rows.length !== 1)
					throw Error("goUp not 1 parent");
				if (rows[0].main_chain_index < objEarlierJoint.unit.main_chain_index) // jumped over the target
					return buildPathToEarlierUnit(objChildJoint);
				addJoint(rows[0].unit, function(objJoint){
					(objJoint.unit.main_chain_index === objEarlierJoint.unit.main_chain_index) ? buildPathToEarlierUnit(objJoint) : goUp(objJoint);
				});
			}
		);
	}
	
	function buildPathToEarlierUnit(objJoint){
		db.query(
			"SELECT unit FROM parenthoods JOIN units ON parent_unit=unit \n\
			WHERE child_unit=? AND main_chain_index=?", 
			[objJoint.unit.unit, objJoint.unit.main_chain_index],
			function(rows){
				if (rows.length === 0)
					throw Error("no parents with same mci?");
				var arrParentUnits = rows.map(function(row){ return row.unit });
				if (arrParentUnits.indexOf(objEarlierJoint.unit.unit) >= 0)
					return onDone();
				if (arrParentUnits.length === 1)
					return addJoint(arrParentUnits[0], buildPathToEarlierUnit);
				// find any parent that includes earlier unit
				async.eachSeries(
					arrParentUnits,
					function(unit, cb){
						graph.determineIfIncluded(db, objEarlierJoint.unit.unit, [unit], function(bIncluded){
							if (!bIncluded)
								return cb(); // try next
							cb(unit); // abort the eachSeries
						});
					},
					function(unit){
						if (!unit)
							throw Error("none of the parents includes earlier unit");
						addJoint(unit, buildPathToEarlierUnit);
					}
				);
			}
		);
	}
	
	if (objLaterJoint.unit.unit === objEarlierJoint.unit.unit)
		return onDone();
	(objLaterJoint.unit.main_chain_index === objEarlierJoint.unit.main_chain_index) ? buildPathToEarlierUnit(objLaterJoint) : goUp(objLaterJoint);
}
function buildPath(objLaterJoint, objEarlierJoint, arrChain, onDone){
	
	function addJoint(unit, onAdded){
	   storage.readJoint(db, unit, {
			ifNotFound: function(){
				throw Error("unit not found?");
			},
			ifFound: function(objJoint){
				arrChain.push(objJoint);
				onAdded(objJoint);
			}
		});
	 }
	
	function goUp(objChildJoint){
		db.query(
			"SELECT parent.unit, parent.main_chain_index FROM units AS child JOIN units AS parent ON child.best_parent_unit=parent.unit \n\
			WHERE child.unit=?", 
			[objChildJoint.unit.unit],
			function(rows){
				if (rows.length !== 1)
					throw Error("goUp not 1 parent");
				if (rows[0].main_chain_index < objEarlierJoint.unit.main_chain_index) // jumped over the target
					return buildPathToEarlierUnit(objChildJoint);
				addJoint(rows[0].unit, function(objJoint){
					(objJoint.unit.main_chain_index === objEarlierJoint.unit.main_chain_index) ? buildPathToEarlierUnit(objJoint) : goUp(objJoint);
				});
			}
		);
	}
	
	function buildPathToEarlierUnit(objJoint){
		db.query(
			"SELECT unit FROM parenthoods JOIN units ON parent_unit=unit \n\
			WHERE child_unit=? AND main_chain_index=?", 
			[objJoint.unit.unit, objJoint.unit.main_chain_index],
			function(rows){
				if (rows.length === 0)
					throw Error("no parents with same mci?");
				var arrParentUnits = rows.map(function(row){ return row.unit });
				if (arrParentUnits.indexOf(objEarlierJoint.unit.unit) >= 0)
					return onDone();
				if (arrParentUnits.length === 1)
					return addJoint(arrParentUnits[0], buildPathToEarlierUnit);
				// find any parent that includes earlier unit
				async.eachSeries(
					arrParentUnits,
					function(unit, cb){
						graph.determineIfIncluded(db, objEarlierJoint.unit.unit, [unit], function(bIncluded){
							if (!bIncluded)
								return cb(); // try next
							cb(unit); // abort the eachSeries
						});
					},
					function(unit){
						if (!unit)
							throw Error("none of the parents includes earlier unit");
						addJoint(unit, buildPathToEarlierUnit);
					}
				);
			}
		);
	}
	
	if (objLaterJoint.unit.unit === objEarlierJoint.unit.unit)
		return onDone();
	(objLaterJoint.unit.main_chain_index === objEarlierJoint.unit.main_chain_index) ? buildPathToEarlierUnit(objLaterJoint) : goUp(objLaterJoint);
}
function buildPath ( objLaterJoint , objEarlierJoint , arrChain , onDone ) { function addJoint ( unit , onAdded ) { storage . readJoint ( db , unit , { ifNotFound : function ( ) { throw Error ( "unit not found?" ) ; } , ifFound : function ( objJoint ) { arrChain . push ( objJoint ) ; onAdded ( objJoint ) ; } } ) ; } function goUp ( objChildJoint ) { db . query ( "SELECT parent.unit, parent.main_chain_index FROM units AS child JOIN units AS parent ON child.best_parent_unit=parent.unit \n\
			WHERE child.unit=?" , [ objChildJoint . unit . unit ] , function ( rows ) { if ( rows . length !== 1 ) throw Error ( "goUp not 1 parent" ) ; if ( rows [ 0 ] . main_chain_index < objEarlierJoint . unit . main_chain_index ) // jumped over the target return buildPathToEarlierUnit ( objChildJoint ) ; addJoint ( rows [ 0 ] . unit , function ( objJoint ) { ( objJoint . unit . main_chain_index === objEarlierJoint . unit . main_chain_index ) ? buildPathToEarlierUnit ( objJoint ) : goUp ( objJoint ) ; } ) ; } ) ; } function buildPathToEarlierUnit ( objJoint ) { db . query ( "SELECT unit FROM parenthoods JOIN units ON parent_unit=unit \n\
			WHERE child_unit=? AND main_chain_index=?" , [ objJoint . unit . unit , objJoint . unit . main_chain_index ] , function ( rows ) { if ( rows . length === 0 ) throw Error ( "no parents with same mci?" ) ; var arrParentUnits = rows . map ( function ( row ) { return row . unit } ) ; if ( arrParentUnits . indexOf ( objEarlierJoint . unit . unit ) >= 0 ) return onDone ( ) ; if ( arrParentUnits . length === 1 ) return addJoint ( arrParentUnits [ 0 ] , buildPathToEarlierUnit ) ; // find any parent that includes earlier unit async . eachSeries ( arrParentUnits , function ( unit , cb ) { graph . determineIfIncluded ( db , objEarlierJoint . unit . unit , [ unit ] , function ( bIncluded ) { if ( ! bIncluded ) return cb ( ) ; // try next cb ( unit ) ; // abort the eachSeries } ) ; } , function ( unit ) { if ( ! unit ) throw Error ( "none of the parents includes earlier unit" ) ; addJoint ( unit , buildPathToEarlierUnit ) ; } ) ; } ) ; } if ( objLaterJoint . unit . unit === objEarlierJoint . unit . unit ) return onDone ( ) ; ( objLaterJoint . unit . main_chain_index === objEarlierJoint . unit . main_chain_index ) ? buildPathToEarlierUnit ( objLaterJoint ) : goUp ( objLaterJoint ) ; }
build parent path from later unit to earlier unit and add all joints along the path into arrChain arrChain will include later unit but not include earlier unit assuming arrChain already includes later unit
build parent path from later unit to earlier unit and add all joints along the path into arrChain arrChain will include later unit but not include earlier unit assuming arrChain already includes later unit