Skip to content

validate

Shardus expects a function called validate to be passed in to setup. This function is provided with the transaction as an argument passed into the function.

This function needs to return an object with the following properties: { result, reason }. result should be a boolean, reason should be a string with a descriptive reason for why the result passed or failed

The purpose of this function is to add an extra validation checkpoint for the fields passed into the transaction. It should check to make sure all the correct data types are passed in to the specific type of transaction that's about to be processed. Basically, it's just to make sure nothing was passed in as the wrong data type, or that certain fields that need to exists on objects do exist, and with the correct primitive types. You don't need to worry about this function too much for development purposes, it's just an extra precaution for the most part.

validate is where most of the the critical validation happens. But it's never a bad idea to type check before passing it along to to validate. The important part here is that result gets labeled "pass" for things to move on to the apply function, and that you pass in the timestamp to the object your return.

Here's an example of how my validate was implemented for a messaging application:

validate(tx) {

  let result = "pass";
  let reason = "";
  let timestamp = tx.timestamp;

  let srcAddress = tx.srcAcc;
  let tgtAddress = tx.tgtAcc;
  let amount = tx.amount;
  let type = tx.type;
  let sign = tx.sign;

  if (sign && typeof sign.owner !== "string") {
    result = "fail";
    reason = '"sign.owner" must be a string.';
    throw new Error(reason);
  }

  if (sign && typeof sign.sig !== "string") {
    result = "fail";
    reason = '"sign.sig" must be a string.';
    throw new Error(reason);
  }

  if (typeof type !== "string") {
    result = "fail";
    reason = '"type" must be a string.';
    throw new Error(reason);
  }

  if (srcAddress && typeof srcAddress !== "string") {
    result = "fail";
    reason = '"srcAddress" must be a string.';
    throw new Error(reason);
  }

  if (tgtAddress && typeof tgtAddress !== "string") {
    result = "fail";
    reason = '"tgtAddress" must be a string.';
    throw new Error(reason);
  }

  if (amount && typeof amount !== "number") {
    result = "fail";
    reason = '"amount" must be a number.';
    throw new Error(reason);
  }

  if (typeof timestamp !== "number") {
    result = "fail";
    reason = '"timestamp" must be a number.';
    throw new Error(reason);
  }

  return {
    result,
    reason,
    timestamp
  };

}
🚀

Although validation happen in validate function, this does not mean all the validation should happen inside validate. This function ideally would be only used to validate incoming transactions. Dapp developer may decide other type of validation in apply() function instead. This is due to major sharding implications and restrictions All you can do is check the TX fields because the data may not even exist on on the node yet. Also checking data is slow and we want a fast check to throw out badly formatted transactions. The last reason is that we have to have a queue to support partial ordering of transactions for the purpose of consensus. Even if a node had the data it would not be safe to read it too soon.