proof_chain.js
function buildLastMileOfProofChain(mci, unit, arrBalls, onDone){
	function addBall(_unit){
		db.query("SELECT unit, ball, content_hash FROM units JOIN balls USING(unit) WHERE unit=?", [_unit], function(rows){
			if (rows.length !== 1)
				throw Error("no unit?");
			var objBall = rows[0];
			if (objBall.content_hash)
				objBall.is_nonserial = true;
			delete objBall.content_hash;
			db.query(
				"SELECT ball FROM parenthoods LEFT JOIN balls ON parent_unit=balls.unit WHERE child_unit=? ORDER BY ball", 
				[objBall.unit],
				function(parent_rows){
					if (parent_rows.some(function(parent_row){ return !parent_row.ball; }))
						throw Error("some parents have no balls");
					if (parent_rows.length > 0)
						objBall.parent_balls = parent_rows.map(function(parent_row){ return parent_row.ball; });
					db.query(
						"SELECT ball \n\
						FROM skiplist_units JOIN units ON skiplist_unit=units.unit LEFT JOIN balls ON units.unit=balls.unit \n\
						WHERE skiplist_units.unit=? ORDER BY ball", 
						[objBall.unit],
						function(srows){
							if (srows.some(function(srow){ return !srow.ball; }))
								throw Error("last mile: some skiplist units have no balls");
							if (srows.length > 0)
								objBall.skiplist_balls = srows.map(function(srow){ return srow.ball; });
							arrBalls.push(objBall);
							if (_unit === unit)
								return onDone();
							findParent(_unit);
						}
					);
				}
			);
		});
	}
	
	function findParent(interim_unit){
		db.query(
			"SELECT parent_unit FROM parenthoods JOIN units ON parent_unit=unit WHERE child_unit=? AND main_chain_index=?", 
			[interim_unit, mci],
			function(parent_rows){
				var arrParents = parent_rows.map(function(parent_row){ return parent_row.parent_unit; });
				if (arrParents.indexOf(unit) >= 0)
					return addBall(unit);
				async.eachSeries(
					arrParents,
					function(parent_unit, cb){
						graph.determineIfIncluded(db, unit, [parent_unit], function(bIncluded){
							bIncluded ? cb(parent_unit) : cb();
						});
					},
					function(parent_unit){
						if (!parent_unit)
							throw Error("no parent that includes target unit");
						addBall(parent_unit);
					}
				)
			}
		);
	}
	
	// start from MC unit and go back in history
	db.query("SELECT unit FROM units WHERE main_chain_index=? AND is_on_main_chain=1", [mci], function(rows){
		if (rows.length !== 1)
			throw Error("no mc unit?");
		var mc_unit = rows[0].unit;
		if (mc_unit === unit)
			return onDone();
		findParent(mc_unit);
	});
}
function buildLastMileOfProofChain(mci, unit, arrBalls, onDone){
	function addBall(_unit){
		db.query("SELECT unit, ball, content_hash FROM units JOIN balls USING(unit) WHERE unit=?", [_unit], function(rows){
			if (rows.length !== 1)
				throw Error("no unit?");
			var objBall = rows[0];
			if (objBall.content_hash)
				objBall.is_nonserial = true;
			delete objBall.content_hash;
			db.query(
				"SELECT ball FROM parenthoods LEFT JOIN balls ON parent_unit=balls.unit WHERE child_unit=? ORDER BY ball", 
				[objBall.unit],
				function(parent_rows){
					if (parent_rows.some(function(parent_row){ return !parent_row.ball; }))
						throw Error("some parents have no balls");
					if (parent_rows.length > 0)
						objBall.parent_balls = parent_rows.map(function(parent_row){ return parent_row.ball; });
					db.query(
						"SELECT ball \n\
						FROM skiplist_units JOIN units ON skiplist_unit=units.unit LEFT JOIN balls ON units.unit=balls.unit \n\
						WHERE skiplist_units.unit=? ORDER BY ball", 
						[objBall.unit],
						function(srows){
							if (srows.some(function(srow){ return !srow.ball; }))
								throw Error("last mile: some skiplist units have no balls");
							if (srows.length > 0)
								objBall.skiplist_balls = srows.map(function(srow){ return srow.ball; });
							arrBalls.push(objBall);
							if (_unit === unit)
								return onDone();
							findParent(_unit);
						}
					);
				}
			);
		});
	}
	
	function findParent(interim_unit){
		db.query(
			"SELECT parent_unit FROM parenthoods JOIN units ON parent_unit=unit WHERE child_unit=? AND main_chain_index=?", 
			[interim_unit, mci],
			function(parent_rows){
				var arrParents = parent_rows.map(function(parent_row){ return parent_row.parent_unit; });
				if (arrParents.indexOf(unit) >= 0)
					return addBall(unit);
				async.eachSeries(
					arrParents,
					function(parent_unit, cb){
						graph.determineIfIncluded(db, unit, [parent_unit], function(bIncluded){
							bIncluded ? cb(parent_unit) : cb();
						});
					},
					function(parent_unit){
						if (!parent_unit)
							throw Error("no parent that includes target unit");
						addBall(parent_unit);
					}
				)
			}
		);
	}
	
	// start from MC unit and go back in history
	db.query("SELECT unit FROM units WHERE main_chain_index=? AND is_on_main_chain=1", [mci], function(rows){
		if (rows.length !== 1)
			throw Error("no mc unit?");
		var mc_unit = rows[0].unit;
		if (mc_unit === unit)
			return onDone();
		findParent(mc_unit);
	});
}
function buildLastMileOfProofChain ( mci , unit , arrBalls , onDone ) { function addBall ( _unit ) { db . query ( "SELECT unit, ball, content_hash FROM units JOIN balls USING(unit) WHERE unit=?" , [ _unit ] , function ( rows ) { if ( rows . length !== 1 ) throw Error ( "no unit?" ) ; var objBall = rows [ 0 ] ; if ( objBall . content_hash ) objBall . is_nonserial = true ; delete objBall . content_hash ; db . query ( "SELECT ball FROM parenthoods LEFT JOIN balls ON parent_unit=balls.unit WHERE child_unit=? ORDER BY ball" , [ objBall . unit ] , function ( parent_rows ) { if ( parent_rows . some ( function ( parent_row ) { return ! parent_row . ball ; } ) ) throw Error ( "some parents have no balls" ) ; if ( parent_rows . length > 0 ) objBall . parent_balls = parent_rows . map ( function ( parent_row ) { return parent_row . ball ; } ) ; db . query ( "SELECT ball \n\
						FROM skiplist_units JOIN units ON skiplist_unit=units.unit LEFT JOIN balls ON units.unit=balls.unit \n\
						WHERE skiplist_units.unit=? ORDER BY ball" , [ objBall . unit ] , function ( srows ) { if ( srows . some ( function ( srow ) { return ! srow . ball ; } ) ) throw Error ( "last mile: some skiplist units have no balls" ) ; if ( srows . length > 0 ) objBall . skiplist_balls = srows . map ( function ( srow ) { return srow . ball ; } ) ; arrBalls . push ( objBall ) ; if ( _unit === unit ) return onDone ( ) ; findParent ( _unit ) ; } ) ; } ) ; } ) ; } function findParent ( interim_unit ) { db . query ( "SELECT parent_unit FROM parenthoods JOIN units ON parent_unit=unit WHERE child_unit=? AND main_chain_index=?" , [ interim_unit , mci ] , function ( parent_rows ) { var arrParents = parent_rows . map ( function ( parent_row ) { return parent_row . parent_unit ; } ) ; if ( arrParents . indexOf ( unit ) >= 0 ) return addBall ( unit ) ; async . eachSeries ( arrParents , function ( parent_unit , cb ) { graph . determineIfIncluded ( db , unit , [ parent_unit ] , function ( bIncluded ) { bIncluded ? cb ( parent_unit ) : cb ( ) ; } ) ; } , function ( parent_unit ) { if ( ! parent_unit ) throw Error ( "no parent that includes target unit" ) ; addBall ( parent_unit ) ; } ) } ) ; } // start from MC unit and go back in history db . query ( "SELECT unit FROM units WHERE main_chain_index=? AND is_on_main_chain=1" , [ mci ] , function ( rows ) { if ( rows . length !== 1 ) throw Error ( "no mc unit?" ) ; var mc_unit = rows [ 0 ] . unit ; if ( mc_unit === unit ) return onDone ( ) ; findParent ( mc_unit ) ; } ) ; }
unit's MC index is mci, find a path from mci unit to this unit
unit s MC index is mci find a path from mci unit to this unit