0

A client calls rest-api then it sends data to validator, the transaction processor and validator talks, finally when the validator processes the transaction and creates a block. At this point, in my case it shows the following error log:

> sawtooth-validator-default | [2018-12-31 07:36:44.519 DEBUG   
> block_validator] Adding block
> 5cad74473aec314bae031acece18fd2b3866ace5c53652118440204e71fc493f4e2251f76298dc7721e8476ad629e0ba0ac533b9fe925bcc63f29c1a6c60795a
> for processing sawtooth-validator-default | [2018-12-31 07:36:44.532
> WARNING  block_validator] Block
> 5cad74473aec314bae031acece18fd2b3866ace5c53652118440204e71fc493f4e2251f76298dc7721e8476ad629e0ba0ac533b9fe925bcc63f29c1a6c60795a
> (block_num:3,
> state:08afc967eb593120ba5db6d1db548c4b91f26801c3d290fd655a789d51753114,
> previous_block_id:b79c22c94151e76cefcb21ed3c374aa512bff68981bb6b677610e76a8c12a6b2211c3634deb31c0d46ec26f568ed98f27f571625d76e37ee160ca0a9c071ff37)
> failed validation: Block
> 5cad74473aec314bae031acece18fd2b3866ace5c53652118440204e71fc493f4e2251f76298dc7721e8476ad629e0ba0ac533b9fe925bcc63f29c1a6c60795a
> (block_num:3,
> state:08afc967eb593120ba5db6d1db548c4b91f26801c3d290fd655a789d51753114,
> previous_block_id:b79c22c94151e76cefcb21ed3c374aa512bff68981bb6b677610e76a8c12a6b2211c3634deb31c0d46ec26f568ed98f27f571625d76e37ee160ca0a9c071ff37)
> 
> failed state root hash validation. Expected
> 08afc967eb593120ba5db6d1db548c4b91f26801c3d290fd655a789d51753114 but
> got 92673edb4422d913aadb6e49fa1e82688a27589ac98acdd7a8f713d6accd1f25
> 
> ========================================================================
> 
> sawtooth-validator-default | [2018-12-31 07:36:44.532 DEBUG   
> block_validator] Removing block from processing
> 5cad74473aec314bae031acece18fd2b3866ace5c53652118440204e71fc493f4e2251f76298dc7721e8476ad629e0ba0ac533b9fe925bcc63f29c1a6c60795a

Actual expected result is: the block should be created and added to the blockchain

Frank C.
  • 7,758
  • 4
  • 35
  • 45
  • Are returning the result of your state write operation from the TP? That could be a reason. Could you share the code? – shonjs Jan 24 '19 at 16:28
  • @1sn0s yes, returning the state write operation from the TP made the problem. transaction processor code written in Javascript which has few promises made promise chain issue in setting the state. Old TP in gist https://gist.github.com/KarthickLinganathan/861fdeb360cdbec8f24367d19a29802d now its been changed , managed promises in a good way – Gowrishankar R Jan 25 '19 at 14:18

2 Answers2

1

The validator will send your TP the same transaction request multiple times. If your TP sets data on the chain with a different address and/or data hash than the validator fails the transaction. It does this for security but it has implications to your TP.

Your TP must not create addresses or data in the TP that given the same input would produce different output. The TP address and data set in the transaction must be deterministic.

If you are generating some unique bit of information (such as time or encryption) then you should do that in the client before sending it to the TP.

Updated:

As pointed out, the data being stored is an associative structure. Because the order in the native association is not deterministic, it is likely the root issue. Adding another protobuf structure to capture the name/value and adding that to an ordered array before saving the data (set) to the chain will solve that.

As per the documentation:

Data structures which don’t enforce ordered serialization (e.g. sets, maps, dicts) should be avoided.

Frank C.
  • 7,758
  • 4
  • 35
  • 45
  • Hi Frank, Even after not creating or generating any address, Still we are getting the same error. – Gowrishankar R Jan 01 '19 at 08:01
  • The data you `set` at the address, does the TP create any of the content or is it identical to the payload sent in the transaction? – Frank C. Jan 01 '19 at 08:53
  • let address="d990b8c7eac5759277b2ac7664935e3782e34d26b56aa22f21c7fc988e9f13e238353a"; It was like the below before later i changed to the above one. // let address = NAMESPACE[2] + hash(payload.id).substring(0, 64); //console.log("address :",address) – Gowrishankar R Jan 01 '19 at 09:58
  • What about the data itself that you put at that address? – Frank C. Jan 01 '19 at 13:30
  • {"Location":"test","Latitude":1,"Longitude":8} is the data we are storing at that address – Gowrishankar R Jan 03 '19 at 11:34
  • Also failed state root hash validation. Expected > 08afc967eb593120ba5db6d1db548c4b91f26801c3d290fd655a789d51753114 but > got 92673edb4422d913aadb6e49fa1e82688a27589ac98acdd7a8f713d6accd1f25, the state root hash which got other than expected is the state root hash of previous block. – Gowrishankar R Jan 03 '19 at 11:37
  • Is that a python map/dictionary? If so, that may be your problem. – Frank C. Jan 04 '19 at 00:03
  • @GowrishankarR - If you think this is the right answer, please mark it so for others. – Frank C. Jan 25 '19 at 16:35
0

The above mentioned state root problem is because of transaction processor code written in Javascript which has few promises made promise chain issue in setting the state. Manage to write the promises correctly solved my problem.

apply(transactionRequest, context) {
  var payload=cbor.decode(transactionRequest.payload)
  if (!payload.action) {
    throw new InvalidTransaction("Payload doesn't contain the 
    action");
  }                
  if (!payload.data) {
    throw new InvalidTransaction("Payload doesn't contain the Data");
  }
  let action = payload.action;
  let address = NAMESPACE + hash(payload.data.productID).substring(0, 
  64);
  switch (action) {
case "updateProduct":
      return context.getState([address])
        .then((possibleAddressValues)=>{
            let stateValue = possibleAddressValues[address];
            if (stateValue && stateValue.length) {
              let value = JSON.parse(cbor.decode(stateValue));
              console.log("decoded values : ",value)
              if (payload.data.price) {
               value.price = payload["data"]["price"]
              }
              if (payload.data.itemsInInventory) {
               value.itemsInInventory = payload["data"]["itemsInInventory"]
              }
              console.log("values after updating status : ",value)                                                   
              let entries = {
                  [address]: cbor.encode(JSON.stringify(value))
              }
              return context.setState(entries);

            }else{
                throw new InvalidTransaction("there is no Product for given Product ID : ",payload.data.purchaseId); 
            }
        })
        .catch((err)=>{
            console.log(new Date()+"Error while getting and setting confirm status for Product ID : ",payload.purchaseId );
        })
    break;
    default:
    throw new InvalidTransaction("The action is Invalid or not supported by this transaction processor");
  }
  }