Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues With Memory String Consumption In Smart Contracts #80

Open
baxterjfinch opened this issue May 3, 2021 · 2 comments
Open

Issues With Memory String Consumption In Smart Contracts #80

baxterjfinch opened this issue May 3, 2021 · 2 comments

Comments

@baxterjfinch
Copy link

baxterjfinch commented May 3, 2021

When attempting to consume a String in a contract function, ExW3 seems to handle encoding improperly, causing variables to mix and or set improperly in the contracts state.

Smart Contract Example:

pragma solidity >=0.4.22 <0.9.0;

contract Tester {
  address public currentAddr;
  uint256 public currentInt;
  string public sym;

  function setOnlyStringBefore(string memory _sym, address new_addr, uint256 new_int) public {
    currentAddr = new_addr;
    currentInt = new_int;
    sym = _sym;
  }

  function setOnlyStringAfter(address new_addr, uint256 new_int, string memory _sym) public {
    currentAddr = new_addr;
    currentInt = new_int;
    sym = _sym;
  }

  function setOnlyAddrAndInt(address new_addr, uint256 new_int) public {
    currentAddr = new_addr;
    currentInt = new_int;
  }
}

Scenario 1

(Function setOnlyStringBefore) - string is set before address and uint256 in smart contract function parameters

Using ExW3 ->
ExW3.Contract.send(:Tester, :setOnlyStringBefore, ["name", "0x0255bff90b8787f06cf13ab325997cbf3b139c1d", 10], %{from: @contracts_owner, gas: 6000000})

{:ok, "0x1c6ac0864e8e6418cfc743200ee74ad06bb2442bd5842fd73c2d12bb835db0dc"}

In Truffle ->

truffle(k8s)> let test = await Tester.deployed()

truffle(k8s)> test.sym()

Thrown:
{ Error: invalid codepoint at offset 14; unexpected continuation byte (argument="bytes", value={"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":2,"13":85,"14":191,"15":249,"16":11,"17":135,"18":135,"19":240,"20":108,"21":241,"22":58,"23":179,"24":37,"25":153,"26":124,"27":191,"28":59,"29":19,"30":156,"31":29,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":10,"64":0,"65":0,"66":0,"67":0,"68":0,"69":0,"70":0,"71":0,"72":0,"73":0,"74":0,"75":0,"76":0,"77":0,"78":0,"79":0,"80":0,"81":0,"82":0,"83":0,"84":0,"85":0,"86":0,"87":0,"88":0,"89":0,"90":0,"91":0,"92":0,"93":0,"94":0,"95":4}, code=INVALID_ARGUMENT, version=strings/5.0.5)
    at evalmachine.<anonymous>:0:6
    at sigintHandlersWrap (vm.js:288:15)
    at Script.runInContext (vm.js:130:14)
    at runScript (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/console.js:251:1)
    at Console.interpret (/usr/local/lib/node_modules/truffle/build/webpack:/packages/core/lib/console.js:266:1)
    at bound (domain.js:402:14)
    at REPLServer.runBound [as eval] (domain.js:415:12)
    at REPLServer.onLine (repl.js:642:10)
    at REPLServer.emit (events.js:198:13)
    at REPLServer.EventEmitter.emit (domain.js:448:20)
    at REPLServer.Interface._onLine (readline.js:308:10)
    at REPLServer.Interface._line (readline.js:656:8)
    at REPLServer.Interface._ttyWrite (readline.js:937:14)
    at REPLServer.self._ttyWrite (repl.js:715:7)
    at ReadStream.onkeypress (readline.js:184:10)
    at ReadStream.emit (events.js:198:13)
    at ReadStream.EventEmitter.emit (domain.js:448:20)
    at emitKeys (internal/readline.js:424:14)
    at emitKeys.next (<anonymous>)
    at ReadStream.onData (readline.js:1073:36)
    at ReadStream.emit (events.js:198:13)
    at ReadStream.EventEmitter.emit (domain.js:448:20)
    at addChunk (_stream_readable.js:288:12)
    at readableAddChunk (_stream_readable.js:269:11)
    at ReadStream.Readable.push (_stream_readable.js:224:10)
    at TTY.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
  reason:
   'invalid codepoint at offset 14; unexpected continuation byte',
  code: 'INVALID_ARGUMENT',
  argument: 'bytes',
  value:
   Uint8Array [
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     2,
     85,
     191,
     249,
     11,
     135,
     135,
     240,
     108,
     241,
     58,
     179,
     37,
     153,
     124,
     191,
     59,
     19,
     156,
     29,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     10,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     0,
     4 ],
  baseType: 'string',
  name: null,
  type: 'string',
  hijackedStack:
   'Error: invalid codepoint at offset 14; unexpected continuation byte (argument="bytes", value={"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":2,"13":

truffle(k8s)> test.currentAddr()
'0x0000000000000000000000000000000000000060'

truffle(k8s)> test.currentInt()
<BN: 255bff90b8787f06cf13ab325997cbf3b139c1d>

Note: The transaction is successful but the sym is set as a byte array and the address and uint256 values are swapped. They are passed in as

[name, new_addr, new_int]

and the function consumes them as

(string memory _sym, address new_addr, uint256 new_int)

however you can see in the above .currentAddr() and .currentInt() that the addr is set as a hex encoded value of 10 and the int is set as a BigNumber conversion of the address.

Note: This function is successful when called directly from truffle

truffle(k8s)> test.setOnlyStringBefore("Name", "0xfe5e669eD4C62A7D4621A604BcC1029171814046", 10)
{ tx:
   '0x1e7f54778810d2ea33b604dc2e1791b05b69540cd77a2357e8572f3f3f580588',
  receipt:
   { blockHash:
      '0x28a3a821daf8b6d8844b330f355ac74e46ee46c900f1be5b748c166357b044c2',
     blockNumber: 878,
     contractAddress: null,
     cumulativeGasUsed: 85007,
     from: '0xfe5e669ed4c62a7d4621a604bcc1029171814046',
     gasUsed: 85007,
     logs: [],
     logsBloom:
      '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
     status: true,
     to: '0x3c7d058ccb934c732674e28b4c45bcc722fb0004',
     transactionHash:
      '0x1e7f54778810d2ea33b604dc2e1791b05b69540cd77a2357e8572f3f3f580588',
     transactionIndex: 0,
     rawLogs: [] },
  logs: [] }

truffle(k8s)> test.sym()

'Name'

truffle(k8s)> test.currentAddr()

'0xfe5e669eD4C62A7D4621A604BcC1029171814046'

truffle(k8s)> test.currentInt()

<BN: a>


Scenerio 2

### (Function setOnlyStringAfter) - string is set after address and uint256 in smart contract function parameters

ExW3.Contract.send(:Tester, :setOnlyStringAfter, [10, "0x0255bff90b8787f06cf13ab325997cbf3b139c1d", "name"], %{from: @contracts_owner, gas: 6000000})

{:ok, "0xcb1e0f29d7a0fa5bc7822c2d9302b12cc5a22b02a52323d3ac3bad1a01b64634"}

In Truffle ->

truffle(k8s)> let test = await Tester.deployed()

truffle(k8s)> test.sym()

'' //// <--- Value never got set

truffle(k8s)> web3.eth.getTransactionReceipt("0xcb1e0f29d7a0fa5bc7822c2d9302b12cc5a22b02a52323d3ac3bad1a01b64634")
{ blockHash:
   '0x146459c31989cc9cfe8ae9025c31701566b5a3da14b74f8e69b97bfe4290d983',
  blockNumber: 877,
  contractAddress: null,
  cumulativeGasUsed: 24203,
  from: '0xfe5e669ed4c62a7d4621a604bcc1029171814046',
  gasUsed: '0x5e8b',
  logs: [],
  logsBloom:
   '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
  status: false,
  to: '0x3c7d058ccb934c732674e28b4c45bcc722fb0004',
  transactionHash:
   '0xcb1e0f29d7a0fa5bc7822c2d9302b12cc5a22b02a52323d3ac3bad1a01b64634',
  transactionIndex: 0 }

Note: The transaction status is 'false', meaning that the transaction has failed for some reason.

Note: The function call is successful when called from Truffle

@aroyer
Copy link

aroyer commented May 7, 2021

good find fixed in my fork

@gregors
Copy link

gregors commented Dec 15, 2021

@aroyer looks like I found that encoding bug again independently see #109

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants