Skip to content

Commit

Permalink
meta-txs: add solidity tests
Browse files Browse the repository at this point in the history
  • Loading branch information
facuspagnuolo committed May 13, 2019
1 parent d83a209 commit eab6b72
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 4 deletions.
2 changes: 1 addition & 1 deletion contracts/common/MemoryHelpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ library MemoryHelpers {
}

// From https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol
function memcpy(uint256 dest, uint256 src, uint256 len) private pure {
function memcpy(uint256 dest, uint256 src, uint256 len) internal pure {
// Copy word-length chunks while possible
for(; len >= 32; len -= 32) {
assembly {
Expand Down
11 changes: 9 additions & 2 deletions contracts/relayer/RelayedAragonApp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@ contract RelayedAragonApp is AragonApp {
}

function _decodeSigner() internal returns (address signer) {
bytes memory calldata = msg.data;
assembly { signer := mload(add(calldata, calldatasize)) }
// Note that calldatasize includes one word more than the original calldata array, due to the address of the
// that is being appended at the end of it. Thus, we are loading the last word of the calldata array to fetch
// the actual signed of the relayed call
assembly {
let ptr := mload(0x40)
mstore(0x40, add(ptr, 0x20))
calldatacopy(ptr, sub(calldatasize, 0x20), 0x20)
signer := mload(ptr)
}
}

function _relayer() internal returns (IRelayer) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/relayer/Relayer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ contract Relayer is IRelayer, AragonApp, DepositableStorage {
return keccak256(abi.encodePacked(keccak256(calldata), nonce));
}

function relayCall(address from, address to, bytes calldata) private {
function relayCall(address from, address to, bytes calldata) internal {
bytes memory encodedSignerCalldata = calldata.append(from);
assembly {
let success := call(gas, to, 0, add(encodedSignerCalldata, 0x20), mload(encodedSignerCalldata), 0, 0)
Expand Down
85 changes: 85 additions & 0 deletions contracts/test/tests/TestMemoryHelpers.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
pragma solidity 0.4.24;

import "../helpers/Assert.sol";
import "../../common/MemoryHelpers.sol";


contract TestMemoryHelpers {
using MemoryHelpers for bytes;

uint256 constant internal FIRST = uint256(10);
uint256 constant internal SECOND = uint256(1);
uint256 constant internal THIRD = uint256(15);

function testBytesArrayCopy() public {
bytes memory blob = _initializeArbitraryBytesArray();
uint256 blobSize = blob.length;
bytes memory copy = new bytes(blobSize);
uint256 input;
uint256 output;
assembly {
input := add(blob, 0x20)
output := add(copy, 0x20)
}
MemoryHelpers.memcpy(output, input, blobSize);

Assert.equal(blob.length, copy.length, "should have correct length");

uint256 firstWord = _assertEqualMemoryWord(blob, copy, 0);
Assert.equal(firstWord, FIRST, "first value should match");

uint256 secondWord = _assertEqualMemoryWord(blob, copy, 1);
Assert.equal(secondWord, SECOND, "second value should match");

uint256 thirdWord = _assertEqualMemoryWord(blob, copy, 2);
Assert.equal(thirdWord, THIRD, "third value should match");
}

function testAppendAddressToBytesArray() public {
bytes memory blob = _initializeArbitraryBytesArray();
address addr = address(0x000000000000000000000000000000000000dEaD);
bytes memory result = blob.append(addr);

Assert.equal(blob.length + 32, result.length, "should have correct length");

uint256 firstWord = _assertEqualMemoryWord(blob, result, 0);
Assert.equal(firstWord, FIRST, "first value should match");

uint256 secondWord = _assertEqualMemoryWord(blob, result, 1);
Assert.equal(secondWord, SECOND, "second value should match");

uint256 thirdWord = _assertEqualMemoryWord(blob, result, 2);
Assert.equal(thirdWord, THIRD, "third value should match");

bytes32 storedAddress;
assembly { storedAddress := mload(add(result, 0x80))}
Assert.equal(storedAddress, bytes32(0x000000000000000000000000000000000000000000000000000000000000dEaD), "appended address should match");
}

function _assertEqualMemoryWord(bytes _actual, bytes _expected, uint256 _index) private returns (uint256) {
uint256 actualValue;
uint256 expectedValue;
uint256 pos = _index * 32;
assembly {
actualValue := mload(add(add(_actual, 0x20), pos))
expectedValue := mload(add(add(_expected, 0x20), pos))
}
Assert.equal(actualValue, expectedValue, "memory values should match");
return expectedValue;
}

function _initializeArbitraryBytesArray() private pure returns (bytes memory) {
bytes memory blob = new bytes(96);

uint256 first = FIRST;
uint256 second = SECOND;
uint256 third = THIRD;
assembly {
mstore(add(blob, 0x20), first)
mstore(add(blob, 0x40), second)
mstore(add(blob, 0x60), third)
}

return blob;
}
}
49 changes: 49 additions & 0 deletions contracts/test/tests/TestRelayerCalldata.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
pragma solidity 0.4.24;

import "../helpers/Assert.sol";
import "../../relayer/Relayer.sol";
import "../../common/MemoryHelpers.sol";


contract RelayedAppTest is RelayedAragonApp {
function callme(uint8 x, bytes32 y, string z) public {
bytes memory calldata = msg.data;
// 4 32 32 32 32 32 32
// [sig][uint8][bytes32][string starting offset][string size][string word][signer]
Assert.equal(calldata.length, 4 + 32 * 6, "should have correct length");

_assertCalldataWord(0x04, bytes32(0x000000000000000000000000000000000000000000000000000000000000000f));
_assertCalldataWord(0x24, bytes32(0x0000000000000000000000000000000000000000000000000000000000000f00));
_assertCalldataWord(0x44, bytes32(0x0000000000000000000000000000000000000000000000000000000000000060));
_assertCalldataWord(0x64, bytes32(0x0000000000000000000000000000000000000000000000000000000000000007));
_assertCalldataWord(0x84, bytes32(0x72656c6179656400000000000000000000000000000000000000000000000000));
_assertCalldataWord(0xa4, bytes32(TestRelayerCalldata(msg.sender).signer()));
}

function _assertCalldataWord(uint256 _pos, bytes32 _expectedValue) private {
bytes32 actualValue;
assembly {
let ptr := mload(0x40)
mstore(0x40, add(ptr, 0x20))
calldatacopy(ptr, _pos, 0x20)
actualValue := mload(ptr)
}
Assert.equal(actualValue, _expectedValue, "calldata values should match");
}
}

contract TestRelayerCalldata is Relayer {
RelayedAppTest public appTest;

address public signer;

constructor () public {
appTest = new RelayedAppTest();
}

function testSignerEncodedCalls() public {
signer = msg.sender;
bytes memory calldata = abi.encodeWithSelector(appTest.callme.selector, uint8(15), bytes32(0xf00), "relayed");
relayCall(signer, address(appTest), calldata);
}
}
3 changes: 3 additions & 0 deletions test/contracts/common/memory_helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const runSolidityTest = require('../../helpers/runSolidityTest')

runSolidityTest('TestMemoryHelpers')
3 changes: 3 additions & 0 deletions test/contracts/relayer/relayer_calldata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const runSolidityTest = require('../../helpers/runSolidityTest')

runSolidityTest('TestRelayerCalldata')

0 comments on commit eab6b72

Please sign in to comment.