Commit e7196c18 authored by Karl Floersch's avatar Karl Floersch Committed by GitHub

Merge pull request #16 from ethereum-optimism/feat/correct_encoding

Add correct encoding
parents 9530e0b2 5a33924c
...@@ -31,6 +31,12 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba ...@@ -31,6 +31,12 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba
uint256 constant public MIN_ROLLUP_TX_GAS = 20000; uint256 constant public MIN_ROLLUP_TX_GAS = 20000;
uint256 constant public MAX_ROLLUP_TX_SIZE = 10000; uint256 constant public MAX_ROLLUP_TX_SIZE = 10000;
uint256 constant public L2_GAS_DISCOUNT_DIVISOR = 10; uint256 constant public L2_GAS_DISCOUNT_DIVISOR = 10;
// Encoding Constants
uint256 constant internal BATCH_CONTEXT_SIZE = 16;
uint256 constant internal BATCH_CONTEXT_LENGTH_POS = 12;
uint256 constant internal BATCH_CONTEXT_START_POS = 15;
uint256 constant internal TX_DATA_HEADER_SIZE = 3;
uint256 constant internal BYTES_TILL_TX_DATA = 66;
/************* /*************
...@@ -64,7 +70,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba ...@@ -64,7 +70,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba
forceInclusionPeriodSeconds = _forceInclusionPeriodSeconds; forceInclusionPeriodSeconds = _forceInclusionPeriodSeconds;
queue.init(100, 50, 10000000000); // TODO: Update once we have arbitrary condition queue.init(100, 50, 10000000000); // TODO: Update once we have arbitrary condition
batches.init(100, 50, 10000000000); // TODO: Update once we have arbitrary condition batches.init(2, 50, 0); // TODO: Update once we have arbitrary condition
} }
...@@ -221,15 +227,27 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba ...@@ -221,15 +227,27 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba
/** /**
* @inheritdoc iOVM_CanonicalTransactionChain * @inheritdoc iOVM_CanonicalTransactionChain
*/ */
function appendSequencerBatch( function appendSequencerBatch( // USES CUSTOM ENCODING FOR EFFICIENCY PURPOSES
bytes[] memory _transactions, // uint40 _shouldStartAtBatch,
BatchContext[] memory _contexts, // uint24 _totalElementsToAppend,
uint256 _shouldStartAtBatch, // BatchContext[] _contexts,
uint _totalElementsToAppend // bytes[] _transactionDataFields
) )
override override
public public
{ {
uint40 _shouldStartAtBatch;
uint24 _totalElementsToAppend;
uint24 _contextsLength;
assembly {
// First 5 bytes after MethodId is _shouldStartAtBatch
_shouldStartAtBatch := shr(216, calldataload(4))
// Next 3 bytes is _totalElementsToAppend
_totalElementsToAppend := shr(232, calldataload(9))
// And the last 3 bytes is the _contextsLength
_contextsLength := shr(232, calldataload(12))
}
require( require(
_shouldStartAtBatch == getTotalBatches(), _shouldStartAtBatch == getTotalBatches(),
"Actual batch start index does not match expected start index." "Actual batch start index does not match expected start index."
...@@ -241,7 +259,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba ...@@ -241,7 +259,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba
); );
require( require(
_contexts.length > 0, _contextsLength > 0,
"Must provide at least one batch context." "Must provide at least one batch context."
); );
...@@ -253,27 +271,51 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba ...@@ -253,27 +271,51 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba
bytes32[] memory leaves = new bytes32[](_totalElementsToAppend); bytes32[] memory leaves = new bytes32[](_totalElementsToAppend);
uint32 transactionIndex = 0; uint32 transactionIndex = 0;
uint32 numSequencerTransactionsProcessed = 0; uint32 numSequencerTransactionsProcessed = 0;
uint32 nextSequencerTransactionPosition = uint32(BATCH_CONTEXT_START_POS + BATCH_CONTEXT_SIZE * _contextsLength);
uint theCalldataSize;
assembly {
theCalldataSize := calldatasize()
}
require(theCalldataSize >= nextSequencerTransactionPosition, "Not enough BatchContexts provided.");
(, uint32 nextQueueIndex) = _getLatestBatchContext(); (, uint32 nextQueueIndex) = _getLatestBatchContext();
for (uint32 i = 0; i < _contexts.length; i++) { for (uint32 i = 0; i < _contextsLength; i++) {
BatchContext memory context = _contexts[i]; BatchContext memory context = _getBatchContext(i);
_validateBatchContext(context, nextQueueIndex); _validateBatchContext(context, nextQueueIndex);
for (uint32 i = 0; i < context.numSequencedTransactions; i++) { for (uint32 j = 0; j < context.numSequencedTransactions; j++) {
leaves[transactionIndex] = _hashTransactionChainElement( uint256 txDataLength;
TransactionChainElement({ assembly {
isSequenced: true, // 3 byte txDataLength
queueIndex: 0, txDataLength := shr(232, calldataload(nextSequencerTransactionPosition))
timestamp: context.timestamp, }
blockNumber: context.blockNumber,
txData: _transactions[numSequencerTransactionsProcessed] bytes memory _chainElement = new bytes(BYTES_TILL_TX_DATA + txDataLength);
}) bytes32 leafHash;
); uint _timestamp = context.timestamp;
uint _blockNumber = context.blockNumber;
assembly {
let chainElementStart := add(_chainElement, 0x20)
mstore8(chainElementStart, 1)
mstore8(add(chainElementStart, 1), 0)
mstore(add(chainElementStart, 2), _timestamp)
mstore(add(chainElementStart, 34), _blockNumber)
// Store the rest of the transaction
calldatacopy(add(chainElementStart, BYTES_TILL_TX_DATA), add(nextSequencerTransactionPosition, 3), txDataLength)
// Calculate the hash
leafHash := keccak256(chainElementStart, add(BYTES_TILL_TX_DATA, txDataLength))
}
leaves[transactionIndex] = leafHash;
nextSequencerTransactionPosition += uint32(TX_DATA_HEADER_SIZE + txDataLength);
numSequencerTransactionsProcessed++; numSequencerTransactionsProcessed++;
transactionIndex++; transactionIndex++;
} }
for (uint32 i = 0; i < context.numSubsequentQueueTransactions; i++) { for (uint32 j = 0; j < context.numSubsequentQueueTransactions; j++) {
leaves[transactionIndex] = _getQueueLeafHash(nextQueueIndex); leaves[transactionIndex] = _getQueueLeafHash(nextQueueIndex);
nextQueueIndex++; nextQueueIndex++;
transactionIndex++; transactionIndex++;
...@@ -281,7 +323,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba ...@@ -281,7 +323,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba
} }
require( require(
numSequencerTransactionsProcessed == _transactions.length, theCalldataSize == nextSequencerTransactionPosition,
"Not all sequencer transactions were processed." "Not all sequencer transactions were processed."
); );
require( require(
...@@ -307,6 +349,45 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba ...@@ -307,6 +349,45 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, OVM_Ba
* Internal Functions * * Internal Functions *
**********************/ **********************/
/**
* Returns the BatchContext located at a particular index.
* @param _index The index of the BatchContext
* @return _context The BatchContext at the specified index.
*/
function _getBatchContext(
uint _index
)
internal
view
returns (
BatchContext memory _context
)
{
// Batch contexts always start at byte 12:
// 4[method_id] + 5[_shouldStartAtBatch] + 3[_totalElementsToAppend] + 3[numBatchContexts]
uint contextPosition = 15 + _index * BATCH_CONTEXT_SIZE;
uint numSequencedTransactions;
uint numSubsequentQueueTransactions;
uint ctxTimestamp;
uint ctxBlockNumber;
assembly {
// 3 byte numSequencedTransactions
numSequencedTransactions := shr(232, calldataload(contextPosition))
// 3 byte numSubsequentQueueTransactions
numSubsequentQueueTransactions := shr(232, calldataload(add(contextPosition, 3)))
// 5 byte timestamp
ctxTimestamp := shr(216, calldataload(add(contextPosition, 6)))
// 5 byte blockNumber
ctxBlockNumber := shr(216, calldataload(add(contextPosition, 11)))
}
return BatchContext({
numSequencedTransactions: numSequencedTransactions,
numSubsequentQueueTransactions: numSubsequentQueueTransactions,
timestamp: ctxTimestamp,
blockNumber: ctxBlockNumber
});
}
/** /**
* Parses the batch context from the extra data. * Parses the batch context from the extra data.
* @return _totalElements Total number of elements submitted. * @return _totalElements Total number of elements submitted.
......
...@@ -97,15 +97,15 @@ interface iOVM_CanonicalTransactionChain is iOVM_BaseChain { ...@@ -97,15 +97,15 @@ interface iOVM_CanonicalTransactionChain is iOVM_BaseChain {
/** /**
* Allows the sequencer to append a batch of transactions. * Allows the sequencer to append a batch of transactions.
* @param _transactions Array of raw transaction data. * param _shouldStartAtBatch Specific batch we expect to start appending to.
* @param _contexts Array of batch contexts. * param _totalElementsToAppend Total number of batch elements we expect to append.
* @param _shouldStartAtBatch Specific batch we expect to start appending to. * param _contexts Array of batch contexts.
* @param _totalElementsToAppend Total number of batch elements we expect to append. * param _transactionDataFields Array of raw transaction data.
*/ */
function appendSequencerBatch( function appendSequencerBatch( // USES CUSTOM ENCODING FOR EFFICIENCY PURPOSES
bytes[] memory _transactions, // uint40 _shouldStartAtBatch,
BatchContext[] memory _contexts, // uint24 _totalElementsToAppend,
uint256 _shouldStartAtBatch, // BatchContext[] _contexts,
uint _totalElementsToAppend // bytes[] _transactionDataFields
) external; ) external;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment