Commit 093ec7eb authored by smartcontracts's avatar smartcontracts Committed by GitHub

feat: CanonicalTransactionChain gas optimizations (#228)

* Final gas optimizations for CTC

* delete and re-init

* Fix issue with tests failing

* Use encoding/decoding from core-utils

* dev: Use eth-optimism/core-utils where applicable (#281)

* Use core-utils where applicable

* Further reduce utils

* Update ovmCREATEEOA.spec.ts
Co-authored-by: default avatarMark Tyneway <mark.tyneway@gmail.com>

* remove unused import

* Revert "remove unused import"

This reverts commit 1df87926e7a3ca8ebdf7448ad5f0395fe7766ff7.

* actually fix imports

* A few more comments

* address PR feedback - add comments, renaming vars

* Optimization: Conditional Monotonicity Checking (#307)

* trying it

* cleanup

* remove duplicate comment

* fix docstring

* fix var name

* missing period
Co-authored-by: default avatarBen Jones <ben@pseudonym.party>
Co-authored-by: default avatarMaurelian <maurelian@protonmail.ch>
Co-authored-by: default avatarMark Tyneway <mark.tyneway@gmail.com>
Co-authored-by: default avatarKevin Ho <kevinjho1996@gmail.com>
parent 61b227d3
...@@ -208,24 +208,10 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -208,24 +208,10 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
Lib_OVMCodec.QueueElement memory _element Lib_OVMCodec.QueueElement memory _element
) )
{ {
iOVM_ChainStorageContainer ctcQueue = queue(); return _getQueueElement(
_index,
uint40 trueIndex = uint40(_index * 2); queue()
bytes32 queueRoot = ctcQueue.get(trueIndex); );
bytes32 timestampAndBlockNumber = ctcQueue.get(trueIndex + 1);
uint40 elementTimestamp;
uint40 elementBlockNumber;
assembly {
elementTimestamp := and(timestampAndBlockNumber, 0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF)
elementBlockNumber := shr(40, and(timestampAndBlockNumber, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000))
}
return Lib_OVMCodec.QueueElement({
queueRoot: queueRoot,
timestamp: elementTimestamp,
blockNumber: elementBlockNumber
});
} }
/** /**
...@@ -256,10 +242,9 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -256,10 +242,9 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
uint40 uint40
) )
{ {
// The underlying queue data structure stores 2 elements return _getQueueLength(
// per insertion, so to get the real queue length we need queue()
// to divide by 2. See the usage of `push2(..)`. );
return uint40(queue().length() / 2);
} }
/** /**
...@@ -326,20 +311,23 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -326,20 +311,23 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
timestampAndBlockNumber := or(timestampAndBlockNumber, shl(40, number())) timestampAndBlockNumber := or(timestampAndBlockNumber, shl(40, number()))
} }
iOVM_ChainStorageContainer ctcQueue = queue(); iOVM_ChainStorageContainer queueRef = queue();
ctcQueue.push2( queueRef.push2(
transactionHash, transactionHash,
timestampAndBlockNumber timestampAndBlockNumber
); );
uint256 queueIndex = ctcQueue.length() / 2; // The underlying queue data structure stores 2 elements
// per insertion, so to get the real queue length we need
// to divide by 2 and subtract 1. See the usage of `push2(..)`.
uint256 queueIndex = queueRef.length() / 2 - 1;
emit TransactionEnqueued( emit TransactionEnqueued(
msg.sender, msg.sender,
_target, _target,
_gasLimit, _gasLimit,
_data, _data,
queueIndex - 1, queueIndex,
block.timestamp block.timestamp
); );
} }
...@@ -354,45 +342,45 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -354,45 +342,45 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
override override
public public
{ {
// Disable `appendQueueBatch` for mainnet // TEMPORARY: Disable `appendQueueBatch` for minnet
revert("appendQueueBatch is currently disabled."); revert("appendQueueBatch is currently disabled.");
_numQueuedTransactions = Lib_Math.min(_numQueuedTransactions, getNumPendingQueueElements()); // _numQueuedTransactions = Lib_Math.min(_numQueuedTransactions, getNumPendingQueueElements());
require( // require(
_numQueuedTransactions > 0, // _numQueuedTransactions > 0,
"Must append more than zero transactions." // "Must append more than zero transactions."
); // );
bytes32[] memory leaves = new bytes32[](_numQueuedTransactions); // bytes32[] memory leaves = new bytes32[](_numQueuedTransactions);
uint40 nextQueueIndex = getNextQueueIndex(); // uint40 nextQueueIndex = getNextQueueIndex();
for (uint256 i = 0; i < _numQueuedTransactions; i++) { // for (uint256 i = 0; i < _numQueuedTransactions; i++) {
if (msg.sender != resolve("OVM_Sequencer")) { // if (msg.sender != resolve("OVM_Sequencer")) {
Lib_OVMCodec.QueueElement memory el = getQueueElement(nextQueueIndex); // Lib_OVMCodec.QueueElement memory el = getQueueElement(nextQueueIndex);
require( // require(
el.timestamp + forceInclusionPeriodSeconds < block.timestamp, // el.timestamp + forceInclusionPeriodSeconds < block.timestamp,
"Queue transactions cannot be submitted during the sequencer inclusion period." // "Queue transactions cannot be submitted during the sequencer inclusion period."
); // );
} // }
leaves[i] = _getQueueLeafHash(nextQueueIndex); // leaves[i] = _getQueueLeafHash(nextQueueIndex);
nextQueueIndex++; // nextQueueIndex++;
} // }
Lib_OVMCodec.QueueElement memory lastElement = getQueueElement(nextQueueIndex - 1); // Lib_OVMCodec.QueueElement memory lastElement = getQueueElement(nextQueueIndex - 1);
_appendBatch( // _appendBatch(
Lib_MerkleTree.getMerkleRoot(leaves), // Lib_MerkleTree.getMerkleRoot(leaves),
_numQueuedTransactions, // _numQueuedTransactions,
_numQueuedTransactions, // _numQueuedTransactions,
lastElement.timestamp, // lastElement.timestamp,
lastElement.blockNumber // lastElement.blockNumber
); // );
emit QueueBatchAppended( // emit QueueBatchAppended(
nextQueueIndex - _numQueuedTransactions, // nextQueueIndex - _numQueuedTransactions,
_numQueuedTransactions, // _numQueuedTransactions,
getTotalElements() // getTotalElements()
); // );
} }
/** /**
...@@ -437,64 +425,98 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -437,64 +425,98 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
); );
uint40 nextTransactionPtr = uint40(BATCH_CONTEXT_START_POS + BATCH_CONTEXT_SIZE * numContexts); uint40 nextTransactionPtr = uint40(BATCH_CONTEXT_START_POS + BATCH_CONTEXT_SIZE * numContexts);
uint256 calldataSize;
assembly {
calldataSize := calldatasize()
}
require( require(
calldataSize >= nextTransactionPtr, msg.data.length >= nextTransactionPtr,
"Not enough BatchContexts provided." "Not enough BatchContexts provided."
); );
// Get queue length for future comparison/ // Take a reference to the queue and its length so we don't have to keep resolving it.
uint40 queueLength = getQueueLength(); // Length isn't going to change during the course of execution, so it's fine to simply
// resolve this once at the start. Saves gas.
iOVM_ChainStorageContainer queueRef = queue();
uint40 queueLength = _getQueueLength(queueRef);
// Reserve some memory to save gas on hashing later on. This is a relatively safe estimate
// for the average transaction size that will prevent having to resize this chunk of memory
// later on. Saves gas.
bytes memory hashMemory = new bytes((msg.data.length / totalElementsToAppend) * 2);
// Initialize the array of canonical chain leaves that we will append. // Initialize the array of canonical chain leaves that we will append.
bytes32[] memory leaves = new bytes32[](totalElementsToAppend); bytes32[] memory leaves = new bytes32[](totalElementsToAppend);
// Each leaf index corresponds to a tx, either sequenced or enqueued. // Each leaf index corresponds to a tx, either sequenced or enqueued.
uint32 leafIndex = 0; uint32 leafIndex = 0;
// Counter for number of sequencer transactions appended so far. // Counter for number of sequencer transactions appended so far.
uint32 numSequencerTransactions = 0; uint32 numSequencerTransactions = 0;
// We will sequentially append leaves which are pointers to the queue. // We will sequentially append leaves which are pointers to the queue.
// The initial queue index is what is currently in storage. // The initial queue index is what is currently in storage.
uint40 nextQueueIndex = getNextQueueIndex(); uint40 nextQueueIndex = getNextQueueIndex();
BatchContext memory curContext; BatchContext memory curContext;
for (uint32 i = 0; i < numContexts; i++) { for (uint32 i = 0; i < numContexts; i++) {
BatchContext memory nextContext = _getBatchContext(i); BatchContext memory nextContext = _getBatchContext(i);
if (i == 0) { if (i == 0) {
// Execute a special check for the first batch.
_validateFirstBatchContext(nextContext); _validateFirstBatchContext(nextContext);
} }
_validateNextBatchContext(curContext, nextContext, nextQueueIndex);
// Execute this check on every single batch, including the first one.
_validateNextBatchContext(
curContext,
nextContext,
nextQueueIndex,
queueLength,
queueRef
);
// Now we can update our current context.
curContext = nextContext; curContext = nextContext;
// Process sequencer transactions first.
for (uint32 j = 0; j < curContext.numSequencedTransactions; j++) { for (uint32 j = 0; j < curContext.numSequencedTransactions; j++) {
uint256 txDataLength; uint256 txDataLength;
assembly { assembly {
txDataLength := shr(232, calldataload(nextTransactionPtr)) txDataLength := shr(232, calldataload(nextTransactionPtr))
} }
leaves[leafIndex] = _getSequencerLeafHash(curContext, nextTransactionPtr, txDataLength); leaves[leafIndex] = _getSequencerLeafHash(
curContext,
nextTransactionPtr,
txDataLength,
hashMemory
);
nextTransactionPtr += uint40(TX_DATA_HEADER_SIZE + txDataLength); nextTransactionPtr += uint40(TX_DATA_HEADER_SIZE + txDataLength);
numSequencerTransactions++; numSequencerTransactions++;
leafIndex++; leafIndex++;
} }
// Now process any subsequent queue transactions.
for (uint32 j = 0; j < curContext.numSubsequentQueueTransactions; j++) { for (uint32 j = 0; j < curContext.numSubsequentQueueTransactions; j++) {
require(nextQueueIndex < queueLength, "Not enough queued transactions to append."); require(
nextQueueIndex < queueLength,
"Not enough queued transactions to append."
);
leaves[leafIndex] = _getQueueLeafHash(nextQueueIndex); leaves[leafIndex] = _getQueueLeafHash(nextQueueIndex);
nextQueueIndex++; nextQueueIndex++;
leafIndex++; leafIndex++;
} }
} }
_validateFinalBatchContext(curContext); _validateFinalBatchContext(
curContext,
nextQueueIndex,
queueLength,
queueRef
);
require( require(
calldataSize == nextTransactionPtr, msg.data.length == nextTransactionPtr,
"Not all sequencer transactions were processed." "Not all sequencer transactions were processed."
); );
...@@ -513,7 +535,14 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -513,7 +535,14 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
blockNumber = uint40(curContext.blockNumber); blockNumber = uint40(curContext.blockNumber);
} else { } else {
// The last element is a queue tx, therefore pull timestamp and block number from the queue element. // The last element is a queue tx, therefore pull timestamp and block number from the queue element.
Lib_OVMCodec.QueueElement memory lastElement = getQueueElement(nextQueueIndex - 1); // curContext.numSubsequentQueueTransactions > 0 which means that we've processed at least one queue element.
// We increment nextQueueIndex after processing each queue element,
// so the index of the last element we processed is nextQueueIndex - 1.
Lib_OVMCodec.QueueElement memory lastElement = _getQueueElement(
nextQueueIndex - 1,
queueRef
);
blockTimestamp = lastElement.timestamp; blockTimestamp = lastElement.timestamp;
blockNumber = lastElement.blockNumber; blockNumber = lastElement.blockNumber;
} }
...@@ -705,11 +734,50 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -705,11 +734,50 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
); );
} }
/**
* Gets the queue element at a particular index.
* @param _index Index of the queue element to access.
* @return _element Queue element at the given index.
*/
function _getQueueElement(
uint256 _index,
iOVM_ChainStorageContainer _queueRef
)
internal
view
returns (
Lib_OVMCodec.QueueElement memory _element
)
{
// The underlying queue data structure stores 2 elements
// per insertion, so to get the actual desired queue index
// we need to multiply by 2. See the usage of `push2(..)`.
(
bytes32 transactionHash,
bytes32 timestampAndBlockNumber
) = _queueRef.get2(uint40(_index * 2));
uint40 elementTimestamp;
uint40 elementBlockNumber;
assembly {
elementTimestamp := and(timestampAndBlockNumber, 0x000000000000000000000000000000000000000000000000000000FFFFFFFFFF)
elementBlockNumber := shr(40, and(timestampAndBlockNumber, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000))
}
return Lib_OVMCodec.QueueElement({
transactionHash: transactionHash,
timestamp: elementTimestamp,
blockNumber: elementBlockNumber
});
}
/** /**
* Retrieves the length of the queue. * Retrieves the length of the queue.
* @return Length of the queue. * @return Length of the queue.
*/ */
function _getQueueLength() function _getQueueLength(
iOVM_ChainStorageContainer _queueRef
)
internal internal
view view
returns ( returns (
...@@ -719,7 +787,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -719,7 +787,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
// The underlying queue data structure stores 2 elements // The underlying queue data structure stores 2 elements
// per insertion, so to get the real queue length we need // per insertion, so to get the real queue length we need
// to divide by 2. See the usage of `push2(..)`. // to divide by 2. See the usage of `push2(..)`.
return uint40(queue().length() / 2); return uint40(_queueRef.length() / 2);
} }
/** /**
...@@ -732,7 +800,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -732,7 +800,8 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
function _getSequencerLeafHash( function _getSequencerLeafHash(
BatchContext memory _context, BatchContext memory _context,
uint256 _nextTransactionPtr, uint256 _nextTransactionPtr,
uint256 _txDataLength uint256 _txDataLength,
bytes memory _hashMemory
) )
internal internal
pure pure
...@@ -740,14 +809,17 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -740,14 +809,17 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
bytes32 bytes32
) )
{ {
// Only allocate more memory if we didn't reserve enough to begin with.
if (BYTES_TILL_TX_DATA + _txDataLength > _hashMemory.length) {
_hashMemory = new bytes(BYTES_TILL_TX_DATA + _txDataLength);
}
bytes memory chainElement = new bytes(BYTES_TILL_TX_DATA + _txDataLength);
uint256 ctxTimestamp = _context.timestamp; uint256 ctxTimestamp = _context.timestamp;
uint256 ctxBlockNumber = _context.blockNumber; uint256 ctxBlockNumber = _context.blockNumber;
bytes32 leafHash; bytes32 leafHash;
assembly { assembly {
let chainElementStart := add(chainElement, 0x20) let chainElementStart := add(_hashMemory, 0x20)
// Set the first byte equal to `1` to indicate this is a sequencer chain element. // Set the first byte equal to `1` to indicate this is a sequencer chain element.
// This distinguishes sequencer ChainElements from queue ChainElements because // This distinguishes sequencer ChainElements from queue ChainElements because
...@@ -825,10 +897,11 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -825,10 +897,11 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
) )
internal internal
{ {
iOVM_ChainStorageContainer batchesRef = batches();
(uint40 totalElements, uint40 nextQueueIndex,,) = _getBatchExtraData(); (uint40 totalElements, uint40 nextQueueIndex,,) = _getBatchExtraData();
Lib_OVMCodec.ChainBatchHeader memory header = Lib_OVMCodec.ChainBatchHeader({ Lib_OVMCodec.ChainBatchHeader memory header = Lib_OVMCodec.ChainBatchHeader({
batchIndex: batches().length(), batchIndex: batchesRef.length(),
batchRoot: _transactionRoot, batchRoot: _transactionRoot,
batchSize: _batchSize, batchSize: _batchSize,
prevTotalElements: totalElements, prevTotalElements: totalElements,
...@@ -851,7 +924,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -851,7 +924,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
_blockNumber _blockNumber
); );
batches().push(batchHeaderHash, latestBatchContext); batchesRef.push(batchHeaderHash, latestBatchContext);
} }
/** /**
...@@ -867,12 +940,66 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -867,12 +940,66 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
// If there are existing elements, this batch must come later. // If there are existing elements, this batch must come later.
if (getTotalElements() > 0) { if (getTotalElements() > 0) {
(,, uint40 lastTimestamp, uint40 lastBlockNumber) = _getBatchExtraData(); (,, uint40 lastTimestamp, uint40 lastBlockNumber) = _getBatchExtraData();
require(_firstContext.blockNumber >= lastBlockNumber, "Context block number is lower than last submitted.");
require(_firstContext.timestamp >= lastTimestamp, "Context timestamp is lower than last submitted."); require(
_firstContext.blockNumber >= lastBlockNumber,
"Context block number is lower than last submitted."
);
require(
_firstContext.timestamp >= lastTimestamp,
"Context timestamp is lower than last submitted."
);
} }
// Sequencer cannot submit contexts which are more than the force inclusion period old. // Sequencer cannot submit contexts which are more than the force inclusion period old.
require(_firstContext.timestamp + forceInclusionPeriodSeconds >= block.timestamp, "Context timestamp too far in the past."); require(
require(_firstContext.blockNumber + forceInclusionPeriodBlocks >= block.number, "Context block number too far in the past."); _firstContext.timestamp + forceInclusionPeriodSeconds >= block.timestamp,
"Context timestamp too far in the past."
);
require(
_firstContext.blockNumber + forceInclusionPeriodBlocks >= block.number,
"Context block number too far in the past."
);
}
/**
* Checks that a given batch context has a time context which is below a given que element
* @param _context The batch context to validate has values lower.
* @param _queueIndex Index of the queue element we are validating came later than the context.
* @param _queueRef The storage container for the queue.
*/
function _validateContextBeforeEnqueue(
BatchContext memory _context,
uint40 _queueIndex,
iOVM_ChainStorageContainer _queueRef
)
internal
view
{
Lib_OVMCodec.QueueElement memory nextQueueElement = _getQueueElement(
_queueIndex,
_queueRef
);
// If the force inclusion period has passed for an enqueued transaction, it MUST be the next chain element.
require(
block.timestamp < nextQueueElement.timestamp + forceInclusionPeriodSeconds,
"Previously enqueued batches have expired and must be appended before a new sequencer batch."
);
// Just like sequencer transaction times must be increasing relative to each other,
// We also require that they be increasing relative to any interspersed queue elements.
require(
_context.timestamp <= nextQueueElement.timestamp,
"Sequencer transaction timestamp exceeds that of next queue element."
);
require(
_context.blockNumber <= nextQueueElement.blockNumber,
"Sequencer transaction blockNumber exceeds that of next queue element."
);
} }
/** /**
...@@ -880,11 +1007,15 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -880,11 +1007,15 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
* @param _prevContext The previously validated batch context. * @param _prevContext The previously validated batch context.
* @param _nextContext The batch context to validate with this call. * @param _nextContext The batch context to validate with this call.
* @param _nextQueueIndex Index of the next queue element to process for the _nextContext's subsequentQueueElements. * @param _nextQueueIndex Index of the next queue element to process for the _nextContext's subsequentQueueElements.
* @param _queueLength The length of the queue at the start of the batchAppend call.
* @param _queueRef The storage container for the queue.
*/ */
function _validateNextBatchContext( function _validateNextBatchContext(
BatchContext memory _prevContext, BatchContext memory _prevContext,
BatchContext memory _nextContext, BatchContext memory _nextContext,
uint40 _nextQueueIndex uint40 _nextQueueIndex,
uint40 _queueLength,
iOVM_ChainStorageContainer _queueRef
) )
internal internal
view view
...@@ -900,26 +1031,12 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -900,26 +1031,12 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
"Context blockNumber values must monotonically increase." "Context blockNumber values must monotonically increase."
); );
// If there are some queue elements pending: // If there is going to be a queue element pulled in from this context:
if (getQueueLength() - _nextQueueIndex > 0) { if (_nextContext.numSubsequentQueueTransactions > 0) {
Lib_OVMCodec.QueueElement memory nextQueueElement = getQueueElement(_nextQueueIndex); _validateContextBeforeEnqueue(
_nextContext,
// If the force inclusion period has passed for an enqueued transaction, it MUST be the next chain element. _nextQueueIndex,
require( _queueRef
block.timestamp < nextQueueElement.timestamp + forceInclusionPeriodSeconds,
"Previously enqueued batches have expired and must be appended before a new sequencer batch."
);
// Just like sequencer transaction times must be increasing relative to each other,
// We also require that they be increasing relative to any interspersed queue elements.
require(
_nextContext.timestamp <= nextQueueElement.timestamp,
"Sequencer transaction timestamp exceeds that of next queue element."
);
require(
_nextContext.blockNumber <= nextQueueElement.blockNumber,
"Sequencer transaction blockNumber exceeds that of next queue element."
); );
} }
} }
...@@ -927,13 +1044,27 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -927,13 +1044,27 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
/** /**
* Checks that the final batch context in a sequencer submission is valid. * Checks that the final batch context in a sequencer submission is valid.
* @param _finalContext The batch context to validate. * @param _finalContext The batch context to validate.
* @param _queueLength The length of the queue at the start of the batchAppend call.
* @param _nextQueueIndex The next element in the queue that will be pulled into the CTC.
* @param _queueRef The storage container for the queue.
*/ */
function _validateFinalBatchContext( function _validateFinalBatchContext(
BatchContext memory _finalContext BatchContext memory _finalContext,
uint40 _nextQueueIndex,
uint40 _queueLength,
iOVM_ChainStorageContainer _queueRef
) )
internal internal
view view
{ {
// If the queue is not now empty, check the mononoticity of whatever the next batch that will come in is.
if (_queueLength - _nextQueueIndex > 0 && _finalContext.numSubsequentQueueTransactions == 0) {
_validateContextBeforeEnqueue(
_finalContext,
_nextQueueIndex,
_queueRef
);
}
// Batches cannot be added from the future, or subsequent enqueue() contexts would violate monotonicity. // Batches cannot be added from the future, or subsequent enqueue() contexts would violate monotonicity.
require(_finalContext.timestamp <= block.timestamp, "Context timestamp is from the future."); require(_finalContext.timestamp <= block.timestamp, "Context timestamp is from the future.");
require(_finalContext.blockNumber <= block.number, "Context block number is from the future."); require(_finalContext.blockNumber <= block.number, "Context block number is from the future.");
...@@ -1053,7 +1184,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad ...@@ -1053,7 +1184,7 @@ contract OVM_CanonicalTransactionChain is iOVM_CanonicalTransactionChain, Lib_Ad
Lib_OVMCodec.QueueElement memory el = getQueueElement(_queueIndex); Lib_OVMCodec.QueueElement memory el = getQueueElement(_queueIndex);
require( require(
el.queueRoot == transactionHash el.transactionHash == transactionHash
&& el.timestamp == _transaction.timestamp && el.timestamp == _transaction.timestamp
&& el.blockNumber == _transaction.blockNumber, && el.blockNumber == _transaction.blockNumber,
"Invalid Queue transaction." "Invalid Queue transaction."
......
...@@ -187,6 +187,23 @@ contract OVM_ChainStorageContainer is iOVM_ChainStorageContainer, Lib_AddressRes ...@@ -187,6 +187,23 @@ contract OVM_ChainStorageContainer is iOVM_ChainStorageContainer, Lib_AddressRes
return buffer.get(uint40(_index)); return buffer.get(uint40(_index));
} }
/**
* @inheritdoc iOVM_ChainStorageContainer
*/
function get2(
uint256 _index
)
override
public
view
returns (
bytes32,
bytes32
)
{
return buffer.get2(uint40(_index));
}
/** /**
* @inheritdoc iOVM_ChainStorageContainer * @inheritdoc iOVM_ChainStorageContainer
*/ */
......
...@@ -104,6 +104,22 @@ interface iOVM_ChainStorageContainer { ...@@ -104,6 +104,22 @@ interface iOVM_ChainStorageContainer {
bytes32 bytes32
); );
/**
* Retrieves two consecutive objects from the container.
* @param _index Index of the particular objects to access.
* @return 32 byte object value at index `_index`.
* @return 32 byte object value at index `_index + 1`.
*/
function get2(
uint256 _index
)
external
view
returns (
bytes32,
bytes32
);
/** /**
* Removes all objects after and including a given index. * Removes all objects after and including a given index.
* @param _index Object index to delete from. * @param _index Object index to delete from.
......
...@@ -81,7 +81,7 @@ library Lib_OVMCodec { ...@@ -81,7 +81,7 @@ library Lib_OVMCodec {
} }
struct QueueElement { struct QueueElement {
bytes32 queueRoot; bytes32 transactionHash;
uint40 timestamp; uint40 timestamp;
uint40 blockNumber; uint40 blockNumber;
} }
......
...@@ -211,6 +211,30 @@ library Lib_RingBuffer { ...@@ -211,6 +211,30 @@ library Lib_RingBuffer {
} }
} }
/**
* Retrieves two consecutive elements from the buffer.
* @param _self Buffer to access.
* @param _index Element index to retrieve.
* @return Value of the element at index `_index`.
* @return Value of the element at index `_index + 1`.
*/
function get2(
RingBuffer storage _self,
uint256 _index
)
internal
view
returns (
bytes32,
bytes32
)
{
return (
_self.get(_index),
_self.get(_index + 1)
);
}
/** /**
* Deletes all elements after (and including) a given index. * Deletes all elements after (and including) a given index.
* @param _self Buffer to access. * @param _self Buffer to access.
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
"dependencies": { "dependencies": {
"@eth-optimism/core-utils": "^0.1.8", "@eth-optimism/core-utils": "^0.1.8",
"@eth-optimism/dev": "^1.1.1", "@eth-optimism/dev": "^1.1.1",
"@eth-optimism/core-utils": "^0.1.5",
"@eth-optimism/solc": "^0.6.12-alpha.1",
"@ethersproject/abstract-provider": "^5.0.8", "@ethersproject/abstract-provider": "^5.0.8",
"@ethersproject/contracts": "^5.0.5", "@ethersproject/contracts": "^5.0.5",
"@ethersproject/hardware-wallets": "^5.0.8", "@ethersproject/hardware-wallets": "^5.0.8",
......
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock'
import {
AppendSequencerBatchParams,
encodeAppendSequencerBatch,
} from '@eth-optimism/core-utils'
import { TransactionResponse } from '@ethersproject/abstract-provider'
import { keccak256 } from 'ethers/lib/utils'
import _ from 'lodash'
/* Internal Imports */
import {
makeAddressManager,
setProxyTarget,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
getEthTime,
getNextBlockNumber,
} from '../../../helpers'
// Still have some duplication from OVM_CanonicalTransactionChain.spec.ts, but it's so minimal that
// this is probably cleaner for now. Particularly since we're planning to move all of this out into
// core-utils soon anyway.
const DECOMPRESSION_ADDRESS = '0x4200000000000000000000000000000000000008'
const MAX_GAS_LIMIT = 8_000_000
const appendSequencerBatch = async (
OVM_CanonicalTransactionChain: Contract,
batch: AppendSequencerBatchParams
): Promise<TransactionResponse> => {
const methodId = keccak256(Buffer.from('appendSequencerBatch()')).slice(2, 10)
const calldata = encodeAppendSequencerBatch(batch)
return OVM_CanonicalTransactionChain.signer.sendTransaction({
to: OVM_CanonicalTransactionChain.address,
data: '0x' + methodId + calldata,
})
}
describe('[GAS BENCHMARK] OVM_CanonicalTransactionChain', () => {
let sequencer: Signer
before(async () => {
;[sequencer] = await ethers.getSigners()
})
let AddressManager: Contract
let Mock__OVM_ExecutionManager: MockContract
let Mock__OVM_StateCommitmentChain: MockContract
before(async () => {
AddressManager = await makeAddressManager()
await AddressManager.setAddress(
'OVM_Sequencer',
await sequencer.getAddress()
)
await AddressManager.setAddress(
'OVM_DecompressionPrecompileAddress',
DECOMPRESSION_ADDRESS
)
Mock__OVM_ExecutionManager = await smockit(
await ethers.getContractFactory('OVM_ExecutionManager')
)
Mock__OVM_StateCommitmentChain = await smockit(
await ethers.getContractFactory('OVM_StateCommitmentChain')
)
await setProxyTarget(
AddressManager,
'OVM_ExecutionManager',
Mock__OVM_ExecutionManager
)
await setProxyTarget(
AddressManager,
'OVM_StateCommitmentChain',
Mock__OVM_StateCommitmentChain
)
Mock__OVM_ExecutionManager.smocked.getMaxTransactionGasLimit.will.return.with(
MAX_GAS_LIMIT
)
})
let Factory__OVM_CanonicalTransactionChain: ContractFactory
let Factory__OVM_ChainStorageContainer: ContractFactory
before(async () => {
Factory__OVM_CanonicalTransactionChain = await ethers.getContractFactory(
'OVM_CanonicalTransactionChain'
)
Factory__OVM_ChainStorageContainer = await ethers.getContractFactory(
'OVM_ChainStorageContainer'
)
})
let OVM_CanonicalTransactionChain: Contract
beforeEach(async () => {
OVM_CanonicalTransactionChain = await Factory__OVM_CanonicalTransactionChain.deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
MAX_GAS_LIMIT
)
const batches = await Factory__OVM_ChainStorageContainer.deploy(
AddressManager.address,
'OVM_CanonicalTransactionChain'
)
const queue = await Factory__OVM_ChainStorageContainer.deploy(
AddressManager.address,
'OVM_CanonicalTransactionChain'
)
await AddressManager.setAddress(
'OVM_ChainStorageContainer:CTC:batches',
batches.address
)
await AddressManager.setAddress(
'OVM_ChainStorageContainer:CTC:queue',
queue.address
)
await AddressManager.setAddress(
'OVM_CanonicalTransactionChain',
OVM_CanonicalTransactionChain.address
)
})
describe('appendSequencerBatch', () => {
beforeEach(() => {
OVM_CanonicalTransactionChain = OVM_CanonicalTransactionChain.connect(
sequencer
)
})
it('200 transactions in a single context', async () => {
console.log(`Benchmark: 200 transactions in a single context.`)
const timestamp = (await getEthTime(ethers.provider)) - 100
const blockNumber = await getNextBlockNumber(ethers.provider)
const transactionTemplate = '0x' + '11'.repeat(400)
const transactions = []
const numTxs = 200
for (let i = 0; i < numTxs; i++) {
transactions.push(transactionTemplate)
}
const fixedCalldataCost =
(transactionTemplate.slice(2).length / 2) * 16 * numTxs
const res = await appendSequencerBatch(OVM_CanonicalTransactionChain, {
shouldStartAtBatch: 0,
totalElementsToAppend: numTxs,
contexts: [
{
numSequencedTransactions: numTxs,
numSubsequentQueueTransactions: 0,
timestamp,
blockNumber,
},
],
transactions,
})
const receipt = await res.wait()
console.log('Benchmark complete.')
console.log('Gas used:', receipt.gasUsed.toNumber())
console.log('Fixed calldata cost:', fixedCalldataCost)
console.log(
'Non-calldata overhead gas cost per transaction:',
(receipt.gasUsed.toNumber() - fixedCalldataCost) / numTxs
)
}).timeout(100000000)
it('200 transactions in 200 contexts', async () => {
console.log(`Benchmark: 200 transactions in 200 contexts.`)
const timestamp = (await getEthTime(ethers.provider)) - 100
const blockNumber = await getNextBlockNumber(ethers.provider)
const transactionTemplate = '0x' + '11'.repeat(400)
const transactions = []
const numTxs = 200
for (let i = 0; i < numTxs; i++) {
transactions.push(transactionTemplate)
}
const fixedCalldataCost =
(transactionTemplate.slice(2).length / 2) * 16 * numTxs
const res = await appendSequencerBatch(OVM_CanonicalTransactionChain, {
shouldStartAtBatch: 0,
totalElementsToAppend: numTxs,
contexts: [...Array(numTxs)].map(() => {
return {
numSequencedTransactions: 1,
numSubsequentQueueTransactions: 0,
timestamp,
blockNumber,
}
}),
transactions,
})
const receipt = await res.wait()
console.log('Benchmark complete.')
console.log('Gas used:', receipt.gasUsed.toNumber())
console.log('Fixed calldata cost:', fixedCalldataCost)
console.log(
'Non-calldata overhead gas cost per transaction:',
(receipt.gasUsed.toNumber() - fixedCalldataCost) / numTxs
)
}).timeout(100000000)
})
})
...@@ -3,9 +3,14 @@ import { expect } from '../../../setup' ...@@ -3,9 +3,14 @@ import { expect } from '../../../setup'
/* External Imports */ /* External Imports */
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract, BigNumber } from 'ethers' import { Signer, ContractFactory, Contract, BigNumber } from 'ethers'
import { TransactionResponse } from '@ethersproject/abstract-provider'
import { smockit, MockContract } from '@eth-optimism/smock' import { smockit, MockContract } from '@eth-optimism/smock'
import { remove0x } from '@eth-optimism/core-utils' import {
AppendSequencerBatchParams,
encodeAppendSequencerBatch,
remove0x,
} from '@eth-optimism/core-utils'
import { TransactionResponse } from '@ethersproject/abstract-provider'
import { keccak256 } from 'ethers/lib/utils'
import _ from 'lodash' import _ from 'lodash'
/* Internal Imports */ /* Internal Imports */
...@@ -23,7 +28,6 @@ import { ...@@ -23,7 +28,6 @@ import {
ZERO_ADDRESS, ZERO_ADDRESS,
mineBlock, mineBlock,
} from '../../../helpers' } from '../../../helpers'
import { defaultAbiCoder, keccak256 } from 'ethers/lib/utils'
const ELEMENT_TEST_SIZES = [1, 2, 4, 8, 16] const ELEMENT_TEST_SIZES = [1, 2, 4, 8, 16]
const DECOMPRESSION_ADDRESS = '0x4200000000000000000000000000000000000008' const DECOMPRESSION_ADDRESS = '0x4200000000000000000000000000000000000008'
...@@ -31,7 +35,7 @@ const MAX_GAS_LIMIT = 8_000_000 ...@@ -31,7 +35,7 @@ const MAX_GAS_LIMIT = 8_000_000
const getQueueLeafHash = (index: number): string => { const getQueueLeafHash = (index: number): string => {
return keccak256( return keccak256(
defaultAbiCoder.encode( ethers.utils.defaultAbiCoder.encode(
['bool', 'uint256', 'uint256', 'uint256', 'bytes'], ['bool', 'uint256', 'uint256', 'uint256', 'bytes'],
[false, index, 0, 0, '0x'] [false, index, 0, 0, '0x']
) )
...@@ -66,60 +70,12 @@ const encodeQueueTransaction = ( ...@@ -66,60 +70,12 @@ const encodeQueueTransaction = (
gasLimit: number, gasLimit: number,
data: string data: string
): string => { ): string => {
return defaultAbiCoder.encode( return ethers.utils.defaultAbiCoder.encode(
['address', 'address', 'uint256', 'bytes'], ['address', 'address', 'uint256', 'bytes'],
[sender, target, gasLimit, data] [sender, target, gasLimit, data]
) )
} }
interface BatchContext {
numSequencedTransactions: number
numSubsequentQueueTransactions: number
timestamp: number
blockNumber: number
}
interface AppendSequencerBatchParams {
shouldStartAtElement: number // 5 bytes -- starts at batch
totalElementsToAppend: number // 3 bytes -- total_elements_to_append
contexts: BatchContext[] // total_elements[fixed_size[]]
transactions: string[] // total_size_bytes[],total_size_bytes[]
}
const encodeAppendSequencerBatch = (b: AppendSequencerBatchParams): string => {
const encodedShouldStartAtElement = remove0x(
BigNumber.from(b.shouldStartAtElement).toHexString()
).padStart(10, '0')
const encodedTotalElementsToAppend = remove0x(
BigNumber.from(b.totalElementsToAppend).toHexString()
).padStart(6, '0')
const encodedContextsHeader = remove0x(
BigNumber.from(b.contexts.length).toHexString()
).padStart(6, '0')
const encodedContexts =
encodedContextsHeader +
b.contexts.reduce((acc, cur) => acc + encodeBatchContext(cur), '')
const encodedTransactionData = b.transactions.reduce((acc, cur) => {
if (cur.length % 2 !== 0)
throw new Error('Unexpected uneven hex string value!')
const encodedTxDataHeader = remove0x(
BigNumber.from(remove0x(cur).length / 2).toHexString()
).padStart(6, '0')
return acc + encodedTxDataHeader + remove0x(cur)
}, '')
return (
encodedShouldStartAtElement +
encodedTotalElementsToAppend +
encodedContexts +
encodedTransactionData
)
}
const appendSequencerBatch = async ( const appendSequencerBatch = async (
OVM_CanonicalTransactionChain: Contract, OVM_CanonicalTransactionChain: Contract,
batch: AppendSequencerBatchParams batch: AppendSequencerBatchParams
...@@ -132,25 +88,6 @@ const appendSequencerBatch = async ( ...@@ -132,25 +88,6 @@ const appendSequencerBatch = async (
}) })
} }
const encodeBatchContext = (context: BatchContext): string => {
return (
remove0x(
BigNumber.from(context.numSequencedTransactions).toHexString()
).padStart(6, '0') +
remove0x(
BigNumber.from(context.numSubsequentQueueTransactions).toHexString()
).padStart(6, '0') +
remove0x(BigNumber.from(context.timestamp).toHexString()).padStart(
10,
'0'
) +
remove0x(BigNumber.from(context.blockNumber).toHexString()).padStart(
10,
'0'
)
)
}
describe('OVM_CanonicalTransactionChain', () => { describe('OVM_CanonicalTransactionChain', () => {
let signer: Signer let signer: Signer
let sequencer: Signer let sequencer: Signer
...@@ -336,7 +273,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -336,7 +273,7 @@ describe('OVM_CanonicalTransactionChain', () => {
const blockNumber = await getNextBlockNumber(ethers.provider) const blockNumber = await getNextBlockNumber(ethers.provider)
await setEthTime(ethers.provider, timestamp) await setEthTime(ethers.provider, timestamp)
const queueRoot = getTransactionHash( const transactionHash = getTransactionHash(
await signer.getAddress(), await signer.getAddress(),
target, target,
gasLimit, gasLimit,
...@@ -358,7 +295,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -358,7 +295,7 @@ describe('OVM_CanonicalTransactionChain', () => {
await OVM_CanonicalTransactionChain.getQueueElement(0) await OVM_CanonicalTransactionChain.getQueueElement(0)
) )
).to.deep.include({ ).to.deep.include({
queueRoot, transactionHash,
timestamp, timestamp,
blockNumber, blockNumber,
}) })
...@@ -371,7 +308,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -371,7 +308,7 @@ describe('OVM_CanonicalTransactionChain', () => {
it(`gets the element when ${size} elements exist`, async () => { it(`gets the element when ${size} elements exist`, async () => {
let timestamp: number let timestamp: number
let blockNumber: number let blockNumber: number
let queueRoot: string let transactionHash: string
const middleIndex = Math.floor(size / 2) const middleIndex = Math.floor(size / 2)
for (let i = 0; i < size; i++) { for (let i = 0; i < size; i++) {
...@@ -380,7 +317,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -380,7 +317,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber = await getNextBlockNumber(ethers.provider) blockNumber = await getNextBlockNumber(ethers.provider)
await setEthTime(ethers.provider, timestamp) await setEthTime(ethers.provider, timestamp)
queueRoot = getTransactionHash( transactionHash = getTransactionHash(
await signer.getAddress(), await signer.getAddress(),
target, target,
gasLimit, gasLimit,
...@@ -406,7 +343,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -406,7 +343,7 @@ describe('OVM_CanonicalTransactionChain', () => {
await OVM_CanonicalTransactionChain.getQueueElement(middleIndex) await OVM_CanonicalTransactionChain.getQueueElement(middleIndex)
) )
).to.deep.include({ ).to.deep.include({
queueRoot, transactionHash,
timestamp, timestamp,
blockNumber, blockNumber,
}) })
...@@ -419,7 +356,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -419,7 +356,7 @@ describe('OVM_CanonicalTransactionChain', () => {
it(`gets the element when ${size} elements exist`, async () => { it(`gets the element when ${size} elements exist`, async () => {
let timestamp: number let timestamp: number
let blockNumber: number let blockNumber: number
let queueRoot: string let transactionHash: string
for (let i = 0; i < size; i++) { for (let i = 0; i < size; i++) {
if (i === size - 1) { if (i === size - 1) {
...@@ -427,7 +364,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -427,7 +364,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber = await getNextBlockNumber(ethers.provider) blockNumber = await getNextBlockNumber(ethers.provider)
await setEthTime(ethers.provider, timestamp) await setEthTime(ethers.provider, timestamp)
queueRoot = getTransactionHash( transactionHash = getTransactionHash(
await signer.getAddress(), await signer.getAddress(),
target, target,
gasLimit, gasLimit,
...@@ -453,7 +390,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -453,7 +390,7 @@ describe('OVM_CanonicalTransactionChain', () => {
await OVM_CanonicalTransactionChain.getQueueElement(size - 1) await OVM_CanonicalTransactionChain.getQueueElement(size - 1)
) )
).to.deep.include({ ).to.deep.include({
queueRoot, transactionHash,
timestamp, timestamp,
blockNumber, blockNumber,
}) })
...@@ -571,7 +508,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -571,7 +508,7 @@ describe('OVM_CanonicalTransactionChain', () => {
await appendSequencerBatch( await appendSequencerBatch(
OVM_CanonicalTransactionChain.connect(sequencer), OVM_CanonicalTransactionChain.connect(sequencer),
{ {
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
contexts: [ contexts: [
{ {
...@@ -675,7 +612,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -675,7 +612,7 @@ describe('OVM_CanonicalTransactionChain', () => {
await appendSequencerBatch( await appendSequencerBatch(
OVM_CanonicalTransactionChain.connect(sequencer), OVM_CanonicalTransactionChain.connect(sequencer),
{ {
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
contexts: [ contexts: [
{ {
...@@ -730,63 +667,6 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -730,63 +667,6 @@ describe('OVM_CanonicalTransactionChain', () => {
) )
}) })
it('should allow for a lower bound per-tx gas usage of <400 gas [GAS BENCHMARK]', async () => {
const timestamp = (await getEthTime(ethers.provider)) - 100
const blockNumber = await getNextBlockNumber(ethers.provider)
// do two batch appends for no reason
await appendSequencerBatch(OVM_CanonicalTransactionChain, {
shouldStartAtElement: 0,
totalElementsToAppend: 1,
contexts: [
{
numSequencedTransactions: 1,
numSubsequentQueueTransactions: 0,
timestamp,
blockNumber,
},
],
transactions: ['0x1234'],
})
await appendSequencerBatch(OVM_CanonicalTransactionChain, {
shouldStartAtElement: 1,
totalElementsToAppend: 1,
contexts: [
{
numSequencedTransactions: 1,
numSubsequentQueueTransactions: 0,
timestamp,
blockNumber,
},
],
transactions: ['0x1234'],
})
console.log('\n~~~~ BEGINNGING TRASACTION IN QUESTION ~~~~')
const transactions = []
const numTxs = 200
for (let i = 0; i < numTxs; i++) {
transactions.push(
'0x' + '1080111111111111111111111111111111111111111111'.repeat(20)
)
}
const res = await appendSequencerBatch(OVM_CanonicalTransactionChain, {
shouldStartAtElement: 2,
totalElementsToAppend: numTxs,
contexts: [
{
numSequencedTransactions: numTxs,
numSubsequentQueueTransactions: 0,
timestamp,
blockNumber,
},
],
transactions,
})
const receipt = await res.wait()
console.log('Benchmark complete. Gas used:', receipt.gasUsed)
}).timeout(100000000)
it('should revert if expected start does not match current total batches', async () => { it('should revert if expected start does not match current total batches', async () => {
await expect( await expect(
appendSequencerBatch(OVM_CanonicalTransactionChain, { appendSequencerBatch(OVM_CanonicalTransactionChain, {
...@@ -799,7 +679,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -799,7 +679,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber: 0, blockNumber: 0,
}, },
], ],
shouldStartAtElement: 1234, shouldStartAtBatch: 1234,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -822,7 +702,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -822,7 +702,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith('Not all sequencer transactions were processed.') ).to.be.revertedWith('Not all sequencer transactions were processed.')
...@@ -840,7 +720,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -840,7 +720,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber: 0, blockNumber: 0,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith('Function can only be called by the Sequencer.') ).to.be.revertedWith('Function can only be called by the Sequencer.')
...@@ -851,7 +731,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -851,7 +731,7 @@ describe('OVM_CanonicalTransactionChain', () => {
appendSequencerBatch(OVM_CanonicalTransactionChain, { appendSequencerBatch(OVM_CanonicalTransactionChain, {
transactions: ['0x1234'], transactions: ['0x1234'],
contexts: [], contexts: [],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith('Must provide at least one batch context.') ).to.be.revertedWith('Must provide at least one batch context.')
...@@ -869,7 +749,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -869,7 +749,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber: 0, blockNumber: 0,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 0, totalElementsToAppend: 0,
}) })
).to.be.revertedWith('Must append at least one element.') ).to.be.revertedWith('Must append at least one element.')
...@@ -896,10 +776,10 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -896,10 +776,10 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith('Not enough queued transactions to append.') ).to.be.revertedWith('Index out of bounds.')
}) })
it('reverts when there are insufficient (but nonzero) transactions in the queue', async () => { it('reverts when there are insufficient (but nonzero) transactions in the queue', async () => {
...@@ -922,7 +802,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -922,7 +802,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: numEnqueues + 1, totalElementsToAppend: numEnqueues + 1,
}) })
).to.be.revertedWith('Not enough queued transactions to append.') ).to.be.revertedWith('Not enough queued transactions to append.')
...@@ -952,7 +832,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -952,7 +832,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 2, totalElementsToAppend: 2,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -981,7 +861,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -981,7 +861,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 2, totalElementsToAppend: 2,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1015,7 +895,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1015,7 +895,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1039,7 +919,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1039,7 +919,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1075,7 +955,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1075,7 +955,7 @@ describe('OVM_CanonicalTransactionChain', () => {
await appendSequencerBatch(OVM_CanonicalTransactionChain, { await appendSequencerBatch(OVM_CanonicalTransactionChain, {
transactions: new Array(numQueuedTransactions).fill('0x1234'), transactions: new Array(numQueuedTransactions).fill('0x1234'),
contexts: validContexts, contexts: validContexts,
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 2 * numQueuedTransactions, totalElementsToAppend: 2 * numQueuedTransactions,
}) })
}) })
...@@ -1090,7 +970,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1090,7 +970,7 @@ describe('OVM_CanonicalTransactionChain', () => {
appendSequencerBatch(OVM_CanonicalTransactionChain, { appendSequencerBatch(OVM_CanonicalTransactionChain, {
transactions: new Array(numQueuedTransactions).fill('0x1234'), transactions: new Array(numQueuedTransactions).fill('0x1234'),
contexts: invalidTimestampContexts, contexts: invalidTimestampContexts,
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 2 * numQueuedTransactions, totalElementsToAppend: 2 * numQueuedTransactions,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1108,7 +988,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1108,7 +988,7 @@ describe('OVM_CanonicalTransactionChain', () => {
appendSequencerBatch(OVM_CanonicalTransactionChain, { appendSequencerBatch(OVM_CanonicalTransactionChain, {
transactions: new Array(numQueuedTransactions).fill('0x1234'), transactions: new Array(numQueuedTransactions).fill('0x1234'),
contexts: invalidBlockNumberContexts, contexts: invalidBlockNumberContexts,
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 2 * numQueuedTransactions, totalElementsToAppend: 2 * numQueuedTransactions,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1136,7 +1016,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1136,7 +1016,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith('Context timestamp is from the future.') ).to.be.revertedWith('Context timestamp is from the future.')
...@@ -1163,7 +1043,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1163,7 +1043,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 2, totalElementsToAppend: 2,
}) })
).to.be.revertedWith('Context timestamp is from the future.') ).to.be.revertedWith('Context timestamp is from the future.')
...@@ -1184,7 +1064,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1184,7 +1064,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith('Context block number is from the future.') ).to.be.revertedWith('Context block number is from the future.')
...@@ -1212,7 +1092,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1212,7 +1092,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith('Context timestamp too far in the past.') ).to.be.revertedWith('Context timestamp too far in the past.')
...@@ -1236,7 +1116,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1236,7 +1116,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber: 10, blockNumber: 10,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith('Context block number too far in the past.') ).to.be.revertedWith('Context block number too far in the past.')
...@@ -1260,7 +1140,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1260,7 +1140,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
}) })
...@@ -1277,7 +1157,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1277,7 +1157,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 1, shouldStartAtBatch: 1,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1297,7 +1177,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1297,7 +1177,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber: blockNumber - 1, blockNumber: blockNumber - 1,
}, },
], ],
shouldStartAtElement: 1, shouldStartAtBatch: 1,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1322,7 +1202,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1322,7 +1202,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 2, totalElementsToAppend: 2,
}) })
}) })
...@@ -1339,7 +1219,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1339,7 +1219,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 2, shouldStartAtBatch: 2,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1359,7 +1239,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1359,7 +1239,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber: blockNumber - 1, blockNumber: blockNumber - 1,
}, },
], ],
shouldStartAtElement: 2, shouldStartAtBatch: 2,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1393,7 +1273,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1393,7 +1273,7 @@ describe('OVM_CanonicalTransactionChain', () => {
blockNumber, blockNumber,
}, },
], ],
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: 1, totalElementsToAppend: 1,
}) })
).to.be.revertedWith( ).to.be.revertedWith(
...@@ -1436,7 +1316,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1436,7 +1316,7 @@ describe('OVM_CanonicalTransactionChain', () => {
appendSequencerBatch(OVM_CanonicalTransactionChain, { appendSequencerBatch(OVM_CanonicalTransactionChain, {
transactions, transactions,
contexts, contexts,
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: size, totalElementsToAppend: size,
}) })
) )
...@@ -1487,7 +1367,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1487,7 +1367,7 @@ describe('OVM_CanonicalTransactionChain', () => {
appendSequencerBatch(OVM_CanonicalTransactionChain, { appendSequencerBatch(OVM_CanonicalTransactionChain, {
transactions, transactions,
contexts, contexts,
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: size * 2, totalElementsToAppend: size * 2,
}) })
) )
...@@ -1527,7 +1407,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1527,7 +1407,7 @@ describe('OVM_CanonicalTransactionChain', () => {
appendSequencerBatch(OVM_CanonicalTransactionChain, { appendSequencerBatch(OVM_CanonicalTransactionChain, {
transactions, transactions,
contexts, contexts,
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: size + spacing, totalElementsToAppend: size + spacing,
}) })
) )
...@@ -1572,7 +1452,7 @@ describe('OVM_CanonicalTransactionChain', () => { ...@@ -1572,7 +1452,7 @@ describe('OVM_CanonicalTransactionChain', () => {
{ {
transactions, transactions,
contexts, contexts,
shouldStartAtElement: 0, shouldStartAtBatch: 0,
totalElementsToAppend: size, totalElementsToAppend: size,
} }
) )
......
...@@ -51,15 +51,20 @@ ...@@ -51,15 +51,20 @@
ganache-core "^2.12.1" ganache-core "^2.12.1"
glob "^7.1.6" glob "^7.1.6"
"@eth-optimism/core-utils@^0.1.8": "@eth-optimism/core-utils@^0.1.5":
version "0.1.8" version "0.1.5"
resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.1.8.tgz#bf9ac0e537e99a56b2f03af525d317aac5933c41" resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.1.5.tgz#90b3f3d14b25abd8a210d78678d36e54f0c841f4"
integrity sha512-IdRDkyVWmrmbA4P0hvupS+uLSQ1qwG1bWtdvwqeG1+wfDMC7nfZyjdeRWrRZbFvVs/hKk20LERC7L5/lJEo1hA== integrity sha512-DLcHKFXcfoVb0yizfHeDGvgfHYb5DRRMnZyXLXIN0HNrAeavQEjgRFLOo/qy+xNjGI99LKSvyJtHP/C9ImJDag==
dependencies: dependencies:
"@ethersproject/abstract-provider" "^5.0.9" "@ethersproject/abstract-provider" "^5.0.9"
colors "^1.4.0" axios "^0.21.1"
debug "^4.3.1" body-parser "^1.19.0"
ethers "^5.0.31" debug "^4.1.1"
dotenv "^8.2.0"
ethereumjs-util "^6.2.0"
ethers "^5.0.24"
express "^4.17.1"
uuid "^3.3.3"
"@eth-optimism/dev@^1.1.1": "@eth-optimism/dev@^1.1.1":
version "1.1.1" version "1.1.1"
...@@ -133,6 +138,21 @@ ...@@ -133,6 +138,21 @@
fs-extra "^9.0.1" fs-extra "^9.0.1"
hardhat "^2.0.3" hardhat "^2.0.3"
"@eth-optimism/solc@^0.6.12-alpha.1":
version "0.6.12-alpha.1"
resolved "https://registry.yarnpkg.com/@eth-optimism/solc/-/solc-0.6.12-alpha.1.tgz#041876f83b34c6afe2f19dfe9626568df6ed8590"
integrity sha512-Ky73mo+2iNJs/VTaT751nMeZ7hXns0TBAlffTOxIOsScjAZ/zi/KWsDUo3r89aV2JKXcYAU/bLidxF40MVJeUw==
dependencies:
command-exists "^1.2.8"
commander "3.0.2"
follow-redirects "^1.12.1"
fs-extra "^0.30.0"
js-sha3 "0.8.0"
memorystream "^0.3.1"
require-from-string "^2.0.0"
semver "^5.5.0"
tmp "0.0.33"
"@ethereum-waffle/chai@^3.0.0", "@ethereum-waffle/chai@^3.2.2": "@ethereum-waffle/chai@^3.0.0", "@ethereum-waffle/chai@^3.2.2":
version "3.2.2" version "3.2.2"
resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.2.2.tgz#33a349688386c9a8fdc4da5baea329036b9fe75e" resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.2.2.tgz#33a349688386c9a8fdc4da5baea329036b9fe75e"
...@@ -1449,6 +1469,13 @@ aws4@^1.8.0: ...@@ -1449,6 +1469,13 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
axios@^0.21.1:
version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
dependencies:
follow-redirects "^1.10.0"
babel-code-frame@^6.26.0: babel-code-frame@^6.26.0:
version "6.26.0" version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
...@@ -2094,7 +2121,7 @@ bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.1.3: ...@@ -2094,7 +2121,7 @@ bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.1.3:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b"
integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
body-parser@1.19.0, body-parser@^1.16.0: body-parser@1.19.0, body-parser@^1.16.0, body-parser@^1.19.0:
version "1.19.0" version "1.19.0"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
...@@ -2633,11 +2660,6 @@ color-name@~1.1.4: ...@@ -2633,11 +2660,6 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
colors@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
version "1.0.8" version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
...@@ -3143,6 +3165,11 @@ domutils@^2.4.3, domutils@^2.4.4: ...@@ -3143,6 +3165,11 @@ domutils@^2.4.3, domutils@^2.4.4:
domelementtype "^2.0.1" domelementtype "^2.0.1"
domhandler "^4.0.0" domhandler "^4.0.0"
dotenv@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
dotignore@~0.1.2: dotignore@~0.1.2:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905"
...@@ -3821,7 +3848,7 @@ ethers@^4.0.0-beta.1, ethers@^4.0.32: ...@@ -3821,7 +3848,7 @@ ethers@^4.0.0-beta.1, ethers@^4.0.32:
uuid "2.0.1" uuid "2.0.1"
xmlhttprequest "1.8.0" xmlhttprequest "1.8.0"
ethers@^5, ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.14, ethers@^5.0.2, ethers@^5.0.25, ethers@^5.0.31: ethers@^5, ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.14, ethers@^5.0.2, ethers@^5.0.24, ethers@^5.0.25, ethers@^5.0.31:
version "5.0.31" version "5.0.31"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.0.31.tgz#60e3b1425864fe5d2babc147ede01be8382a7d2a" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.0.31.tgz#60e3b1425864fe5d2babc147ede01be8382a7d2a"
integrity sha512-zpq0YbNFLFn+t+ibS8UkVWFeK5w6rVMSvbSHrHAQslfazovLnQ/mc2gdN5+6P45/k8fPgHrfHrYvJ4XvyK/S1A== integrity sha512-zpq0YbNFLFn+t+ibS8UkVWFeK5w6rVMSvbSHrHAQslfazovLnQ/mc2gdN5+6P45/k8fPgHrfHrYvJ4XvyK/S1A==
...@@ -3924,7 +3951,7 @@ expand-template@^2.0.3: ...@@ -3924,7 +3951,7 @@ expand-template@^2.0.3:
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
express@^4.14.0: express@^4.14.0, express@^4.17.1:
version "4.17.1" version "4.17.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
...@@ -4138,7 +4165,7 @@ flow-stoplight@^1.0.0: ...@@ -4138,7 +4165,7 @@ flow-stoplight@^1.0.0:
resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b" resolved "https://registry.yarnpkg.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b"
integrity sha1-SiksW8/4s5+mzAyxqFPYbyfu/3s= integrity sha1-SiksW8/4s5+mzAyxqFPYbyfu/3s=
follow-redirects@^1.12.1: follow-redirects@^1.10.0, follow-redirects@^1.12.1:
version "1.13.2" version "1.13.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147"
integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA== integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==
...@@ -8426,7 +8453,7 @@ uuid@3.3.2: ...@@ -8426,7 +8453,7 @@ uuid@3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
uuid@^3.3.2: uuid@^3.3.2, uuid@^3.3.3:
version "3.4.0" version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
......
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