From 1b301d5ead2ba9d0b5d601697221ee8731350a96 Mon Sep 17 00:00:00 2001 From: Joel Burget Date: Sat, 8 Sep 2018 10:38:54 -0700 Subject: [PATCH] Fix consensus on private contract failure. Previously we had populated the public receipt `failed` field with the result of the transaction. This is correct for public transactions. It's also correct for successful private transactions. But it's not correct for failing private transactions, because their public receipt should not indicate failure. The fix is straightforward. Testing: I used this contract: contract RevertTest{ uint public newValue; function revertFunction() public{ uint a = 1; require(a == 0); } } After deploying the contract I sent in several failing transactions via function sendBad() { eth.sendTransaction({ from: eth.accounts[0], data: web3.sha3("revertFunction()"), gas: 0x47b760, privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="] }); } Watching the logs (`1.log` and `2.log`), I saw the `TX-ACCEPTED` events scroll as I sent `revertFunction` transactions. I see 10 `TX-ACCEPTED` events in both logs (1 for deploy and 9 tests via `sendBad`). Via extra logging, in `1.log` I see that the public receipts have status `1`, whereas private receipts have status `0`. In `2.log` they all have status `1`. All nodes stayed up the whole time. Fixes #434 --- core/state_processor.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/state_processor.go b/core/state_processor.go index 7d59ed54b..e46406cb8 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -117,6 +117,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmenv := vm.NewEVM(context, statedb, privateState, config, cfg) + // Apply the transaction to the current state (included in the env) _, gas, failed, err := ApplyMessage(vmenv, msg, gp) if err != nil { @@ -132,9 +133,13 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common } usedGas.Add(usedGas, gas) + // If this is a private transaction, the public receipt should always + // indicate success. + publicFailed := !(config.IsQuorum && tx.IsPrivate()) && failed + // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing wether the root touch-delete accounts. - receipt := types.NewReceipt(root, failed, usedGas) + receipt := types.NewReceipt(root, publicFailed, usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) // if the transaction created a contract, store the creation address in the receipt.