validation/validation_byzantine.js
function validateProposalJoint(objJoint, callbacks){
	var objUnit = objJoint.unit;
	if (typeof objUnit !== "object" || objUnit === null)
		return callbacks.ifInvalid("no unit object");
	
	console.log("\nvalidating joint identified by unit "+objJoint.unit.unit);
	
	if (!isStringOfLength(objUnit.unit, constants.HASH_LENGTH))
		return callbacks.ifInvalid("wrong unit length");
	
	// UnitError is linked to objUnit.unit, so we need to ensure objUnit.unit is true before we throw any UnitErrors
	if (objectHash.getProposalUnitHash(objUnit) !== objUnit.unit){
		// console.log("888888888888888888888888--Proposal joint : " + JSON.stringify(objJoint));
		return callbacks.ifInvalid("wrong proposal unit hash: "+objectHash.getProposalUnitHash(objUnit)+" != "+objUnit.unit);
	}
	

	if (hasFieldsExcept(objUnit, ["unit", "version", "alt" ,"round_index","pow_type","timestamp", "parent_units", "last_ball", "last_ball_unit", "messages", "hp"]))
		return callbacks.ifInvalid("unknown fields in nonserial unit");
	
	if (objUnit.version !== constants.version)
		return callbacks.ifInvalid("wrong version");
	if (objUnit.alt !== constants.alt)
		return callbacks.ifInvalid("wrong alt");
	if (typeof objUnit.round_index !== "number")
		return callbacks.ifInvalid("no round index");
	if (typeof objUnit.pow_type !== "number")
		return callbacks.ifInvalid("no pow_type type");
	if (typeof objUnit.hp !== "number")
		return callbacks.ifInvalid("no hp type");
	
	// pow_type type should be 2 for trustme 
	if ( objUnit.pow_type !==  constants.POW_TYPE_TRUSTME)
		return callbacks.ifInvalid("invalid unit type");
	// unity round index should be in range of [1,4204800]
	if ( objUnit.round_index < 1 || objUnit.round_index > 4204800)
		return callbacks.ifInvalid("invalid unit round index");
	
	if (!isNonemptyArray(objUnit.messages))
		return callbacks.ifInvalid("missing or empty messages array");
	// only one 'data_feed' message allowed in trust me units.
	if (objUnit.messages.length !== 1) 
		return callbacks.ifInvalid("only one message allowed in proposal unit");
	
	// Joint fields validation   add last_ball_mci for only proposal joint, used for final trustme unit
	if (hasFieldsExcept(objJoint, ["unit", "proposer", "phase", "address","last_ball_mci", "idv","vp","isValid","sig"]))
		return callbacks.ifInvalid("unknown fields in joint unit " + json.stringify(objJoint));
	
	if (typeof objJoint.phase !== "number" || objJoint.phase < 0 )
		return callbacks.ifInvalid("joint phase invalid");
	if(objJoint.proposer && objJoint.proposer.length !== 1)
		return callbacks.ifInvalid("multiple proposers are not allowed");
		
	var conn = null;
	var objValidationState = { };
	async.series(
		[
			function(cb){
				db.takeConnectionFromPool(function(new_conn){
					conn = new_conn;
					conn.query("BEGIN", function(){cb();});
				});
			},
			function(cb){
				//validate roundIndex and hp (mci) to see if I am sync with proposer mci
				//if not, return -1 to let caller knows .
				round.getCurrentRoundIndex(conn, function(curRoundIndex){
					if(objUnit.round_index < curRoundIndex)
						return cb("proposer's round_index is too old, curRoundIndex: " + curRoundIndex + " proposer round_index: " +objUnit.round_index );
					if(objUnit.round_index > curRoundIndex)
						return cb({error_code: "unresolved_dependency", errorMessage:"propose round_index is ahead of me , curRoundIndex: " + curRoundIndex + " proposer round_index: " +objUnit.round_index });
					storage.getMaxMci(conn,function(curMCI){
						if(objUnit.hp < curMCI + 1) // recieve old proposal
							return cb("proposal hp is old, will discard it");
						if(objUnit.hp > curMCI + 1 ) // propose mci is ahead of me 
							return cb({error_code: "unresolved_dependency", errorMessage:"propose mci is ahead of me, will handle it once come up with it " });
						cb();
					});
				});
			},
			function(cb){
				validateParents(conn, objJoint, objValidationState, cb);
			},
			// function(cb){
			// 	profiler.stop('validation-parents');
			// 	profiler.start();
			// 	!objJoint.skiplist_units
			// 		? cb()
			// 		: validateSkiplist(conn, objJoint.skiplist_units, cb);
			// },
			function(cb){
				// validate proposer ID
				byzantine.getCoordinators(conn, objUnit.hp, objJoint.phase, function(err, proposer, round_index, witnesses){	
					if(err)
						return cb("error occured when getCoordinators err:" + err);		
					if(proposer !== objJoint.proposer[0].address)
						return cb("proposer incorrect,Expected: "+ proposer +" Actual :" + objJoint.proposer[0].address);
					if(round_index !== objUnit.round_index)
						return cb("proposer round_index incorrect ,Expected: "+ round_index +" Actual :" + objUnit.round_index);
					objValidationState.unit_hash_to_sign = objectHash.getProposalHashToSign(objUnit);
					//validate proposer signature
					validateProposer(conn, objJoint.proposer[0], objUnit, objValidationState, cb);
				});
			},
			function(cb){ // check timestamp is near to mine in data feed message 
			 	validateDataFeedMessage(conn, objUnit.messages[0], objUnit, objValidationState, cb);
			},
		], 
		function(err){
			if(!err){
				conn.query("COMMIT", function(){
					conn.release();
					callbacks.ifOk();
				});
			}
			else{
			//Error occured here
			conn.query("ROLLBACK", function(){
				conn.release();
				if (typeof err === "object"){
					if (err.error_code === "unresolved_dependency"){
						console.log(err.errorMessage);
						callbacks.ifNeedWaiting(err.errorMessage);
					}
					else
						throw Error("unknown error code");
				}
				else
					callbacks.ifInvalid(err);
				});
			}
			
		}
	); // async.series
	
}
function validateProposalJoint(objJoint, callbacks){
	var objUnit = objJoint.unit;
	if (typeof objUnit !== "object" || objUnit === null)
		return callbacks.ifInvalid("no unit object");
	
	console.log("\nvalidating joint identified by unit "+objJoint.unit.unit);
	
	if (!isStringOfLength(objUnit.unit, constants.HASH_LENGTH))
		return callbacks.ifInvalid("wrong unit length");
	
	// UnitError is linked to objUnit.unit, so we need to ensure objUnit.unit is true before we throw any UnitErrors
	if (objectHash.getProposalUnitHash(objUnit) !== objUnit.unit){
		// console.log("888888888888888888888888--Proposal joint : " + JSON.stringify(objJoint));
		return callbacks.ifInvalid("wrong proposal unit hash: "+objectHash.getProposalUnitHash(objUnit)+" != "+objUnit.unit);
	}
	

	if (hasFieldsExcept(objUnit, ["unit", "version", "alt" ,"round_index","pow_type","timestamp", "parent_units", "last_ball", "last_ball_unit", "messages", "hp"]))
		return callbacks.ifInvalid("unknown fields in nonserial unit");
	
	if (objUnit.version !== constants.version)
		return callbacks.ifInvalid("wrong version");
	if (objUnit.alt !== constants.alt)
		return callbacks.ifInvalid("wrong alt");
	if (typeof objUnit.round_index !== "number")
		return callbacks.ifInvalid("no round index");
	if (typeof objUnit.pow_type !== "number")
		return callbacks.ifInvalid("no pow_type type");
	if (typeof objUnit.hp !== "number")
		return callbacks.ifInvalid("no hp type");
	
	// pow_type type should be 2 for trustme 
	if ( objUnit.pow_type !==  constants.POW_TYPE_TRUSTME)
		return callbacks.ifInvalid("invalid unit type");
	// unity round index should be in range of [1,4204800]
	if ( objUnit.round_index < 1 || objUnit.round_index > 4204800)
		return callbacks.ifInvalid("invalid unit round index");
	
	if (!isNonemptyArray(objUnit.messages))
		return callbacks.ifInvalid("missing or empty messages array");
	// only one 'data_feed' message allowed in trust me units.
	if (objUnit.messages.length !== 1) 
		return callbacks.ifInvalid("only one message allowed in proposal unit");
	
	// Joint fields validation   add last_ball_mci for only proposal joint, used for final trustme unit
	if (hasFieldsExcept(objJoint, ["unit", "proposer", "phase", "address","last_ball_mci", "idv","vp","isValid","sig"]))
		return callbacks.ifInvalid("unknown fields in joint unit " + json.stringify(objJoint));
	
	if (typeof objJoint.phase !== "number" || objJoint.phase < 0 )
		return callbacks.ifInvalid("joint phase invalid");
	if(objJoint.proposer && objJoint.proposer.length !== 1)
		return callbacks.ifInvalid("multiple proposers are not allowed");
		
	var conn = null;
	var objValidationState = { };
	async.series(
		[
			function(cb){
				db.takeConnectionFromPool(function(new_conn){
					conn = new_conn;
					conn.query("BEGIN", function(){cb();});
				});
			},
			function(cb){
				//validate roundIndex and hp (mci) to see if I am sync with proposer mci
				//if not, return -1 to let caller knows .
				round.getCurrentRoundIndex(conn, function(curRoundIndex){
					if(objUnit.round_index < curRoundIndex)
						return cb("proposer's round_index is too old, curRoundIndex: " + curRoundIndex + " proposer round_index: " +objUnit.round_index );
					if(objUnit.round_index > curRoundIndex)
						return cb({error_code: "unresolved_dependency", errorMessage:"propose round_index is ahead of me , curRoundIndex: " + curRoundIndex + " proposer round_index: " +objUnit.round_index });
					storage.getMaxMci(conn,function(curMCI){
						if(objUnit.hp < curMCI + 1) // recieve old proposal
							return cb("proposal hp is old, will discard it");
						if(objUnit.hp > curMCI + 1 ) // propose mci is ahead of me 
							return cb({error_code: "unresolved_dependency", errorMessage:"propose mci is ahead of me, will handle it once come up with it " });
						cb();
					});
				});
			},
			function(cb){
				validateParents(conn, objJoint, objValidationState, cb);
			},
			// function(cb){
			// 	profiler.stop('validation-parents');
			// 	profiler.start();
			// 	!objJoint.skiplist_units
			// 		? cb()
			// 		: validateSkiplist(conn, objJoint.skiplist_units, cb);
			// },
			function(cb){
				// validate proposer ID
				byzantine.getCoordinators(conn, objUnit.hp, objJoint.phase, function(err, proposer, round_index, witnesses){	
					if(err)
						return cb("error occured when getCoordinators err:" + err);		
					if(proposer !== objJoint.proposer[0].address)
						return cb("proposer incorrect,Expected: "+ proposer +" Actual :" + objJoint.proposer[0].address);
					if(round_index !== objUnit.round_index)
						return cb("proposer round_index incorrect ,Expected: "+ round_index +" Actual :" + objUnit.round_index);
					objValidationState.unit_hash_to_sign = objectHash.getProposalHashToSign(objUnit);
					//validate proposer signature
					validateProposer(conn, objJoint.proposer[0], objUnit, objValidationState, cb);
				});
			},
			function(cb){ // check timestamp is near to mine in data feed message 
			 	validateDataFeedMessage(conn, objUnit.messages[0], objUnit, objValidationState, cb);
			},
		], 
		function(err){
			if(!err){
				conn.query("COMMIT", function(){
					conn.release();
					callbacks.ifOk();
				});
			}
			else{
			//Error occured here
			conn.query("ROLLBACK", function(){
				conn.release();
				if (typeof err === "object"){
					if (err.error_code === "unresolved_dependency"){
						console.log(err.errorMessage);
						callbacks.ifNeedWaiting(err.errorMessage);
					}
					else
						throw Error("unknown error code");
				}
				else
					callbacks.ifInvalid(err);
				});
			}
			
		}
	); // async.series
	
}
function validateProposalJoint ( objJoint , callbacks ) { var objUnit = objJoint . unit ; if ( typeof objUnit !== "object" || objUnit === null ) return callbacks . ifInvalid ( "no unit object" ) ; console . log ( "\nvalidating joint identified by unit " + objJoint . unit . unit ) ; if ( ! isStringOfLength ( objUnit . unit , constants . HASH_LENGTH ) ) return callbacks . ifInvalid ( "wrong unit length" ) ; // UnitError is linked to objUnit.unit, so we need to ensure objUnit.unit is true before we throw any UnitErrors if ( objectHash . getProposalUnitHash ( objUnit ) !== objUnit . unit ) { // console.log("888888888888888888888888--Proposal joint : " + JSON.stringify(objJoint)); return callbacks . ifInvalid ( "wrong proposal unit hash: " + objectHash . getProposalUnitHash ( objUnit ) + " != " + objUnit . unit ) ; } if ( hasFieldsExcept ( objUnit , [ "unit" , "version" , "alt" , "round_index" , "pow_type" , "timestamp" , "parent_units" , "last_ball" , "last_ball_unit" , "messages" , "hp" ] ) ) return callbacks . ifInvalid ( "unknown fields in nonserial unit" ) ; if ( objUnit . version !== constants . version ) return callbacks . ifInvalid ( "wrong version" ) ; if ( objUnit . alt !== constants . alt ) return callbacks . ifInvalid ( "wrong alt" ) ; if ( typeof objUnit . round_index !== "number" ) return callbacks . ifInvalid ( "no round index" ) ; if ( typeof objUnit . pow_type !== "number" ) return callbacks . ifInvalid ( "no pow_type type" ) ; if ( typeof objUnit . hp !== "number" ) return callbacks . ifInvalid ( "no hp type" ) ; // pow_type type should be 2 for trustme  if ( objUnit . pow_type !== constants . POW_TYPE_TRUSTME ) return callbacks . ifInvalid ( "invalid unit type" ) ; // unity round index should be in range of [1,4204800] if ( objUnit . round_index < 1 || objUnit . round_index > 4204800 ) return callbacks . ifInvalid ( "invalid unit round index" ) ; if ( ! isNonemptyArray ( objUnit . messages ) ) return callbacks . ifInvalid ( "missing or empty messages array" ) ; // only one 'data_feed' message allowed in trust me units. if ( objUnit . messages . length !== 1 ) return callbacks . ifInvalid ( "only one message allowed in proposal unit" ) ; // Joint fields validation   add last_ball_mci for only proposal joint, used for final trustme unit if ( hasFieldsExcept ( objJoint , [ "unit" , "proposer" , "phase" , "address" , "last_ball_mci" , "idv" , "vp" , "isValid" , "sig" ] ) ) return callbacks . ifInvalid ( "unknown fields in joint unit " + json . stringify ( objJoint ) ) ; if ( typeof objJoint . phase !== "number" || objJoint . phase < 0 ) return callbacks . ifInvalid ( "joint phase invalid" ) ; if ( objJoint . proposer && objJoint . proposer . length !== 1 ) return callbacks . ifInvalid ( "multiple proposers are not allowed" ) ; var conn = null ; var objValidationState = { } ; async . series ( [ function ( cb ) { db . takeConnectionFromPool ( function ( new_conn ) { conn = new_conn ; conn . query ( "BEGIN" , function ( ) { cb ( ) ; } ) ; } ) ; } , function ( cb ) { //validate roundIndex and hp (mci) to see if I am sync with proposer mci //if not, return -1 to let caller knows . round . getCurrentRoundIndex ( conn , function ( curRoundIndex ) { if ( objUnit . round_index < curRoundIndex ) return cb ( "proposer's round_index is too old, curRoundIndex: " + curRoundIndex + " proposer round_index: " + objUnit . round_index ) ; if ( objUnit . round_index > curRoundIndex ) return cb ( { error_code : "unresolved_dependency" , errorMessage : "propose round_index is ahead of me , curRoundIndex: " + curRoundIndex + " proposer round_index: " + objUnit . round_index } ) ; storage . getMaxMci ( conn , function ( curMCI ) { if ( objUnit . hp < curMCI + 1 ) // recieve old proposal return cb ( "proposal hp is old, will discard it" ) ; if ( objUnit . hp > curMCI + 1 ) // propose mci is ahead of me  return cb ( { error_code : "unresolved_dependency" , errorMessage : "propose mci is ahead of me, will handle it once come up with it " } ) ; cb ( ) ; } ) ; } ) ; } , function ( cb ) { validateParents ( conn , objJoint , objValidationState , cb ) ; } , // function(cb){ // 	profiler.stop('validation-parents'); // 	profiler.start(); // 	!objJoint.skiplist_units // 		? cb() // 		: validateSkiplist(conn, objJoint.skiplist_units, cb); // }, function ( cb ) { // validate proposer ID byzantine . getCoordinators ( conn , objUnit . hp , objJoint . phase , function ( err , proposer , round_index , witnesses ) { if ( err ) return cb ( "error occured when getCoordinators err:" + err ) ; if ( proposer !== objJoint . proposer [ 0 ] . address ) return cb ( "proposer incorrect,Expected: " + proposer + " Actual :" + objJoint . proposer [ 0 ] . address ) ; if ( round_index !== objUnit . round_index ) return cb ( "proposer round_index incorrect ,Expected: " + round_index + " Actual :" + objUnit . round_index ) ; objValidationState . unit_hash_to_sign = objectHash . getProposalHashToSign ( objUnit ) ; //validate proposer signature validateProposer ( conn , objJoint . proposer [ 0 ] , objUnit , objValidationState , cb ) ; } ) ; } , function ( cb ) { // check timestamp is near to mine in data feed message  validateDataFeedMessage ( conn , objUnit . messages [ 0 ] , objUnit , objValidationState , cb ) ; } , ] , function ( err ) { if ( ! err ) { conn . query ( "COMMIT" , function ( ) { conn . release ( ) ; callbacks . ifOk ( ) ; } ) ; } else { //Error occured here conn . query ( "ROLLBACK" , function ( ) { conn . release ( ) ; if ( typeof err === "object" ) { if ( err . error_code === "unresolved_dependency" ) { console . log ( err . errorMessage ) ; callbacks . ifNeedWaiting ( err . errorMessage ) ; } else throw Error ( "unknown error code" ) ; } else callbacks . ifInvalid ( err ) ; } ) ; } } ) ; // async.series }
validate proposed value
validate proposed value