Skip to content

Commit

Permalink
Merge branch 'arbitrary-message-bridging-#73' into amb-erc677-erc677
Browse files Browse the repository at this point in the history
# Conflicts:
#	contracts/interfaces/IAMB.sol
  • Loading branch information
patitonar committed Aug 22, 2019
2 parents 66e8bbe + 6f8221a commit 6eaf28a
Show file tree
Hide file tree
Showing 22 changed files with 270 additions and 131 deletions.
1 change: 1 addition & 0 deletions contracts/ERC677BridgeTokenRewardable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ contract ERC677BridgeTokenRewardable is ERC677BridgeToken {

function setStakingContract(address _stakingContract) external onlyOwner {
require(AddressUtils.isContract(_stakingContract));
require(balanceOf(_stakingContract) == 0);
stakingContract = _stakingContract;
}

Expand Down
1 change: 1 addition & 0 deletions contracts/interfaces/IAMB.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity 0.4.24;
interface IAMB {
function messageSender() external view returns (address);
function maxGasPerTx() external view returns (uint256);
function transactionHash() external view returns (bytes32);
function withdrawFromDeposit(address _recipient) external;
function requireToPassMessage(address _contract, bytes _data, uint256 _gas) external;
function requireToPassMessage(address _contract, bytes _data, uint256 _gas, uint256 _gasPrice) external;
Expand Down
28 changes: 11 additions & 17 deletions contracts/libraries/ArbitraryMessage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import "./Message.sol";
library ArbitraryMessage {
// layout of message :: bytes:
// offset 0: 32 bytes :: uint256 - message length
// offset 32: 20 bytes :: address - sender address
// offset 52: 20 bytes :: address - executor contract
// offset 72: 32 bytes :: bytes32 txHash
// offset 32: 32 bytes :: bytes32 txHash
// offset 52: 20 bytes :: address - sender address
// offset 72: 20 bytes :: address - executor contract
// offset 104: 32 bytes :: uint256 - gasLimit
// offset 136: 1 bytes :: bytes1 - dataType
// (optional) 137: 32 bytes :: uint256 - gasPrice
Expand Down Expand Up @@ -40,41 +40,35 @@ library ArbitraryMessage {
{
uint256 dataOffset = 0;
uint256 datasize;
// 20 (sender) + 20 (executor) + 32 (tx hash) + 32 (gasLimit) + 1 (dataType)
uint256 srcdataptr = 20 + 20 + 32 + 32 + 1;
// 32 (tx hash) + 20 (sender) + 20 (executor) + 32 (gasLimit) + 1 (dataType)
uint256 srcdataptr = 32 + 20 + 20 + 32 + 1;
assembly {
sender := and(mload(add(_data, 20)), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
executor := and(mload(add(_data, 40)), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
txHash := mload(add(_data, 72))
txHash := mload(add(_data, 32))
sender := mload(add(_data, 52))
executor := mload(add(_data, 72))
gasLimit := mload(add(_data, 104))
dataType := and(mload(add(_data, 136)), 0xFF00000000000000000000000000000000000000000000000000000000000000)
switch dataType
case 0x0000000000000000000000000000000000000000000000000000000000000000 {
gasPrice := 0
if eq(applyDataOffset, 1) {
dataOffset := sub(srcdataptr, 9)
}
}
case 0x0100000000000000000000000000000000000000000000000000000000000000 {
gasPrice := mload(add(_data, 137)) // 32
srcdataptr := add(srcdataptr, 0x20)
if eq(applyDataOffset, 1) {
dataOffset := sub(srcdataptr, 41)
}
}
case 0x0200000000000000000000000000000000000000000000000000000000000000 {
gasPrice := 0
srcdataptr := add(srcdataptr, 0x01)
if eq(applyDataOffset, 1) {
dataOffset := sub(srcdataptr, 10)
}
}
datasize := sub(mload(_data), srcdataptr)
}
data = new bytes(datasize);
assembly {
// BYTES_HEADER_SIZE
let dataptr := add(data, 32)
if eq(applyDataOffset, 1) {
dataOffset := 32
}
// 68 = 4 (selector) + 32 (bytes header) + 32 (bytes length)
calldatacopy(dataptr, add(add(68, srcdataptr), dataOffset), datasize)
}
Expand Down
35 changes: 35 additions & 0 deletions contracts/libraries/Message.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,41 @@ library Message {
}
}

function hasEnoughValidSignatures(
bytes _message,
bytes _signatures,
IBridgeValidators _validatorContract,
bool isAMBMessage
) internal view {
require(isAMBMessage || (!isAMBMessage && isMessageValid(_message)));
uint256 requiredSignatures = _validatorContract.requiredSignatures();
uint8 amount;
assembly {
amount := mload(add(_signatures, 1))
}
require(amount >= requiredSignatures);
bytes32 hash = hashMessage(_message, isAMBMessage);
address[] memory encounteredAddresses = new address[](requiredSignatures);

for (uint256 i = 0; i < requiredSignatures; i++) {
uint8 v;
bytes32 r;
bytes32 s;
uint256 posr = 33 + amount + 32 * i;
uint256 poss = posr + 32 * amount;
assembly {
v := mload(add(_signatures, add(2, i)))
r := mload(add(_signatures, posr))
s := mload(add(_signatures, poss))
}

address recoveredAddress = ecrecover(hash, v, r, s);
require(_validatorContract.isValidator(recoveredAddress));
require(!addressArrayContains(encounteredAddresses, recoveredAddress));
encounteredAddresses[i] = recoveredAddress;
}
}

function uintToString(uint256 i) internal pure returns (string) {
if (i == 0) return "0";
uint256 j = i;
Expand Down
2 changes: 2 additions & 0 deletions contracts/mocks/Box.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import "../interfaces/IAMB.sol";
contract Box {
uint256 public value;
address public lastSender;
bytes32 public txHash;

function setValue(uint256 _value) public {
value = _value;
lastSender = IAMB(msg.sender).messageSender();
txHash = IAMB(msg.sender).transactionHash();
}

function methodWillFail() public {
Expand Down
4 changes: 1 addition & 3 deletions contracts/mocks/MessageTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ contract MessageTest {

function unpackDataWithExtraParams(
bytes _data,
uint8[], /*vs*/
bytes32[], /*rs*/
bytes32[] /*ss*/
bytes /*signatures*/
)
public
pure
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import "./MessageProcessor.sol";
import "../MessageRelay.sol";

contract BasicForeignAMB is BasicAMB, MessageRelay, MessageDelivery, MessageProcessor {
function executeSignatures(bytes _data, uint8[] vs, bytes32[] rs, bytes32[] ss) external {
Message.hasEnoughValidSignatures(_data, vs, rs, ss, validatorContract(), true);
function executeSignatures(bytes _data, bytes _signatures) external {
Message.hasEnoughValidSignatures(_data, _signatures, validatorContract(), true);

address sender;
address executor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ contract BasicHomeAMB is BasicAMB, MessageDelivery, MessageProcessor {

function signature(bytes32 _hash, uint256 _index) public view returns (bytes) {
bytes32 signIdx = keccak256(abi.encodePacked(_hash, _index));
return signatures(signIdx);
return bytesStorage[keccak256(abi.encodePacked("signatures", signIdx))];
}

function messagesSigned(bytes32 _message) public view returns (bool) {
Expand All @@ -120,10 +120,6 @@ contract BasicHomeAMB is BasicAMB, MessageDelivery, MessageProcessor {
return bytesStorage[keccak256(abi.encodePacked("messages", _hash))];
}

function signatures(bytes32 _hash) internal view returns (bytes) {
return bytesStorage[keccak256(abi.encodePacked("signatures", _hash))];
}

function setSignatures(bytes32 _hash, bytes _signature) internal {
bytesStorage[keccak256(abi.encodePacked("signatures", _hash))] = _signature;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ contract ForeignAMB is BasicForeignAMB {
event UserRequestForAffirmation(bytes encodedData);
event RelayedMessage(address sender, address executor, bytes32 transactionHash, bool status);

function getMaxGasPerTx() internal returns (uint256) {
return maxGasPerTx();
}

function isMessageDeliverySubsidizedMode() internal returns (bool) {
return foreignToHomeMode() == SUBSIDIZED_MODE;
}
Expand Down
4 changes: 0 additions & 4 deletions contracts/upgradeable_contracts/arbitrary_message/HomeAMB.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ contract HomeAMB is BasicHomeAMB {
event UserRequestForSignature(bytes encodedData);
event AffirmationCompleted(address sender, address executor, bytes32 transactionHash, bool status);

function getMaxGasPerTx() internal returns (uint256) {
return maxGasPerTx();
}

function isMessageDeliverySubsidizedMode() internal returns (bool) {
return homeToForeignMode() == SUBSIDIZED_MODE;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./BasicAMB.sol";

contract MessageDelivery {
contract MessageDelivery is BasicAMB {
using SafeMath for uint256;

function requireToPassMessage(address _contract, bytes _data, uint256 _gas) public {
require(isMessageDeliverySubsidizedMode());
require(_gas >= getMinimumGasUsage(_data) && _gas <= getMaxGasPerTx());
require(_gas >= getMinimumGasUsage(_data) && _gas <= maxGasPerTx());
emitEventOnMessageRequest(abi.encodePacked(msg.sender, _contract, _gas, uint8(0x00), _data));
}

function requireToPassMessage(address _contract, bytes _data, uint256 _gas, uint256 _gasPrice) public {
if (isMessageDeliverySubsidizedMode()) requireToPassMessage(_contract, _data, _gas);
else {
require(_gas >= getMinimumGasUsage(_data) && _gas <= getMaxGasPerTx());
require(_gas >= getMinimumGasUsage(_data) && _gas <= maxGasPerTx());
emitEventOnMessageRequest(abi.encodePacked(msg.sender, _contract, _gas, uint8(0x01), _gasPrice, _data));
}
}

function requireToPassMessage(address _contract, bytes _data, uint256 _gas, bytes1 _oracleGasPriceSpeed) public {
if (isMessageDeliverySubsidizedMode()) requireToPassMessage(_contract, _data, _gas);
else {
require(_gas >= getMinimumGasUsage(_data) && _gas <= getMaxGasPerTx());
require(_gas >= getMinimumGasUsage(_data) && _gas <= maxGasPerTx());
emitEventOnMessageRequest(
abi.encodePacked(msg.sender, _contract, _gas, uint8(0x02), _oracleGasPriceSpeed, _data)
);
Expand All @@ -35,8 +36,6 @@ contract MessageDelivery {
return _data.length.mul(68);
}

function getMaxGasPerTx() internal returns (uint256);

function isMessageDeliverySubsidizedMode() internal returns (bool);

function emitEventOnMessageRequest(bytes encodedData) internal;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "./BalanceHandler.sol";
contract MessageProcessor is BalanceHandler {
uint256 internal constant PASS_MESSAGE_GAS = 100000;
bytes32 internal constant MESSAGE_SENDER = keccak256(abi.encodePacked("messageSender"));
bytes32 internal constant TRANSACTION_HASH = keccak256(abi.encodePacked("transactionHash"));

function messageSender() external view returns (address) {
return addressStorage[MESSAGE_SENDER];
Expand All @@ -14,6 +15,20 @@ contract MessageProcessor is BalanceHandler {
addressStorage[MESSAGE_SENDER] = _sender;
}

function transactionHash() external view returns (bytes32) {
return getTransactionHash(bytesStorage[TRANSACTION_HASH]);
}

function getTransactionHash(bytes _txHash) internal view returns (bytes32 result) {
assembly {
result := mload(add(_txHash, 32))
}
}

function setTransactionHash(bytes32 _txHash) internal {
bytesStorage[TRANSACTION_HASH] = abi.encodePacked(_txHash);
}

function processMessage(
address sender,
address executor,
Expand All @@ -27,22 +42,22 @@ contract MessageProcessor is BalanceHandler {

if (dataType == 0x00) {
require(isMessageProcessorSubsidizedMode());
status = _passMessage(sender, executor, data, gasLimit);
status = _passMessage(sender, executor, data, gasLimit, txHash);
} else if (dataType == 0x01) {
require(!isMessageProcessorSubsidizedMode());
require(gasPrice == tx.gasprice);
status = _defrayAndPassMessage(sender, executor, data, gasLimit);
status = _defrayAndPassMessage(sender, executor, data, gasLimit, txHash);
} else if (dataType == 0x02) {
require(!isMessageProcessorSubsidizedMode());
status = _defrayAndPassMessage(sender, executor, data, gasLimit);
status = _defrayAndPassMessage(sender, executor, data, gasLimit, txHash);
} else {
status = false;
}

emitEventOnMessageProcessed(sender, executor, txHash, status);
}

function _defrayAndPassMessage(address _sender, address _contract, bytes _data, uint256 _gas)
function _defrayAndPassMessage(address _sender, address _contract, bytes _data, uint256 _gas, bytes32 _txHash)
internal
returns (bool)
{
Expand All @@ -52,23 +67,28 @@ contract MessageProcessor is BalanceHandler {

setBalanceOf(_sender, balanceOf(_sender).sub(fee));

bool status = _passMessage(_sender, _contract, _data, _gas);
bool status = _passMessage(_sender, _contract, _data, _gas, _txHash);

msg.sender.transfer(fee);

return status;
}

function _passMessage(address _sender, address _contract, bytes _data, uint256 _gas) internal returns (bool) {
function _passMessage(address _sender, address _contract, bytes _data, uint256 _gas, bytes32 _txHash)
internal
returns (bool)
{
if (_contract == address(this)) {
//Special check to handle invocation of withdrawFromDeposit
if (isWithdrawFromDepositSelector(_data)) {
setAccountForAction(_sender);
}
}
setMessageSender(_sender);
setTransactionHash(_txHash);
bool status = _contract.call.gas(_gas)(_data);
setMessageSender(address(0));
setTransactionHash(bytes32(0));
return status;
}

Expand Down
7 changes: 6 additions & 1 deletion deploy/src/erc_to_erc/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ const {
} = require('../loadContracts')

const VALIDATORS = env.VALIDATORS.split(' ')
const VALIDATORS_REWARD_ACCOUNTS = env.VALIDATORS_REWARD_ACCOUNTS.split(' ')

const {
DEPLOYMENT_ACCOUNT_PRIVATE_KEY,
Expand Down Expand Up @@ -60,6 +59,12 @@ const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVAT

const isRewardableBridge = HOME_REWARDABLE === 'BOTH_DIRECTIONS'

let VALIDATORS_REWARD_ACCOUNTS = []

if (isRewardableBridge && BLOCK_REWARD_ADDRESS === ZERO_ADDRESS) {
VALIDATORS_REWARD_ACCOUNTS = env.VALIDATORS_REWARD_ACCOUNTS.split(' ')
}

async function initializeBridge({ validatorsBridge, bridge, erc677token, initialNonce }) {
let nonce = initialNonce
let initializeHomeBridgeData
Expand Down
11 changes: 8 additions & 3 deletions deploy/src/erc_to_native/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const {
} = require('../loadContracts')

const VALIDATORS = env.VALIDATORS.split(' ')
const VALIDATORS_REWARD_ACCOUNTS = env.VALIDATORS_REWARD_ACCOUNTS.split(' ')

const {
BLOCK_REWARD_ADDRESS,
Expand All @@ -51,6 +50,12 @@ const DEPLOYMENT_ACCOUNT_ADDRESS = privateKeyToAddress(DEPLOYMENT_ACCOUNT_PRIVAT
const isRewardableBridge = HOME_REWARDABLE === 'BOTH_DIRECTIONS'
const isFeeManagerPOSDAO = HOME_FEE_MANAGER_TYPE === 'POSDAO_REWARD'

let VALIDATORS_REWARD_ACCOUNTS = []

if (isRewardableBridge && !isFeeManagerPOSDAO) {
VALIDATORS_REWARD_ACCOUNTS = env.VALIDATORS_REWARD_ACCOUNTS.split(' ')
}

async function initializeBridge({ validatorsBridge, bridge, initialNonce }) {
let nonce = initialNonce
let initializeHomeBridgeData
Expand Down Expand Up @@ -175,7 +180,7 @@ async function deployHome() {
nonce++

console.log('\ndeploying implementation for home validators')
const bridgeValidatorsContract = isRewardableBridge ? RewardableValidators : BridgeValidators
const bridgeValidatorsContract = isRewardableBridge && !isFeeManagerPOSDAO ? RewardableValidators : BridgeValidators
const bridgeValidatorsHome = await deployContract(bridgeValidatorsContract, [], {
from: DEPLOYMENT_ACCOUNT_ADDRESS,
nonce
Expand All @@ -197,7 +202,7 @@ async function deployHome() {
bridgeValidatorsHome.options.address = storageValidatorsHome.options.address
await initializeValidators({
contract: bridgeValidatorsHome,
isRewardableBridge,
isRewardableBridge: isRewardableBridge && !isFeeManagerPOSDAO,
requiredNumber: REQUIRED_NUMBER_OF_VALIDATORS,
validators: VALIDATORS,
rewardAccounts: VALIDATORS_REWARD_ACCOUNTS,
Expand Down
Loading

0 comments on commit 6eaf28a

Please sign in to comment.