fabric
fabric copied to clipboard
there is no mechanisms to abort chaincode even if it has an infinite loop
Description
If chaincode includes an infinite loop, it keeps running and there is no mechanism to abort chaincode. This happens both in invoke and query transactions. If an infinite loop is within a Query transaction, then the validating peer detects timeout. However, the chaincode docker container keeps running even after VP returns the error.
I think the validating peer should monitor the chaincode, and abort it when it is not responding for a pre-defined period of time.
Describe How to Reproduce
write an infinite loop within invoke or query transaction.
func (this *MyCode) simpleLoop(db *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
this.logger = shim.NewLogger("MyCode")
x := 0
for ; ; {
this.logger.Infof("simpleLoop, count=%d", x)
x++
}
}
...
func (this *MyCode) Query(db *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
return this.simpleLoop(db, function, args)
}
func (this *MyCode) Invoke(db *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
return this.simpleLoop(db, function, args)
}
How about we start thinking about how to sidestep an unsolvable problem and use a deterministic, terminating language instead?
The peer needs to act like a hypervisor. There are any number of things that a chaincode could do that might be construed as violating some resource constraint (heap, stack, cores, local storage, putstate, etc). If/when it does, the peer should be able to enforce restrictions/penalties (such as denying additional heap or terminating the process). Excessive runtime is just one such parameter.
I agree that the ideal is to provide a runtime language that is as conducive to writing deterministic/terminating programs as possible. However, I don't think we should solely rely on this to protect the kernel. For one thing, you always need to ensure that all operational constraints are adhered to (e.g. deterministic code could still ask for too much heap/putstate). Secondly, we don't only need to protect runtime: compile time can arguably be riskier for a platform (at least with GPLs).
how about just stopping and destroying the container if a query/invoke times out ? Its kind of worst case but a timeout on a request borders on "unexpected / bad" behavior
@muralisrini I agree with you. I think it is a simple and practical approach.
There is gas for Ethereum. Could we use the similar concept?