ethereum / solidity

Solidity, the Smart Contract Programming Language
https://soliditylang.org
GNU General Public License v3.0
23.19k stars 5.75k forks source link

Verifying Ethereum signature by Solidity: “VM Exception while processing transaction: revert” #4524

Closed s1241 closed 6 years ago

s1241 commented 6 years ago

Issue

When I want to verify the Ethereum ECDSA signature by Solidity contract that has been generated using ethereumjs I receive : “VM Exception while processing transaction: revert”. Whereas I can verify this signature by JavaScript code and ethereumjs successfully.

The entire code is presented HERE

Steps to Reproduce

I tested signature verification of the code presented HERE as follows:

running testRPC :

root@ubuntu:/home/s# testrpc
    EthereumJS TestRPC v6.0.3 (ganache-core: 2.0.2)

    Available Accounts
    ==================
    (0) 0xa1fe30d3b82fd7c563b6fc9c44f3990bfcef3ed4
    (1) 0xfadc848eea30a47a19ec8a62a42471de3e073b89
    (2) 0x162e8acc48158f4e8961865f09f8d029d625161f
    (3) 0x8f132b6c06b8a93ebc8689371c44fc8271ac9d73
    (4) 0x4741548cb9a157522b353e94b9393ec537b1e352
    (5) 0x6f786e92be3b0da9142f657a391bf7f91ae81910
    (6) 0x3e90f71ea98ea71957f0cc9a1a5c4e0ad530a381
    (7) 0xb3032b6bad1406fd6041839c4c9a0e544d3bd9a5
    (8) 0x10f4925ac27d37df3ca1e8a4df37d3a94645a1a3
    (9) 0x63021d2642b7f7581b963408436f69a6329195a8

    Private Keys
    ==================
    (0) f9059a43ab6d30687a95a5dcd2551b02f98a6abc557cacf17fb5a7586c30fc9e
    (1) b74d7dad53e04db199f06f57f4e53e4bb0914d9d5118d367b6f7a39998bb45b7
    (2) 837d2cb30033f7c218d6cd6fd4f7703f950495dae89c797e7dd01c6a469ed64c
    (3) f7c1d7df52b765609315127f664363fea5df108bf414788e6eb4905005638b5e
    (4) ec4b55a3ae654a5c2aeeeeb068c47c84808065a4a466148844763e0bdf7e87cf
    (5) d7e75efcb275f2496790c86b9a5951ab86a9361d0e55604f9409cd9a6844b595
    (6) adee6af8313963b68ce440d4ade36e7e1163d2bb9dd351152d73c6aee1b5ae95
    (7) 6f3b9662e341aaae1131522c691834e0eb4a8a7987b8c39f412334ea4fc8050d
    (8) d48189838281fd47802fe755767531433af116428379fdabadcf92779a6e157c
    (9) acde15308f46d5f96ad229eef0a8b6b20e864e05cbf7063e83249cd1b6080425

    HD Wallet
    ==================
    Mnemonic:      other shell crater issue merit system age kitchen south mother lecture embrace
    Base HD Path:  m/44'/60'/0'/0/{account_index}

    Listening on localhost:8545

And I chose the following addresses as signer / sender and recipient :

```
sender address = 0xa1fe30d3b82fd7c563b6fc9c44f3990bfcef3ed4
    recipient address = 0xfadc848eea30a47a19ec8a62a42471de3e073b89

Deploying contract:

const thisContract = new web3.eth.Contract(abi); undefined

thisContract.deploy({
... ... data: bytecode, ... ... arguments: [ "0xfadc848eea30a47a19ec8a62a42471de3e073b89", 2592000] ... ... }).send({ ... ... from: "0xa1fe30d3b82fd7c563b6fc9c44f3990bfcef3ed4", ... ... gas: 5000000 , ... ... gasPrice: '3000000000', ... ... value: 5000 ... ... }, ... ... function(error, transactionHash) { ... ... console.log(error); ... ... console.log(transactionHash); ... ... console.log('function exec'); ... ... }).then(function(newContractInstance) { ... ... console.log('Contract Instance:' + newContractInstance.options.address); ... ... }); Promise {

, domain: Domain { domain: null, _events: { removeListener: [Function: updateExceptionCapture], newListener: [Function: updateExceptionCapture], error: [Function: debugDomainError] }, _eventsCount: 3, _maxListeners: undefined, members: [] } } null 0xee77c9011a4fb4d18cdf6804007ddc6b2b05828c7b8cac28f784f7b26c0021ef function exec Contract Instance:0xa6D8893aAF5121AEfb496aB305e0DA42F71aAaa5 ```

Getting contract balance :

> web3.eth.getBalance('0xa6D8893aAF5121AEfb496aB305e0DA42F71aAaa5').then(console.log) // contract
Promise {
  <pending>,
  domain: 
   Domain {
     domain: null,
     _events: 
      { removeListener: [Function: updateExceptionCapture],
        newListener: [Function: updateExceptionCapture],
        error: [Function: debugDomainError] },
     _eventsCount: 3,
     _maxListeners: undefined,
     members: [] } }
> 5000

Signing :

```

signPayment('0xa6D8893aAF5121AEfb496aB305e0DA42F71aAaa5', 50, function(err, something) {}); //signature= 0xb6dec803b061504e22bccccffdfe26980ddaa33d650268361bec5ef4bd4a863f6ff2ee7d524f63cd82ef5634a063cd5e21f164c2ab1a6c952131308d6f46fb1200

Verifying :

```

result = isValidSignature('0xa6D8893aAF5121AEfb496aB305e0DA42F71aAaa5', 50, "0xb6dec803b061504e22bccccffdfe26980ddaa33d650268361bec5ef4bd4a863f6ff2ee7d524f63cd82ef5634a063cd5e21f164c2ab1a6c952131308d6f46fb1200", "0xa1fe30d3b82fd7c563b6fc9c44f3990bfcef3ed4"); console.log("Signature Verification Result= ", result); //result = true

## Expected Behavior

After calling `function close` `recipient` address should receive `ether` and the contract should be destroyed. However, transaction does not become complete.

## Actual Results

Call `function close` to transfer `ether` and destroy `contract`

var contractInstance = new web3.eth.Contract(abi, '0xa6D8893aAF5121AEfb496aB305e0DA42F71aAaa5'); undefined

contractInstance.options.address; '0xa6D8893aAF5121AEfb496aB305e0DA42F71aAaa5'

contractInstance.methods.close(50, "0xb6dec803b061504e22bccccffdfe26980ddaa33d650268361bec5ef4bd4a863f6ff2ee7d524f63cd82ef5634a063cd5e21f164c2ab1a6c952131308d6f46fb1200").send({ from: '0xfadc848eea30a47a19ec8a62a42471de3e073b89' }, function(error, result) { ... ... console.log(error); ... ... console.log(result) ... ... }); Promise {

, domain: Domain { domain: null, _events: { removeListener: [Function: updateExceptionCapture], newListener: [Function: updateExceptionCapture], error: [Function: debugDomainError] }, _eventsCount: 3, _maxListeners: undefined, members: [] }, _events: undefined, emit: [Function: emit], on: [Function: on], once: [Function: once], off: [Function: removeListener], listeners: [Function: listeners], addListener: [Function: on], removeListener: [Function: removeListener], removeAllListeners: [Function: removeAllListeners] } Error: Returned error: VM Exception while processing transaction: revert at Object.ErrorResponse (/home/s/node_modules/web3-core-helpers/src/errors.js:29:16) at /home/s/node_modules/web3-core-requestmanager/src/index.js:140:36 at XMLHttpRequest.request.onreadystatechange (/home/s/node_modules/web3-providers-http/src/index.js:77:13) at XMLHttpRequestEventTarget.dispatchEvent (/home/s/node_modules/xhr2/lib/xhr2.js:64:18) at XMLHttpRequest._setReadyState (/home/s/node_modules/xhr2/lib/xhr2.js:354:12) at XMLHttpRequest._onHttpResponseEnd (/home/s/node_modules/xhr2/lib/xhr2.js:509:12) at IncomingMessage. (/home/s/node_modules/xhr2/lib/xhr2.js:469:24) at IncomingMessage.emit (events.js:185:15) at IncomingMessage.emit (domain.js:440:23) at endReadableNT (_stream_readable.js:1106:12) at process._tickCallback (internal/process/next_tick.js:178:19) undefined
**Error:**

> **### error: VM Exception while processing transaction: revert**

And here is `testrpc` message :

eth_sendTransaction

  Transaction: 0x2dbc6d601e48f6cab5327f162ff415d4e0b11264685a7ceed90de8d77adc2d8a
  Gas usage: 31867
  Block Number: 12
  Block Time: Tue Jul 17 2018 13:56:35 GMT+0200 (CEST)
  Runtime Error: revert
And when I get `contract balance` it's still `5000` :

web3.eth.getBalance('0xa6D8893aAF5121AEfb496aB305e0DA42F71aAaa5').then(console.log) // contract Promise {

, domain: Domain { domain: null, _events: { removeListener: [Function: updateExceptionCapture], newListener: [Function: updateExceptionCapture], error: [Function: debugDomainError] }, _eventsCount: 3, _maxListeners: undefined, members: [] } } 5000 ```

Note 1: When I remove signature from function close as follows, transferring ether is done, since when I get contract balance it becomes zero. However, with signature I receive the above error message.

 function close(uint256 amount) public {

            recipient.transfer(amount);
            selfdestruct(sender);
        }

Note 2:

Meanwhile I added a new function as follow to get value of message in :

`bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));`

by which I can get value of recoverSigner(message, signature) :

So I defined following function and deployed contract again :

```

function returnMsg(uint256 amount) public

    returns (bytes32)

    {
        bytes32 message = prefixed(keccak256(abi.encodePacked(this, amount)));
        return message;
    }

However, I could not get value of `message` and I only received transaction receipt as follows:

contractInstance.methods.returnMsg(50).send({ from: '0x39969849de82f978e9f356ffa5516f8d25f44ddc' }, function(error, result) { ... ... console.log(error); ... ... console.log(result) ... ... }); Promise {

, domain: Domain { domain: null, _events: { removeListener: [Function: updateExceptionCapture], newListener: [Function: updateExceptionCapture], error: [Function: debugDomainError] }, _eventsCount: 3, _maxListeners: undefined, members: [] }, _events: undefined, emit: [Function: emit], on: [Function: on], once: [Function: once], off: [Function: removeListener], listeners: [Function: listeners], addListener: [Function: on], removeListener: [Function: removeListener], removeAllListeners: [Function: removeAllListeners] } null 0xb6dc221924f4ce6fffe184297b68649cf5ec2ab64c8413a20c9f0d1d8233f04c ```

And when I get transaction status "contract address is "null" : "

    ```
> var receipt = web3.eth.getTransactionReceipt('0xb6dc221924f4ce6fffe184297b68649cf5ec2ab64c8413a20c9f0d1d8233f04c').then(console.log);
    undefined
    > { transactionHash: '0xb6dc221924f4ce6fffe184297b68649cf5ec2ab64c8413a20c9f0d1d8233f04c',
      transactionIndex: 0,
      blockHash: '0xf65f637eba42b5fb29dfa051ea8d3c1bc876395210fe635b3dd7333a8a7f7307',
      blockNumber: 2,
      gasUsed: 22861,
      cumulativeGasUsed: 22861,
      contractAddress: null,
      logs: [],
      status: true }

**Important Note:** _Please note that verifying signature using `JavaScript` is verified however apparently by `Solidity` code it is not verified and I think because of this transaction is reverted, Since as I mentioned in my question, without signature verification `ether` is transferred and contract is destroyed._

## Environment

* Operating System: Ubuntu (using VM Ware)
* Ethereum client: EthereumJS TestRPC v6.0.3 (ganache-core: 2.0.2)
* Truffle version (`truffle version`): I do not use truffle
* node version (`node --version`):  v9.11.1
* npm version (`npm --version`):  6.0.0
chriseth commented 6 years ago

Such problems are usually caused by not setting the EVM version of the runtime to the latest version (byzantium) - especially if it works in some environments but not in all. Could you please check that? Thanks!

chriseth commented 6 years ago

Closed due to inactivity. Please reopen if the issue persists of if you have more questions.