Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding startsAtIndex to sequencer batch appending #245

Merged
merged 13 commits into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from 10 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 @@ -152,15 +152,63 @@ contract CanonicalTransactionChain is ContractResolver {
safetyQueue.dequeue();
}

/**
* Appends transaction batches from the L1ToL2Queue and/or SafetyQueue until the total
* number of transactions in the canonical chain equals the provided _upToIndex.
* This will revert if there are too few or too many transactions in queued batches such that
* the total number of canonical tx chain elements isn't exactly _upToIndex as a result of this call.
* @param _upToTransactionIndex The expected next available tx index in the canonical chain after this call.
*/
function appendFromQueuesUpToTransactionIndex(
uint _upToTransactionIndex
)
public
{
require(
isSequencer(msg.sender),
"Message sender does not have permission to append from queues"
);

L1ToL2TransactionQueue l1ToL2Queue = resolveL1ToL2TransactionQueue();
SafetyTransactionQueue safetyQueue = resolveSafetyTransactionQueue();

while(cumulativeNumElements < _upToTransactionIndex) {
bool safetyQueueIsEmpty = safetyQueue.isEmpty();
bool l1ToL2QueueIsEmpty = l1ToL2Queue.isEmpty();
if (safetyQueueIsEmpty && l1ToL2QueueIsEmpty) {
revert("Cannot append from queues up to index because queues are empty");
}
else if (l1ToL2QueueIsEmpty) {
appendSafetyBatch();
}
else if (safetyQueueIsEmpty) {
appendL1ToL2Batch();
}
else if (safetyQueue.peekTimestamp() <= l1ToL2Queue.peekTimestamp()) {
appendSafetyBatch();
}
else {
appendL1ToL2Batch();
}
}

require(
cumulativeNumElements == _upToTransactionIndex,
"Up to index was exceeded in appending from queues"
);
}

/**
* Attempts to append a batch provided by the sequencer.
* @param _txBatch Transaction batch to append.
* @param _timestamp Timestamp for the batch.
* @param _startsAtTxIndex The absolute index in the canonical chain of this batch's first transaction.
*/
function appendSequencerBatch(
bytes[] memory _txBatch,
uint _timestamp,
uint _blockNumber
uint _blockNumber,
uint _startsAtTxIndex
)
public
{
Expand Down Expand Up @@ -197,6 +245,15 @@ contract CanonicalTransactionChain is ContractResolver {
"Cannot submit a batch with a blockNumber in the future"
);

require(
_startsAtTxIndex >= cumulativeNumElements,
"Cannot submit a batch with a startsAtTxIndex less than cumulativeNumElements"
);

if (_startsAtTxIndex > cumulativeNumElements) {
appendFromQueuesUpToTransactionIndex(_startsAtTxIndex);
}

if (!l1ToL2Queue.isEmpty()) {
require(
_timestamp <= l1ToL2Queue.peekTimestamp(),
Expand Down Expand Up @@ -289,7 +346,6 @@ contract CanonicalTransactionChain is ContractResolver {
return hashBatchHeader(batchHeader) == batches[_inclusionProof.batchIndex];
}


/*
* Internal Functions
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,11 @@ contract StateCommitmentChain is ContractResolver {
/**
* Attempts to append a state batch.
* @param _stateBatch Batch of ordered root hashes to append.
* @param _startsAtRootIndex The absolute index in the state root chain of the first state root in this batch.
*/
function appendStateBatch(
bytes32[] memory _stateBatch
bytes32[] memory _stateBatch,
uint _startsAtRootIndex
)
public
{
Expand All @@ -100,14 +102,38 @@ contract StateCommitmentChain is ContractResolver {
"Cannot submit an empty state commitment batch"
);

require(
_startsAtRootIndex <= cumulativeNumElements,
"_startsAtRootIndex index indicates future state root"
);

if (cumulativeNumElements >= _startsAtRootIndex + _stateBatch.length) {
// This means all the roots in this batch were already appended. Don't fail, but don't change state.
return;
}

bytes32[] memory batchToAppend;
if (_startsAtRootIndex < cumulativeNumElements) {
// TODO: This can be made much more efficient later by just making
// TODO: merkleUtils.getMerkleRootFrom32ByteLeafData take an index
// TODO: indicating the start of the array instead of creating a new one
uint elementsToSkip = cumulativeNumElements - _startsAtRootIndex;
batchToAppend = new bytes32[](_stateBatch.length - elementsToSkip);
for (uint i = 0; i < batchToAppend.length; i++) {
batchToAppend[i] = _stateBatch[elementsToSkip + i];
}
} else {
batchToAppend = _stateBatch;
}

bytes32 batchHeaderHash = keccak256(abi.encodePacked(
merkleUtils.getMerkleRootFrom32ByteLeafData(_stateBatch), // elementsMerkleRoot
_stateBatch.length, // numElementsInBatch
merkleUtils.getMerkleRootFrom32ByteLeafData(batchToAppend), // elementsMerkleRoot
batchToAppend.length, // numElementsInBatch
cumulativeNumElements // cumulativeNumElements
));

batches.push(batchHeaderHash);
cumulativeNumElements += _stateBatch.length;
cumulativeNumElements += batchToAppend.length;
emit StateBatchAppended(batchHeaderHash);
}

Expand Down
Loading