Attachment resolution failure for


(Jiachuan Li) #1

Hi Team

I used AngularJS to invoke Corda web api to upload one document and received the hash code successfully, and refer to the attachment demo code, I just simply added one addAttachment method to add this attachment hash code to the intial transaction(with SecureHash.parse function to parse the returned string type hash code to secure hash format), the iou.iou.userFileHash is actually the returned hash code and I can see it is correct in debug, but when I execute this code, there is one exception “Attachment resolution failure for hashcode”, and after search this error key word in Corda’s core project, I found this should be caused by “if a required attachment was not found in storage”, this storage is the db and this error should be due to the attachment is not stored in DB, am I correct? But actually it already stored in the attachment table in the database so the upload attachment api could return the hash code to me. So could you please help to provide some comments about what is the matter? Thanks in advance.

// Generate an unsigned transaction.
val txCommand = Command(IOUContract.Commands.Create(), iou.participants.map { it.owningKey })
val unsignedTx = TransactionType.General.Builder(notary).withItems(iou, txCommand)
unsignedTx.addAttachment(SecureHash.parse(iou.iou.userFileHash))


(Mike Hearn) #2

When you upload an attachment you get a hash returned from the server. Does it match the hash you’re expecting?


(Jiachuan Li) #3

Hi Mike

Resolved this issue by referring to this thread Attachment Resolution failure in M9.1

By using ResolveTransactionsFlow in recipient side, the attachment was retrieved before doing verify. But one question is from the documentation, ResolveTransactionsFlow should be used to verify the transaction chain, so
Question 1 would be whether we always need to invoke it to verify the transaction chain or its depends on do we want to do it or not. As the tutorial doesn’t invoke it, so I am not sure whether it’s due to it is tutorial which is not focus on the transaction chain verification part.
Question 2 would be if ResolveTransactionsFlow is not a required method or we can say we don’t need always verify the transaction chain, but now we only can use it to retrieve the attachment, and this transaction is the initial transaction.

@srinidhi, I saw your issues still hasn’t been resolved at last in that thread, so just share my fixing for your reference. I added the ResolveTransactionsFlow in Acceptor’s unwrap function, code as below

val partSignedTx = receive<SignedTransaction>(otherParty).unwrap { partSignedTx ->
    val wtx = partSignedTx.tx  //WireTransaction
    // Stage 6.
    progressTracker.currentStep = VERIFYING_TRANSACTION
    // Check that the signature of the other party is valid.
    // Our signature and the notary's signature are allowed to be omitted at this stage as this is only
    // a partially signed transaction.
    val wireTx = partSignedTx.verifySignatures(publicKey, notaryPubKey)

    subFlow(ResolveTransactionsFlow(wireTx, otherParty))

    // Run the contract's verify function.
    // We want to be sure that the agreed-upon IOU is valid under the rules of the contract.
    // To do this we need to run the contract's verify() function.
    wireTx.toLedgerTransaction(serviceHub).verify()
    // We've verified the signed transaction and return it.
    partSignedTx
}

(Roger Willis) #4

Attachments and input states in transactions are only references - this is very important to remember. You always need to call ResolveTransactionFlow to resolve the input state and attachment references to get the actual data. Only once you have the data, can you verify the transaction. Most of the time ResolveTransactionsFlow is called on your behalf e.g. in CollectSignaturesFlow and SignTransactionFlow.

Important to note: When you ever try to verify a transaction and you get a ‘resolution exception’ or whenever you expect to see an attachment or state in a node’s storage service/vault and it’s not there then it’s because ResolveTransactionsFlow has not been called. Also, the latter issue can sometimes be caused by not broadcasting a finalised transaction to all required parties via the FainalityFlow.


(Jiachuan Li) #5

Thanks Roger, got it.


(Sean Zhang) #6

If the initiator runs the FinalityFlow, the attachment will be also loaded on the acceptor node.
Of course, where to run FinalityFlow is subject to your flow design

\Sean


(Jiachuan Li) #7

So you mean before send the transaction to the counterpart, send it to the notary firstly by FinalityFlow, and once received the notary’s signature, then send it to the counterpart to request approve. By this approach, the attachment will be loaded on the counterpart node automatically but no need to invoke ResolveTransactionsFlow. Am I correct?


(Sean Zhang) #8

What that meant is that in some flow design, once the initiator has gathered the counter parties signatures (remember the transaction only has the hashes of the attachments so it can be signed without the attachments), it just runs the FinalityFlow which among other things, will send the attachments to the counter parties without the need for them to run ResolveTransactionFlow.
But I like your way better because the acceptor has a chance to see the actual attachments before signing the transaction.

\Sean


(Sean Zhang) #9

Then again, according to Mike Hearn on a recent slacker post:

you should always use FinalityFlow
other flows will be encapsulated at some point in the next few months, you won’t be able to call them at all

So, I am not sure if ResolveTransactionsFlow is one of them.

\Sean


(Ajitha) #10

@lijiachuan, @mike,
Can you please help me with the details of how to upload a document using a web api to corda store instead of using the rpc client?

Thanks
Ajitha