Running the Fabric test network with a very basic asset based chaincode.
Using the Java SDK to submit batches of assets. All works fine until I've submitted about 75,000 transactions. At this point, the following exception starts to occur every insert. It does however appear to successfully add assets.
org.hyperledger.fabric.gateway.ContractException: Commit strategy failed
Looking at the ContractException, the proposalResponse for each peer appears to have the ChaincodeResponseStatus set to SUCCESS, and indeed the hashes of the payload responses match. There seems to be nothing within the exception to indicate something has gone wrong (apart from the presence of the exception itself).
A restart of the Java app using the SDK seems to resolve this until 75k or so inserts. No errors appear in the logs of the peers (or indeed the chaincode containers). If I add debug output to the CC, no adverse output is generated.
The steps in the submit flow at the client end are:
Send transaction proposal to peers for endorsement.
Send endorsed transaction to the orderer.
Listen for block events from peers, and look through each block for the submitted transaction ID.
The way the block events are handled depends on which commit strategy is selected, but the default behaviour is:
If an unsuccessful validation code is observed from any peer, the transaction failed validation at the peer, the ledger was not updated, and you get an exception to indicate that.
If a timeout period is reached before a result (either successful validation or connection failure) is received for all org peers, a TimeoutException occurs.
Once a successful transaction validation code has been received or a connection failure has occurred for all org peers:
If at least one successful validation code is observed, you're good.
If the block eventing connection to all peers fails without the transaction being observed, you get the "Commit strategy failed" message.
So this message is received after the transaction has been successfully endorsed and sent to the orderer, but then the block eventing connection to all peers failed and the client does not know whether or not the transaction was successful. It might have committed successfully. It might have failed. It might not have been committed at all yet.
The block eventing connections should retry and reestablish connectivity, but I have seen some cases where something in the network path is black-holing traffic for some reason. Since it seems to happen consistently for you after a certain number of transactions, it's just possible there is some issue in the client that is causing a failure over time, like a memory leak. It's worth doing some investigation.
In general, if you do have a transaction in this indeterminate state, a good approach can be to resubmit the transaction with the same transaction ID to the orderer again until you can observe the commit status and know for sure whether the transaction was successful or failed. Using the same transaction ID is important as it avoids the possibility of double-spend since Fabric will reject a transaction at validation time if that transaction ID has previously been committed, either successfully or unsuccessfully.
Related
I was going through https://hyperledger-fabric.readthedocs.io/en/latest/peers/peers.html link where 3 phases of ledger updates have been discussed. My question is with regard to phase 3.We have below text at the above link:
After a peer has successfully validated each individual transaction, it updates the ledger.Failed transactions are not applied to the ledger, but they are retained for audit purposes, as are successful transactions.
Where are these failed transactions retained, are these with peer's FileSystem?
Are Failed and Invalidated transactions the same?
They are appended to the block of the corresponding channel's chain, but they do not alter the channel's state.
With "failed" you probably refer to those transactions discarded by the chaincode's logic (those returning an HTTP 500 error on endorsement as launched by shim.Error).
With "invalidated" you probably refer to those transactions that do not fulfill the endorsement policy. For instance, individual endorsements return an HTTP 200 success code, but endorsements from different peers do not match. Another example: a MVCC_READ_CONFLICT error when trying to update the same writeset in the same block.
I'm looking for a transaction rollback. This is necessary if a chaincode transaction modifies the state, but then fails with an error before it is able to return.
I saw this is done for a pull request but I can not understand how does it works
Added support for rolling back a tx if chaincode execution fails
Someone can give me an example how does it works?
EDIT
What I'm looking for is the concept of Transaction in database(unit of work) but in Hyperledger Fabric
Let's suppose that we are going to register a product for a list of clients, if there is a problem with the registration of the product in some customer then the operation is eliminated and the registration is not made to any client
The commit you linked is no longer relevant to current Hyperledger Fabric versions. This functionality was added before v1.0, which restructured the entire framework architecture.
As of v1.0+, transactions are first simulated by endorsers, which create a signed set of state changes resulting from the chaincode. If enough endorsers sign a transaction (according to an endorsement policy), the client can then send the transaction to the ordering service for inclusion in the ledger. A transaction that results in an error in the chaincode would never get to this point, because it would fail to gather the necessary endorsements due to the error. The client must modify the transaction or request a modification of the chaincode for it to work.
Check out the Hyperledger Fabric architecture paper for a more detailed explanation, including a sequence diagram.
To my knowledge, there isn't a way to do timed transaction in Hyperledger Fabric.
Consider the use case using the marbles example. Say I want to transfer a marble 600 seconds after I received it. Does the Fabric SDK provide anyway for me to get the unix timestamp of the event when I received my marble then send another transaction to a queue that will happen exactly 600 seconds later by calculating the timestamp + 600?
As you are talking about the time when the Marbles are actually received, then in my opinion you have to write some code on both sides. i.e, both at client and the chaincode sides.
I am not sure how to do the same with only SDK/Client side code.
If you are willing to write something in your transaction processing logic, there is a method ChaincodeStubInterface.GetTxTimestamp() in the github.com/hyperledger/fabric/core/chaincode/shim package to get the time when the transaction is processed by the Fabric.
You could return the same to your SDK, and then to your external calling program. And then compute the +600 seconds and send the next transaction.
No, there is no way to automate a timed transaction from within the chaincode and it would be bad practice to try handle it there. If you try to create a timestamp from within the chaincode, it is guaranteed that all peers processing the transaction proposal will return different values as they do not all being processing the proposal at the same exact instance. Since the results sets will return non-deterministic, the transaction will always fail when it enters the validation phase. If you try to use stub.GetTxTimestamp() you will only be returning the timestamp that the client itself sent up, as per the docs.
The best way to do this is with pure sdk code. After acquiring requisite transaction proposals and sending the transaction for ordering, listen for a transaction commitment event.
Upon receiving notification of transaction commitment, you can queue up another transaction to be sent endorsement and commitment 600 seconds later. The specifics of how will differ from sdk to sdk, but all sdk's support notification of transaction commitment.
I successfully deployed my network file(.bna). Then I started a REST API using command composer-rest-server. I submit a single transaction using my front end Laravel application. When I try using for loop for submitting multiple transactions, I get an error in some time that MVCC_READ_CONFLICT. I decrease my network's bachtimeout. But the error continues. Please answer anyone if you have any idea about this issue.
Fabric vertion: 1.1.0
Composer : .19.16
Node :8.12
OS: Ubuntu 16.04
Well, MVCC_READ_CONFLICT means you are doing concurrent modification for some key in two different transactions, hence after transaction being ordered into block, whatever transaction gets in first committed while second one or subsequent transaction which works on same key marked invalid with MVCC_READ_CONFLICT.
To understand better the reason behind this status it's probably worth noting the transaction flow in fabric:
Client submit transaction proposal for endorsement sending it to endorsing peers
Endorsing peers executes simulation of chaincode where execution results are captured into Read-Write Set
Client collects endorsements and composes transaction, submitting it for ordering
Ordering service batches transactions into block employing total order of transactions
Block distributed between peers
Peer conducts validation to attest conformance with endorsement policy for each transaction
After that there is multi value concurrency control (MVCC), which checks for concurrent modifications, in fact validating keys version of RWSet and if concurrent modification detected tx invalidated with status MVCC_READ_CONFLICT
You can find more details in documentation "Transaction Flow".
lower the latency of the block creation so that blocks will be created more frequently and thus peers would be updated faster, for example, max_message_count=1 .but that may lead to some performance issue
According to architecture explained (http://hyperledger-fabric.readthedocs.io/en/latest/arch-deep-dive.html), ordering service collects transactions (RWSets) into block for distribution to committing peers. Then, committing peer validates endorsement policy and RWsets then apply the transaction to ledger.
To verify the transaction was succeeded, should client application wait until all committing peers returned "Success" event ? Or just need to verify only one "Success" event ?
To verify the transaction was succeeded, should client application
wait until all committing peers returned "Success" event ? Or just
need to verify only one "Success" event ?
Tanaka, that's a very good question!
The short answer is No.
The reason is that in contrast to existing popular blockchains, HLF has a unique transaction lifecycle which does:
A transaction is simulated on some endorser or a few endorsers
It is sent to the ordering service and is cut into some block
The block is sent to peers, and they all execute the same validation code and all validation code for a specific transaction is guaranteed to reach the same conclusion in all peers, because they run it in the same order across all of them.
Therefore, if a transaction is validated on some peer - when other peers will receive the block the transaction resides in - they will too consider it as valid.
However - a very important aspect you should consider is data availability and synchronization.
For example, if you have an application that uses 10 peers and only 1 peer got the event and the rest didn't, and you invoke another transaction on the other peers, it might be that the endorsements that the other peers will compute will be turned into an invalid transaction, because they will simulate on old data (the fact that they didn't get the event yet proves that they have not processed the block for that transaction), so you need to keep that in mind.