Skip to content

Commit d256809

Browse files
Clean up contracts and tests (#166)
* Moved all OVM files and deleted the package * Started cleaning contracts * Quick contract cleanup * Added cleaned contracts * Fixed package.json * Removed /ovm requirements * Fixed circular dependencies * Fixed various linting errors * Fixed yet another ganache-core issue * Fixed bug causing tests to fail * Fixed bug causing tests to fail * Merged master * Added older RLPEncode file again * Renamed rollup-contracts => contracts
1 parent 88f93e2 commit d256809

File tree

127 files changed

+5293
-4138
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+5293
-4138
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"release:alpha": "yarn clean && yarn build && lerna version prerelease --yes && lerna publish from-package --yes --force-publish --dist-tag=alpha -m \"chore(@ethereum-optimism) publish %s release\"",
2929
"release:beta": "yarn clean && yarn build && lerna version prerelease --yes && lerna publish from-package --yes --force-publish --dist-tag=beta -m \"chore(@ethereum-optimism) publish %s release\"",
3030
"patch": "yarn run patch:ganache && yarn run patch:waffle",
31-
"patch:ganache": "sed -ie 's!import { Provider as Web3Provider } from \"web3/providers\";!import { provider as Web3Provider } from \"web3-core\";!' node_modules/ganache-core/typings/index.d.ts",
31+
"patch:ganache": "sed -ie 's!import { Provider as Web3Provider } from \"web3/providers\";!import { AbstractProvider as Web3Provider } from \"web3-core\";!' node_modules/ganache-core/typings/index.d.ts",
3232
"patch:waffle": "sed -ie 's!Ganache.GanacheOpts!any!g' node_modules/ethereum-waffle/dist/waffle.d.ts"
3333
},
3434
"repository": "git+https://github.com/ethereum-optimism/optimism-monorepo.git",
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
pragma solidity ^0.5.0;
22
pragma experimental ABIEncoderV2;
33

4-
/* Internal Imports */
5-
import {DataTypes as dt} from "./DataTypes.sol";
6-
74
contract L1ToL2TransactionPasser {
8-
uint nonce = 0;
5+
/*
6+
* Events
7+
*/
98

109
event L1ToL2Transaction(
1110
uint _nonce,
@@ -14,13 +13,30 @@ contract L1ToL2TransactionPasser {
1413
bytes _callData
1514
);
1615

17-
function passTransactionToL2(address ovmEntrypoint, bytes memory ovmCalldata) public {
18-
// TODO: Actually create/enqueue a rollup block with this message. We are simply mocking this functionality for now.
16+
17+
/*
18+
* Contract Variables
19+
*/
20+
21+
uint nonce;
22+
23+
24+
/*
25+
* Public Functions
26+
*/
27+
28+
function passTransactionToL2(
29+
address _ovmEntrypoint,
30+
bytes memory _ovmCalldata
31+
) public {
32+
// TODO: Actually create/enqueue a rollup block with this message.
33+
// We are simply mocking this functionality for now.
34+
1935
emit L1ToL2Transaction(
2036
nonce++,
2137
msg.sender,
22-
ovmEntrypoint,
23-
ovmCalldata
38+
_ovmEntrypoint,
39+
_ovmCalldata
2440
);
2541
}
2642
}

packages/rollup-contracts/contracts/L2ToL1MessageReceiver.sol renamed to packages/contracts/contracts/optimistic-ethereum/bridge/L2ToL1MessageReceiver.sol

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,105 @@ pragma solidity ^0.5.0;
22
pragma experimental ABIEncoderV2;
33

44
/* Internal Imports */
5-
import {DataTypes as dt} from "./DataTypes.sol";
5+
import { DataTypes } from "../utils/DataTypes.sol";
66

77
contract L2ToL1MessageReceiver {
8+
/*
9+
* Events
10+
*/
11+
812
event L2ToL1MessageEnqueued(
913
address ovmSender,
1014
bytes callData,
1115
uint nonce
1216
);
1317

18+
19+
/*
20+
* Structs
21+
*/
22+
1423
struct EnqueuedL2ToL1Message {
15-
dt.L2ToL1Message message;
24+
DataTypes.L2ToL1Message message;
1625
uint l1BlockEnqueued;
1726
}
1827

28+
29+
/*
30+
* Contract Variables
31+
*/
32+
1933
address public sequencer;
2034
uint public blocksUntilFinal;
21-
uint messageNonce = 0;
35+
uint public messageNonce;
2236
mapping (uint => EnqueuedL2ToL1Message) public messages;
2337

38+
39+
/*
40+
* Constructor
41+
*/
42+
2443
constructor(address _sequencer, uint _blocksUntilFinal) public {
2544
sequencer = _sequencer;
2645
blocksUntilFinal = _blocksUntilFinal;
2746
}
2847

29-
function enqueueL2ToL1Message(dt.L2ToL1Message memory _message) public {
30-
require(msg.sender == sequencer, "For now, only our trusted sequencer can enqueue messages to be verified on L1");
31-
uint blockNum = block.number;
48+
49+
/*
50+
* Public Functions
51+
*/
52+
53+
function enqueueL2ToL1Message(
54+
DataTypes.L2ToL1Message memory _message
55+
) public {
56+
require(
57+
msg.sender == sequencer,
58+
"For now, only our trusted sequencer can enqueue messages."
59+
);
60+
61+
// Enqueue the message.
3262
messages[messageNonce] = EnqueuedL2ToL1Message({
3363
message: _message,
34-
l1BlockEnqueued: blockNum
64+
l1BlockEnqueued: block.number
3565
});
66+
67+
// Let the world know.
3668
emit L2ToL1MessageEnqueued(
3769
_message.ovmSender,
3870
_message.callData,
3971
messageNonce
4072
);
73+
74+
// On to the next one.
4175
messageNonce += 1;
4276
}
4377

44-
function verifyL2ToL1Message(dt.L2ToL1Message memory _message, uint _nonce) public view returns (bool) {
45-
// The enqueued message for the given nonce must match the _message being verified
78+
function verifyL2ToL1Message(
79+
DataTypes.L2ToL1Message memory _message,
80+
uint _nonce
81+
) public view returns (bool) {
82+
// The enqueued message for the given nonce must match the _message
83+
// being verified.
4684
bytes32 givenMessageHash = getMessageHash(_message);
4785
bytes32 storedMessageHash = getMessageHash(messages[_nonce].message);
4886
bool messageWasEnqueued = (storedMessageHash == givenMessageHash);
49-
// Message must be finalized on L1
50-
bool messageIsFinalized = (block.number >= messages[_nonce].l1BlockEnqueued + blocksUntilFinal);
87+
88+
// Message must be finalized on L1.
89+
bool messageIsFinalized = (
90+
block.number >= messages[_nonce].l1BlockEnqueued + blocksUntilFinal
91+
);
92+
5193
return messageWasEnqueued && messageIsFinalized;
5294
}
5395

54-
function getMessageHash(dt.L2ToL1Message memory _message) internal pure returns(bytes32) {
96+
97+
/*
98+
* Internal Functions
99+
*/
100+
101+
function getMessageHash(
102+
DataTypes.L2ToL1Message memory _message
103+
) internal pure returns (bytes32) {
55104
return keccak256(abi.encode(_message));
56105
}
57106
}
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
pragma solidity ^0.5.0;
2+
pragma experimental ABIEncoderV2;
3+
4+
/* Internal Imports */
5+
import { DataTypes } from "../utils/DataTypes.sol";
6+
import { RollupMerkleUtils } from "../utils/RollupMerkleUtils.sol";
7+
import { L1ToL2TransactionQueue } from "../queue/L1ToL2TransactionQueue.sol";
8+
import { SafetyTransactionQueue } from "../queue/SafetyTransactionQueue.sol";
9+
10+
contract CanonicalTransactionChain {
11+
/*
12+
* Contract Variables
13+
*/
14+
15+
address public sequencer;
16+
uint public forceInclusionPeriod;
17+
RollupMerkleUtils public merkleUtils;
18+
L1ToL2TransactionQueue public l1ToL2Queue;
19+
SafetyTransactionQueue public safetyQueue;
20+
uint public cumulativeNumElements;
21+
bytes32[] public batches;
22+
uint public lastOVMTimestamp;
23+
24+
25+
/*
26+
* Constructor
27+
*/
28+
29+
constructor(
30+
address _rollupMerkleUtilsAddress,
31+
address _sequencer,
32+
address _l1ToL2TransactionPasserAddress,
33+
uint _forceInclusionPeriod
34+
) public {
35+
merkleUtils = RollupMerkleUtils(_rollupMerkleUtilsAddress);
36+
sequencer = _sequencer;
37+
forceInclusionPeriod = _forceInclusionPeriod;
38+
lastOVMTimestamp = 0;
39+
40+
safetyQueue = new SafetyTransactionQueue(address(this));
41+
l1ToL2Queue = new L1ToL2TransactionQueue(
42+
_l1ToL2TransactionPasserAddress,
43+
address(this)
44+
);
45+
}
46+
47+
48+
/*
49+
* Public Functions
50+
*/
51+
52+
function getBatchesLength() public view returns (uint) {
53+
return batches.length;
54+
}
55+
56+
function hashBatchHeader(
57+
DataTypes.TxChainBatchHeader memory _batchHeader
58+
) public pure returns (bytes32) {
59+
return keccak256(abi.encodePacked(
60+
_batchHeader.timestamp,
61+
_batchHeader.isL1ToL2Tx,
62+
_batchHeader.elementsMerkleRoot,
63+
_batchHeader.numElementsInBatch,
64+
_batchHeader.cumulativePrevElements
65+
));
66+
}
67+
68+
function authenticateAppend(
69+
address _sender
70+
) public view returns (bool) {
71+
return _sender == sequencer;
72+
}
73+
74+
function appendL1ToL2Batch() public {
75+
DataTypes.TimestampedHash memory l1ToL2Header = l1ToL2Queue.peek();
76+
77+
require(
78+
safetyQueue.isEmpty() || l1ToL2Header.timestamp <= safetyQueue.peekTimestamp(),
79+
"Must process older SafetyQueue batches first to enforce timestamp monotonicity"
80+
);
81+
82+
_appendQueueBatch(l1ToL2Header, true);
83+
l1ToL2Queue.dequeue();
84+
}
85+
86+
function appendSafetyBatch() public {
87+
DataTypes.TimestampedHash memory safetyHeader = safetyQueue.peek();
88+
89+
require(
90+
l1ToL2Queue.isEmpty() || safetyHeader.timestamp <= l1ToL2Queue.peekTimestamp(),
91+
"Must process older L1ToL2Queue batches first to enforce timestamp monotonicity"
92+
);
93+
94+
_appendQueueBatch(safetyHeader, false);
95+
safetyQueue.dequeue();
96+
}
97+
98+
function _appendQueueBatch(
99+
DataTypes.TimestampedHash memory timestampedHash,
100+
bool isL1ToL2Tx
101+
) internal {
102+
uint timestamp = timestampedHash.timestamp;
103+
104+
require(
105+
timestamp + forceInclusionPeriod <= now || authenticateAppend(msg.sender),
106+
"Message sender does not have permission to append this batch"
107+
);
108+
109+
lastOVMTimestamp = timestamp;
110+
bytes32 elementsMerkleRoot = timestampedHash.txHash;
111+
uint numElementsInBatch = 1;
112+
113+
bytes32 batchHeaderHash = keccak256(abi.encodePacked(
114+
timestamp,
115+
isL1ToL2Tx,
116+
elementsMerkleRoot,
117+
numElementsInBatch,
118+
cumulativeNumElements // cumulativePrevElements
119+
));
120+
121+
batches.push(batchHeaderHash);
122+
cumulativeNumElements += numElementsInBatch;
123+
}
124+
125+
function appendSequencerBatch(
126+
bytes[] memory _txBatch,
127+
uint _timestamp
128+
) public {
129+
require(
130+
authenticateAppend(msg.sender),
131+
"Message sender does not have permission to append a batch"
132+
);
133+
134+
require(
135+
_txBatch.length > 0,
136+
"Cannot submit an empty batch"
137+
);
138+
139+
require(
140+
_timestamp + forceInclusionPeriod > now,
141+
"Cannot submit a batch with a timestamp older than the sequencer inclusion period"
142+
);
143+
144+
require(
145+
_timestamp <= now,
146+
"Cannot submit a batch with a timestamp in the future"
147+
);
148+
149+
require(
150+
l1ToL2Queue.isEmpty() || _timestamp <= l1ToL2Queue.peekTimestamp(),
151+
"Must process older L1ToL2Queue batches first to enforce timestamp monotonicity"
152+
);
153+
154+
require(
155+
safetyQueue.isEmpty() || _timestamp <= safetyQueue.peekTimestamp(),
156+
"Must process older SafetyQueue batches first to enforce timestamp monotonicity"
157+
);
158+
159+
require(
160+
_timestamp >= lastOVMTimestamp,
161+
"Timestamps must monotonically increase"
162+
);
163+
164+
lastOVMTimestamp = _timestamp;
165+
166+
bytes32 batchHeaderHash = keccak256(abi.encodePacked(
167+
_timestamp,
168+
false, // isL1ToL2Tx
169+
merkleUtils.getMerkleRoot(_txBatch), // elementsMerkleRoot
170+
_txBatch.length, // numElementsInBatch
171+
cumulativeNumElements // cumulativeNumElements
172+
));
173+
174+
batches.push(batchHeaderHash);
175+
cumulativeNumElements += _txBatch.length;
176+
}
177+
178+
// verifies an element is in the current list at the given position
179+
function verifyElement(
180+
bytes memory _element, // the element of the list being proven
181+
uint _position, // the position in the list of the element being proven
182+
DataTypes.TxElementInclusionProof memory _inclusionProof // inclusion proof in the rollup batch
183+
) public view returns (bool) {
184+
// For convenience, store the batchHeader
185+
DataTypes.TxChainBatchHeader memory batchHeader = _inclusionProof.batchHeader;
186+
187+
// make sure absolute position equivalent to relative positions
188+
if (_position != _inclusionProof.indexInBatch +
189+
batchHeader.cumulativePrevElements) {
190+
return false;
191+
}
192+
193+
// verify elementsMerkleRoot
194+
if (!merkleUtils.verify(
195+
batchHeader.elementsMerkleRoot,
196+
_element,
197+
_inclusionProof.indexInBatch,
198+
_inclusionProof.siblings
199+
)) {
200+
return false;
201+
}
202+
203+
//compare computed batch header with the batch header in the list.
204+
return hashBatchHeader(batchHeader) == batches[_inclusionProof.batchIndex];
205+
}
206+
}

0 commit comments

Comments
 (0)