Skip to content
This repository was archived by the owner on Apr 12, 2021. It is now read-only.

First draft of changes #301

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ contract OVM_L1CrossDomainMessenger is iOVM_L1CrossDomainMessenger, Abs_BaseCros
iOVM_CanonicalTransactionChain(resolve("OVM_CanonicalTransactionChain")).enqueue(
resolve("OVM_L2CrossDomainMessenger"),
_gasLimit,
_message
_message,
0, ""
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_MerkleTree } from "../../libraries/utils/Lib_MerkleTree.sol";
import { Lib_Math } from "../../libraries/utils/Lib_Math.sol";
import { ReplayProtection } from "../../libraries/standards/ReplayProtection.sol";

/* Interface Imports */
import { iOVM_CanonicalTransactionChain } from "../../iOVM/chain/iOVM_CanonicalTransactionChain.sol";
Expand All @@ -30,7 +31,7 @@ import { OVM_ExecutionManager } from "../execution/OVM_ExecutionManager.sol";
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_AddressResolver {
contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_AddressResolver, ReplayProtection {

/*************
* Constants *
Expand Down Expand Up @@ -263,16 +264,21 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
return uint40(queue().length() / 2);
}


/**
* Adds a transaction to the queue.
* @param _target Target L2 contract to send the transaction to.
* @param _gasLimit Gas limit for the enqueued L2 transaction.
* @param _data Transaction data.
* @param _nonce Replay protection nonce
* @param _signature Signature
*/
function enqueue(
address _target,
uint256 _gasLimit,
bytes memory _data
bytes memory _data,
uint _nonce,
bytes memory _signature
)
override
public
Expand Down Expand Up @@ -312,9 +318,18 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
i++;
}

address signer;
if(_signature.length != 0) {
// Extract signer's address.
bytes32 message = keccak256(abi.encode("enqueue", _target, _gasLimit, _data, address(this), _nonce));
signer = checkSignatureAndReplayProtection(message, _nonce, _signature); // Throws if signature or replay protection is invalid
} else {
signer = msg.sender;
}

bytes32 transactionHash = keccak256(
abi.encode(
msg.sender,
signer,
_target,
_gasLimit,
_data
Expand All @@ -336,7 +351,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad

uint256 queueIndex = queue.length() / 2;
emit TransactionEnqueued(
msg.sender,
signer,
_target,
_gasLimit,
_data,
Expand All @@ -348,9 +363,13 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
/**
* Appends a given number of queued transactions as a single batch.
* @param _numQueuedTransactions Number of transactions to append.
* @param _nonce Replay protection nonce
* @param _signature Signature
*/
function appendQueueBatch(
uint256 _numQueuedTransactions
uint256 _numQueuedTransactions,
uint _nonce,
bytes memory _signature
)
override
public
Expand All @@ -364,11 +383,20 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
"Must append more than zero transactions."
);

address signer;
if(_signature.length != 0) {
// Extract signer's address.
bytes32 message = keccak256(abi.encode("appendQueueBatch", _numQueuedTransactions, address(this), _nonce));
signer = checkSignatureAndReplayProtection(message, _nonce, _signature); // Throws if signature or replay protection is invalid
} else {
signer = msg.sender;
}

bytes32[] memory leaves = new bytes32[](_numQueuedTransactions);
uint40 nextQueueIndex = getNextQueueIndex();

for (uint256 i = 0; i < _numQueuedTransactions; i++) {
if (msg.sender != resolve("OVM_Sequencer")) {
if (signer != resolve("OVM_Sequencer")) {
Lib_OVMCodec.QueueElement memory el = getQueueElement(nextQueueIndex);
require(
el.timestamp + forceInclusionPeriodSeconds < block.timestamp,
Expand Down Expand Up @@ -422,8 +450,17 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
"Actual batch start index does not match expected start index."
);

address signer = msg.sender;
// if(_signature.length == 0) {
// // Extract signer's address.
// bytes32 message = keccak256(abi.encode("appendSequencerBatch", address(this), _nonce));
// signer = checkSignatureAndReplayProtection(message, _nonce, _signature); // Throws if signature or replay protection is invalid
// } else {
// signer = msg.sender;
// }

require(
msg.sender == resolve("OVM_Sequencer"),
signer == resolve("OVM_Sequencer"),
"Function can only be called by the Sequencer."
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pragma experimental ABIEncoderV2;
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_MerkleTree } from "../../libraries/utils/Lib_MerkleTree.sol";
import { ReplayProtection } from "../../libraries/standards/ReplayProtection.sol";

/* Interface Imports */
import { iOVM_FraudVerifier } from "../../iOVM/verification/iOVM_FraudVerifier.sol";
Expand All @@ -27,7 +28,7 @@ import '@openzeppelin/contracts/math/SafeMath.sol';
* Compiler used: solc
* Runtime target: EVM
*/
contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, Lib_AddressResolver {
contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, Lib_AddressResolver, ReplayProtection {

/*************
* Constants *
Expand Down Expand Up @@ -126,7 +127,9 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, Lib_AddressResol
*/
function appendStateBatch(
bytes32[] memory _batch,
uint256 _shouldStartAtElement
uint256 _shouldStartAtElement,
uint _nonce,
bytes memory _signature
)
override
public
Expand All @@ -138,9 +141,18 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, Lib_AddressResol
"Actual batch start index does not match expected start index."
);

address signer;
if(_signature.length != 0) {
// Extract signer's address.
bytes32 message = keccak256(abi.encode("appendStateBatch", _batch, _shouldStartAtElement, address(this), _nonce));
signer = checkSignatureAndReplayProtection(message, _nonce, _signature); // Throws if signature or replay protection is invalid
} else {
signer = msg.sender;
}

// Proposers must have previously staked at the BondManager
require(
iOVM_BondManager(resolve("OVM_BondManager")).isCollateralized(msg.sender),
iOVM_BondManager(resolve("OVM_BondManager")).isCollateralized(signer),
"Proposer does not have enough collateral posted"
);

Expand All @@ -158,21 +170,34 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, Lib_AddressResol
// to be used in the fraud proofs
_appendBatch(
_batch,
abi.encode(block.timestamp, msg.sender)
abi.encode(block.timestamp, signer),
signer
);
}

/**
* @inheritdoc iOVM_StateCommitmentChain
*/
function deleteStateBatch(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
uint _nonce,
bytes memory _signature
)
override
public
{

address signer;
if(_signature.length != 0) {
// Extract signer's address.
bytes32 message = keccak256(abi.encode("deleteStateBatch", _batchHeader, address(this), _nonce));
signer = checkSignatureAndReplayProtection(message, _nonce, _signature); // Throws if signature or replay protection is invalid
} else {
signer = msg.sender;
}

require(
msg.sender == resolve("OVM_FraudVerifier"),
signer == resolve("OVM_FraudVerifier"),
"State batches can only be deleted by the OVM_FraudVerifier."
);

Expand Down Expand Up @@ -312,17 +337,19 @@ contract OVM_StateCommitmentChain is iOVM_StateCommitmentChain, Lib_AddressResol
* Appends a batch to the chain.
* @param _batch Elements within the batch.
* @param _extraData Any extra data to append to the batch.
* @param _signer Signer's address (verified in parent call).
*/
function _appendBatch(
bytes32[] memory _batch,
bytes memory _extraData
bytes memory _extraData,
address _signer
)
internal
{
address sequencer = resolve("OVM_Sequencer");
(uint40 totalElements, uint40 lastSequencerTimestamp) = _getBatchExtraData();

if (msg.sender == sequencer) {
if (_signer == sequencer) {
lastSequencerTimestamp = uint40(block.timestamp);
} else {
// We keep track of the last batch submitted by the sequencer so there's a window in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ contract OVM_FraudVerifier is Lib_AddressResolver, Abs_FraudContributor, iOVM_Fr

// Delete the state batch.
ovmStateCommitmentChain.deleteStateBatch(
_postStateRootBatchHeader
_postStateRootBatchHeader, 0, ""
);

// Get the timestamp and publisher for that block.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,20 +184,28 @@ interface iOVM_CanonicalTransactionChain {
* @param _target Target contract to send the transaction to.
* @param _gasLimit Gas limit for the given transaction.
* @param _data Transaction data.
* @param _nonce Replay protection nonce.
* @param _signature Signature.
*/
function enqueue(
address _target,
uint256 _gasLimit,
bytes memory _data
bytes memory _data,
uint _nonce,
bytes memory _signature
)
external;

/**
* Appends a given number of queued transactions as a single batch.
* @param _numQueuedTransactions Number of transactions to append.
* @param _nonce Replay protection nonce.
* @param _signature Signature.
*/
function appendQueueBatch(
uint256 _numQueuedTransactions
uint256 _numQueuedTransactions,
uint _nonce,
bytes memory _signature
)
external;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,27 @@ interface iOVM_StateCommitmentChain {
* Appends a batch of state roots to the chain.
* @param _batch Batch of state roots.
* @param _shouldStartAtElement Index of the element at which this batch should start.
* @param _nonce Replay protection nonce.
* @param _signature Signature.
*/
function appendStateBatch(
bytes32[] calldata _batch,
uint256 _shouldStartAtElement
uint256 _shouldStartAtElement,
uint _nonce,
bytes memory _signature
)
external;

/**
* Deletes all state roots after (and including) a given batch.
* @param _batchHeader Header of the batch to start deleting from.
* @param _nonce Replay protection nonce.
* @param _signature Signature.
*/
function deleteStateBatch(
Lib_OVMCodec.ChainBatchHeader memory _batchHeader
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
uint _nonce,
bytes memory _signature
)
external;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
pragma solidity >=0.5.16 <0.8.0;

/* External Imports */
import "@openzeppelin/contracts/cryptography/ECDSA.sol";

contract ReplayProtection {

/*********************
* Replay protection *
********************/
mapping(address => uint) nonce;

/**
* Throws if the replay protection is incorrect for the signer.
* It will check that the submitted nonce is greater than the nonce stored. Unlike Ethereum which requires it
* to strictly increment by 1.
*
* @param _hash Hash of message to be signed.
* @param _nonce Replay protection nonce.
* @param _signature Signature to verify.
* @return Signer's address.
*/
function checkSignatureAndReplayProtection(bytes32 _hash, uint _nonce, bytes memory _signature) internal returns(address) {
address signer = ECDSA.recover(_hash, _signature);
require(_nonce > nonce[signer], "Transaction already submitted by signer");
nonce[signer] = _nonce; // Re-use storage to minimise gas cost
return signer;
}
}
2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const config: HardhatUserConfig = {
},
},
typechain: {
outDir: 'build/types',
outDir: 'src/types',
target: 'ethers-v5',
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,19 @@ describe('OVM_L1CrossDomainMessenger', () => {
OVM_L1CrossDomainMessenger.sendMessage(target, message, gasLimit)
).to.not.be.reverted

console.log(
JSON.stringify(
Mock__OVM_CanonicalTransactionChain.smocked.enqueue.calls[0]
)
)
expect(
Mock__OVM_CanonicalTransactionChain.smocked.enqueue.calls[0]
).to.deep.equal([
Mock__OVM_L2CrossDomainMessenger.address,
BigNumber.from(gasLimit),
getXDomainCalldata(await signer.getAddress(), target, message, 0),
BigNumber.from('0'),
'0x',
])
})

Expand Down
Loading