diff --git a/src/blob-inner/blob-constants.js b/src/blob-inner/blob-constants.js index 9fc3fd84..2e0879bd 100644 --- a/src/blob-inner/blob-constants.js +++ b/src/blob-inner/blob-constants.js @@ -7,6 +7,7 @@ module.exports.FIELD_ELEMENTS_PER_BLOB = fieldElementsPerBlob; module.exports.BYTES_PER_FIELD_ELEMENT = bytesPerFieldElement; module.exports.BLOB_BYTES = fieldElementsPerBlob * bytesPerFieldElement; // 131072 module.exports.ZKGAS_BATCH = 100000000; +module.exports.MAX_BATCHES_FORCED = 1; // blob type module.exports.BLOB_TYPE = { diff --git a/src/blob-inner/blob-processor.js b/src/blob-inner/blob-processor.js index d78d0eb8..f241345b 100644 --- a/src/blob-inner/blob-processor.js +++ b/src/blob-inner/blob-processor.js @@ -99,13 +99,13 @@ module.exports = class BlobProcessor { const batchL2Data = _batchL2Data.startsWith('0x') ? _batchL2Data.slice(2) : _batchL2Data; if (batchL2Data === '') { - this.blobLength += 4; + this.blobLength += blobConstants.BLOB_ENCODING.BYTES_BATCH_LENGTH; } else { // check hexadecimal string if (!isHex(batchL2Data)) { throw new Error('BlobProcessor:addBatchL2Data: invalid hexadecimal string'); } - this.blobLength += 4 + batchL2Data.length / 2; + this.blobLength += blobConstants.BLOB_ENCODING.BYTES_BATCH_LENGTH + batchL2Data.length / 2; } this.batches.push(batchL2Data); @@ -156,8 +156,15 @@ module.exports = class BlobProcessor { // build blobData this._buildBlobData(); - // check zkGasLimit - await this._checkZkGasLimit(); + // check forced batches + if (this.isInvalid === false) { + this._checkForcedBatches(); + } + + // check zkGasLimit if not already invalid blob + if (this.isInvalid === false) { + await this._checkZkGasLimit(); + } // read local exit root if necessary if (this.isInvalid === true) { @@ -178,11 +185,18 @@ module.exports = class BlobProcessor { this.isInvalid = res.isInvalid; this.batches = res.batches; } else { - // TODO: Build empty blobInner with no batches. Almost same result throw new Error('BlobProcessor:executeBlob: no data added'); } } + _checkForcedBatches() { + if (this.blobType === blobConstants.BLOB_TYPE.FORCED) { + if (this.batches.length > blobConstants.MAX_BATCHES_FORCED) { + this.isInvalid = true; + } + } + } + _checkZkGasLimit() { const minZkGasLimit = Scalar.mul(this.batches.length, blobConstants.ZKGAS_BATCH); diff --git a/test/blob-inner/blob-inner-processor.test.js b/test/blob-inner/blob-inner-processor.test.js index c85caf08..f2ac4edb 100644 --- a/test/blob-inner/blob-inner-processor.test.js +++ b/test/blob-inner/blob-inner-processor.test.js @@ -43,7 +43,7 @@ describe('BlobProcessor', async function () { }); it('Check test vectors', async () => { - for (let i = 0; i < testVectors.length; i++) { + for (let i = 4; i < testVectors.length; i++) { let { description, preExecution, diff --git a/test/helpers/test-vectors/blob-inner/blob-inner-data.json b/test/helpers/test-vectors/blob-inner/blob-inner-data.json index 82c87808..02478797 100644 --- a/test/helpers/test-vectors/blob-inner/blob-inner-data.json +++ b/test/helpers/test-vectors/blob-inner/blob-inner-data.json @@ -106,5 +106,78 @@ "localExitRootFromBlob": "0x0000000000000000000000000000000000000000000000000000000000000001", "isInvalid": true } + }, + { + "id": 3, + "description": "blob type 2, one valid batch", + "preExecution": { + "initLocalExitRoot": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "inputBlob": { + "publics": { + "oldBlobStateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "oldBlobAccInputHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "oldNumBlob": 0, + "forkID": 10, + "oldStateRoot": "0x799c98013da3f7a43b6e8086d0cedd89bd6a9bfef7179ce30755b27f7e9be302" + }, + "private": { + "lastL1InfoTreeIndex": 42, + "lastL1InfoTreeRoot": "0x4242424242424242424242424242424242424242424242424242424242424242", + "timestampLimit": "1944498031", + "sequencerAddress": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", + "blobType": 2, + "zkGasLimit": "1000000000000000000", + "forcedHashData": "0x9f778fe86955a7ac8ccb2e9e0c98ada37dd8e3c4b739b6224fa910fc4c93c4a1" + } + }, + "batchesData": [ + "0x0b73e6af6f00000000ee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e880801cee7e01dc62f69a12c3510c6d64de04ee6346d84b6a017f3e786c7d87f963e75d8cc91fa983cd6d9cf55fff80d73bd26cd333b0f098acc1e58edb1fd484ad731bff" + ], + "expected": { + "newBlobStateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newBlobAccInputHash": "0x6baa9dc5d111235c41f2cb0c359c50080d4ce025c93c3f43f8ba1200dfbb9b6b", + "newNumBlob": 1, + "finalAccBatchHashData": "0x0213125971c403a77ebe0b009d5a3350bc36355427d35d7807013930cad6ecc2", + "localExitRootFromBlob": "0x0000000000000000000000000000000000000000000000000000000000000000", + "isInvalid": false + } + }, + { + "id": 4, + "description": "blob type 2, two batches, invalid forced", + "preExecution": { + "initLocalExitRoot": "0x0000000000000000000000000000000000000000000000000000000000000001" + }, + "inputBlob": { + "publics": { + "oldBlobStateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "oldBlobAccInputHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "oldNumBlob": 0, + "forkID": 10, + "oldStateRoot": "0x799c98013da3f7a43b6e8086d0cedd89bd6a9bfef7179ce30755b27f7e9be302" + }, + "private": { + "lastL1InfoTreeIndex": 42, + "lastL1InfoTreeRoot": "0x4242424242424242424242424242424242424242424242424242424242424242", + "timestampLimit": "1944498031", + "sequencerAddress": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", + "blobType": 2, + "zkGasLimit": "1000000000000000000", + "forcedHashData": "0x9f778fe86955a7ac8ccb2e9e0c98ada37dd8e3c4b739b6224fa910fc4c93c4a1" + } + }, + "batchesData": [ + "0x0b73e6af6f00000000ee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e880801cee7e01dc62f69a12c3510c6d64de04ee6346d84b6a017f3e786c7d87f963e75d8cc91fa983cd6d9cf55fff80d73bd26cd333b0f098acc1e58edb1fd484ad731bff", + "0x0b73e6af6f00000000ee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e880801cee7e01dc62f69a12c3510c6d64de04ee6346d84b6a017f3e786c7d87f963e75d8cc91fa983cd6d9cf55fff80d73bd26cd333b0f098acc1e58edb1fd484ad731bff" + ], + "expected": { + "newBlobStateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", + "newBlobAccInputHash": "0x591f1dcb2bf2f3620d3e5ce5d11b34c346e114310eb034708a0681d7619b94d9", + "newNumBlob": 1, + "finalAccBatchHashData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "localExitRootFromBlob": "0x0000000000000000000000000000000000000000000000000000000000000001", + "isInvalid": true + } } ] \ No newline at end of file