From c8dd1d5e6189d5defc9541efb8f3ad29585038d1 Mon Sep 17 00:00:00 2001 From: invocamanman Date: Wed, 2 Feb 2022 20:35:26 +0100 Subject: [PATCH 1/2] rename processor and decode rlp --- README.md | 2 +- docs/general-spec.md | 5 - .../{executor-utils.js => processor-utils.js} | 111 ++++++++++++++++++ src/zk-EVM/{executor.js => processor.js} | 50 ++------ src/zk-EVM/zkevm-db.js | 42 +++---- .../proofOfEfficiency-test-vectors.test.js | 2 +- .../helpers/inputs-executor/input_4.json | 5 +- .../test-vector-data/state-transition.json | 2 +- ...-utils.test.js => processor-utils.test.js} | 32 ++++- .../{executor.test.js => processor.test.js} | 4 +- test/src/zk-EVM/utils.test.js | 2 +- test/src/zk-EVM/zkevm-db.test.js | 2 +- .../calldata-test-vector.json | 2 +- .../update-test-vectors.js | 2 +- 14 files changed, 185 insertions(+), 78 deletions(-) delete mode 100644 docs/general-spec.md rename src/zk-EVM/helpers/{executor-utils.js => processor-utils.js} (50%) rename src/zk-EVM/{executor.js => processor.js} (88%) rename test/src/zk-EVM/{executor-utils.test.js => processor-utils.test.js} (69%) rename test/src/zk-EVM/{executor.test.js => processor.test.js} (99%) diff --git a/README.md b/README.md index d955f80a0..0c2ce9aa5 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Smart contract implementation which will be used by the zkEVM - `contracts`: zkEVM contracts - `docs`: specs and useful links -- `src`: js code to interact with the zkEVM, executor, zkEVMDB, sequencer and aggregator. +- `src`: js code to interact with the zkEVM, processor, zkEVMDB, sequencer and aggregator. - `test`: test of all repository ## Activate github hook diff --git a/docs/general-spec.md b/docs/general-spec.md deleted file mode 100644 index 66e904a83..000000000 --- a/docs/general-spec.md +++ /dev/null @@ -1,5 +0,0 @@ -## General specification - -All the information can be found in this link: [HackMD](https://hackmd.io/-M4X8KpuTJmhIxZobKLnnQ). - -> When the specification is more consistent, it will be found in this folder. diff --git a/src/zk-EVM/helpers/executor-utils.js b/src/zk-EVM/helpers/processor-utils.js similarity index 50% rename from src/zk-EVM/helpers/executor-utils.js rename to src/zk-EVM/helpers/processor-utils.js index 7cf9050f1..823ddcc82 100644 --- a/src/zk-EVM/helpers/executor-utils.js +++ b/src/zk-EVM/helpers/processor-utils.js @@ -101,10 +101,121 @@ function encodedStringToArray(encodedTransactions) { return decodedRawTx; } +function decodeNextShortStringRLP(encodedTxBytes, offset) { + if (encodedTxBytes[offset] >= 0xb8) { + throw new Error('Should be a short string RLP'); + } else if (encodedTxBytes[offset] >= 0x80) { + const length = encodedTxBytes[offset] - 0x80; + const result = ethers.utils.hexlify(encodedTxBytes.slice(offset + 1, offset + 1 + length)); + return { consumed: (1 + length), result }; + } else { + return { consumed: 1, result: ethers.utils.hexlify(encodedTxBytes[offset]) }; + } +} + +function decodeNextStringRLP(encodedTxBytes, offset) { + if (encodedTxBytes[offset] >= 0xb8) { + const lengthLength = encodedTxBytes[offset] - 0xb7; + const length = unarrayifyInteger(encodedTxBytes, offset + 1, lengthLength); + const result = ethers.utils.hexlify(encodedTxBytes.slice(offset + 1 + lengthLength, offset + 1 + lengthLength + length)); + return { consumed: (1 + lengthLength + length), result }; + } + return decodeNextShortStringRLP(encodedTxBytes, offset); +} + +function decodeCustomRawTxProverMethod(encodedTransactions) { + // should check total len before read + const encodedTxBytes = ethers.utils.arrayify(encodedTransactions); + const txDecoded = {}; + + let offset = 0; // in zkasm this is the p + + let txListLength = 0; + + // Decode list length + if (encodedTxBytes[offset] < 0xc0) { + throw new Error('headerList should be a list'); + } else if (encodedTxBytes[offset] >= 0xf8) { + const lengthLength = encodedTxBytes[offset] - 0xf7; + txListLength = unarrayifyInteger(encodedTxBytes, offset + 1, lengthLength); + offset = offset + 1 + lengthLength; + } else if (encodedTxBytes[offset] >= 0xc0) { + txListLength = encodedTxBytes[offset] - 0xc0; + offset += 1; + } + + // Nonce read + const decodedNonce = decodeNextShortStringRLP(encodedTxBytes, offset); + offset += decodedNonce.consumed; + txDecoded.nonce = decodedNonce.result; + + // GasPrice read + const decodedGasPrice = decodeNextShortStringRLP(encodedTxBytes, offset); + offset += decodedGasPrice.consumed; + txDecoded.gasPrice = decodedGasPrice.result; + + // gas read + const decodedGasLimit = decodeNextShortStringRLP(encodedTxBytes, offset); + offset += decodedGasLimit.consumed; + txDecoded.gasLimit = decodedGasLimit.result; + + // To READ + if (encodedTxBytes[offset] === 0x80) { + txDecoded.to = '0x'; + // isContract = true + } else if (encodedTxBytes[offset] === 0x94) { + const length = 20; + txDecoded.to = ethers.utils.hexlify(encodedTxBytes.slice(offset + 1, offset + 1 + length)); + offset += 1 + length; + } else { + throw new Error('To should be an address or empty'); + } + + // Value READ + const decodedValue = decodeNextShortStringRLP(encodedTxBytes, offset); + offset += decodedValue.consumed; + txDecoded.value = decodedValue.result; + + // Data READ + const decodedData = decodeNextStringRLP(encodedTxBytes, offset); + offset += decodedData.consumed; + txDecoded.data = decodedData.result; + + // Value READ + const decodedChainID = decodeNextShortStringRLP(encodedTxBytes, offset); + offset += decodedChainID.consumed; + txDecoded.chainID = decodedChainID.result; + + if ((encodedTxBytes[offset] !== 0x80) || encodedTxBytes[offset + 1] !== 0x80) { + throw new Error('The last 2 values should be 0x8080'); + } + offset += 2; + + if (txListLength + 1 !== offset) { + throw new Error('Invalid list length'); + } + + const rlpSignData = ethers.utils.hexlify(encodedTxBytes.slice(0, offset)); + + const lenR = 32; + const lenS = 32; + const lenV = 1; + + txDecoded.r = ethers.utils.hexlify(encodedTxBytes.slice(offset, offset + lenR)); + offset += lenR; + txDecoded.s = ethers.utils.hexlify(encodedTxBytes.slice(offset, offset + lenS)); + offset += lenS; + txDecoded.v = ethers.utils.hexlify(encodedTxBytes.slice(offset, offset + lenV)); + offset += lenV; + + return { txDecoded, rlpSignData }; +} + module.exports = { toHexStringRlp, customRawTxToRawTx, rawTxToCustomRawTx, arrayToEncodedString, encodedStringToArray, + decodeCustomRawTxProverMethod, }; diff --git a/src/zk-EVM/executor.js b/src/zk-EVM/processor.js similarity index 88% rename from src/zk-EVM/executor.js rename to src/zk-EVM/processor.js index b0b1558f9..2e793b808 100644 --- a/src/zk-EVM/executor.js +++ b/src/zk-EVM/processor.js @@ -11,8 +11,9 @@ const smtKeyUtils = require('./helpers/smt-key-utils'); const { getCurrentDB } = require('./helpers/smt-utils'); const { calculateCircuitInput, calculateBatchHashData } = require('./helpers/contract-utils'); +const { decodeCustomRawTxProverMethod } = require('./helpers/processor-utils'); -module.exports = class Executor { +module.exports = class Processor { constructor(db, batchNumber, arity, poseidon, maxNTx, seqChainID, root, sequencerAddress, localExitRoot, globalExitRoot) { this.db = db; this.batchNumber = batchNumber; @@ -37,7 +38,7 @@ module.exports = class Executor { } /** - * Add a raw transaction to the executor + * Add a raw transaction to the processor * @param {Object} rawTx - RLP encoded transaction with signature */ addRawTx(rawTx) { @@ -85,52 +86,19 @@ module.exports = class Executor { for (let i = 0; i < this.rawTxs.length; i++) { const rawTx = this.rawTxs[i]; - // A: Well formed RLP encoding - const signatureCharacters = Constants.signatureBytes * 2; - const rlpSignData = rawTx.slice(0, -signatureCharacters); - const signature = `0x${rawTx.slice(-signatureCharacters)}`; - + // Decode raw transaction using prover method let txDecoded; - - // Decode rlp signing data + let rlpSignData; try { - const txFields = ethers.utils.RLP.decode(rlpSignData); - - txDecoded = { - nonce: txFields[0], - gasPrice: txFields[1], - gasLimit: txFields[2], - to: txFields[3], - value: txFields[4], - data: txFields[5], - chainID: Number(txFields[6]), - }; - - if (txFields[7] !== '0x' || txFields[8] !== '0x') { - throw new Error('The rlp encode should be: rlp(nonce, gasprice, startgas, to, value, data, chainid, 0, 0)'); - } + const decodedObject = decodeCustomRawTxProverMethod(rawTx); + txDecoded = decodedObject.txDecoded; + rlpSignData = decodedObject.rlpSignData; } catch (error) { this.decodedTxs.push({ isInvalid: true, reason: 'TX INVALID: Failed to RLP decode signing data', tx: txDecoded }); continue; } - - // Decode signature - try { - const { r, s, v } = ethers.utils.splitSignature(signature); - txDecoded.r = r; - txDecoded.s = s; - txDecoded.v = v; - } catch (error) { - this.decodedTxs.push({ isInvalid: true, reason: 'TX INVALID: Failed to decode singature', tx: txDecoded }); - continue; - } txDecoded.from = undefined; - - // TODO should be check the type of every decoded parameter? - if (!ethers.utils.isAddress(txDecoded.to)) { - this.decodedTxs.push({ isInvalid: true, reason: 'TX INVALID: To invalid address', tx: txDecoded }); - continue; - } + txDecoded.chainID = Number(txDecoded.chainID); // B: Valid chainID if (txDecoded.chainID !== this.seqChainID && txDecoded.chainID !== Constants.defaultSeqChainID) { diff --git a/src/zk-EVM/zkevm-db.js b/src/zk-EVM/zkevm-db.js index 36514dac9..d7cc68b04 100644 --- a/src/zk-EVM/zkevm-db.js +++ b/src/zk-EVM/zkevm-db.js @@ -1,7 +1,7 @@ const { Scalar } = require('ffjavascript'); const Constants = require('./constants'); -const Executor = require('./executor'); +const Processor = require('./processor'); const SMT = require('./zkproverjs/smt'); const { getState } = require('./helpers/state-utils'); const { getValue, setValue } = require('./helpers/db-key-value-utils'); @@ -25,11 +25,11 @@ class ZkEVMDB { } /** - * Return a new Executor with the current RollupDb state + * Return a new Processor with the current RollupDb state * @param {Scalar} maxNTx - Maximum number of transactions */ async buildBatch(maxNTx = Constants.defaultMaxTx) { - return new Executor( + return new Processor( this.db, Scalar.add(this.lastBatch, 1), this.arity, @@ -45,24 +45,24 @@ class ZkEVMDB { /** * Consolidate a batch by writing it in the DB - * @param {Object} executor - Executor object + * @param {Object} processor - Processor object */ - async consolidate(executor) { - if (executor.batchNumber !== Scalar.add(this.lastBatch, 1)) { + async consolidate(processor) { + if (processor.batchNumber !== Scalar.add(this.lastBatch, 1)) { throw new Error('Updating the wrong batch'); } - if (!executor.builded) { - await executor.executeTxs(); + if (!processor.builded) { + await processor.executeTxs(); } // Populate actual DB with the keys and values inserted in the batch - await executor.tmpDB.populateSrcDb(); + await processor.tmpDB.populateSrcDb(); // Set state root await setValue( - Scalar.add(Constants.DB_StateRoot, executor.batchNumber), - this.F.toString(executor.currentRoot), + Scalar.add(Constants.DB_StateRoot, processor.batchNumber), + this.F.toString(processor.currentRoot), this.db, this.F, ); @@ -71,9 +71,9 @@ class ZkEVMDB { await setValue( Scalar.add( Constants.DB_LocalExitRoot, - executor.batchNumber, + processor.batchNumber, ), - this.F.toString(executor.localExitRoot), + this.F.toString(processor.localExitRoot), this.db, this.F, ); @@ -82,21 +82,21 @@ class ZkEVMDB { await setValue( Scalar.add( Constants.DB_GlobalExitRoot, - executor.batchNumber, + processor.batchNumber, ), - this.F.toString(executor.globalExitRoot), + this.F.toString(processor.globalExitRoot), this.db, this.F, ); // Set last batch number - await setValue(Constants.DB_LastBatch, executor.batchNumber, this.db, this.F); + await setValue(Constants.DB_LastBatch, processor.batchNumber, this.db, this.F); // Update ZKEVMDB variables - this.lastBatch = executor.batchNumber; - this.stateRoot = executor.currentRoot; - this.localExitRoot = executor.localExitRoot; - this.globalExitRoot = executor.globalExitRoot; + this.lastBatch = processor.batchNumber; + this.stateRoot = processor.currentRoot; + this.localExitRoot = processor.localExitRoot; + this.globalExitRoot = processor.globalExitRoot; } /** @@ -146,7 +146,7 @@ class ZkEVMDB { * @param {Object} seqChainID - Sequencer chian id * @param {Object} poseidon - Poseidon object * @param {String} sequencerAddress - Sequencer address - * @param {Uint8Array} root - Executor object + * @param {Uint8Array} root - Processor object * @returns {Object} ZkEVMDB object */ static async newZkEVM(db, seqChainID, arity, poseidon, sequencerAddress, stateRoot, localExitRoot, globalExitRoot) { diff --git a/test/contracts/proofOfEfficiency-test-vectors.test.js b/test/contracts/proofOfEfficiency-test-vectors.test.js index da36ddf2c..d5e47fe5e 100644 --- a/test/contracts/proofOfEfficiency-test-vectors.test.js +++ b/test/contracts/proofOfEfficiency-test-vectors.test.js @@ -11,7 +11,7 @@ const stateUtils = require('../../src/zk-EVM/helpers/state-utils'); const ZkEVMDB = require('../../src/zk-EVM/zkevm-db'); const { setGenesisBlock } = require('../src/zk-EVM/helpers/test-helpers'); -const { rawTxToCustomRawTx, toHexStringRlp } = require('../../src/zk-EVM/helpers/executor-utils'); +const { rawTxToCustomRawTx, toHexStringRlp } = require('../../src/zk-EVM/helpers/processor-utils'); const { calculateCircuitInput } = require('../../src/zk-EVM/helpers/contract-utils'); diff --git a/test/src/zk-EVM/helpers/inputs-executor/input_4.json b/test/src/zk-EVM/helpers/inputs-executor/input_4.json index 23bdcbb48..dccda8657 100644 --- a/test/src/zk-EVM/helpers/inputs-executor/input_4.json +++ b/test/src/zk-EVM/helpers/inputs-executor/input_4.json @@ -1,5 +1,8 @@ { - "keys": {}, + "keys": { + "03ae74d1bbdff41d14f155ec79bb389db716160c1766a49ee9c9707407f80a11": "00000000000000000000000000000000000000000000000ad78ebc5ac6200000", + "18d749d7bcc2bc831229c19256f9e933c08b6acdaff4915be158e34cbbc8a8e1": "0000000000000000000000000000000000000000000000000000000000000000" + }, "oldStateRoot": "0x090bcaf734c4f06c93954a827b45a6e8c67b8e0fd1e0a35a1c5982d6961828f9", "chainId": 1001, "db": { diff --git a/test/src/zk-EVM/helpers/test-vector-data/state-transition.json b/test/src/zk-EVM/helpers/test-vector-data/state-transition.json index af9cbdd1b..6310dac9e 100644 --- a/test/src/zk-EVM/helpers/test-vector-data/state-transition.json +++ b/test/src/zk-EVM/helpers/test-vector-data/state-transition.json @@ -361,7 +361,7 @@ "gasPrice": "1", "chainId": 1001, "rawTx": "0xee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e980801186622d03b6b8da7cf111d1ccba5bb185c56deae6a322cebc6dda0556f3cb9700910c26408b64b51c5da36ba2f38ef55ba1cee719d5a6c012259687999074321b", - "reason": "TX INVALID: Failed to RLP decode signing data" + "reason": "TX INVALID: Failed signature" } ], "expectedNewRoot": "4091651772388093439828475955668620102367778455436412389529460210592290187513", diff --git a/test/src/zk-EVM/executor-utils.test.js b/test/src/zk-EVM/processor-utils.test.js similarity index 69% rename from test/src/zk-EVM/executor-utils.test.js rename to test/src/zk-EVM/processor-utils.test.js index cbc0fe737..f36d5c62f 100644 --- a/test/src/zk-EVM/executor-utils.test.js +++ b/test/src/zk-EVM/processor-utils.test.js @@ -6,7 +6,9 @@ const { expect } = require('chai'); const fs = require('fs'); const path = require('path'); const { Scalar } = require('ffjavascript'); -const { toHexStringRlp, customRawTxToRawTx, rawTxToCustomRawTx } = require('../../../src/zk-EVM/helpers/executor-utils'); +const { + toHexStringRlp, customRawTxToRawTx, rawTxToCustomRawTx, decodeCustomRawTxProverMethod, +} = require('../../../src/zk-EVM/helpers/processor-utils'); describe('Encode and decode transactions in RLP', () => { let testVectors; @@ -85,6 +87,34 @@ describe('Encode and decode transactions in RLP', () => { expect(rawTxEthers).to.equal(reconstructedEthers); } expect(customRawTx).to.equal(txData.rawTx); + + // Test decode raw tx prover method + const { txDecoded, rlpSignData } = decodeCustomRawTxProverMethod(customRawTx); + const signData = ethers.utils.RLP.encode([ + toHexStringRlp(Scalar.e(tx.nonce)), + toHexStringRlp(tx.gasPrice), + toHexStringRlp(tx.gasLimit), + toHexStringRlp(tx.to), + toHexStringRlp(tx.value), + toHexStringRlp(tx.data), + toHexStringRlp(tx.chainId), + '0x', + '0x', + ]); + expect(rlpSignData).to.equal(signData); + + const txParams = Object.keys(txDecoded); + txParams.forEach((key) => { + if (txDecoded[key] === '0x' && key !== 'data') { + txDecoded[key] = '0x00'; + } + }); + expect(Number(txDecoded.nonce)).to.equal(tx.nonce); + expect(ethers.BigNumber.from(txDecoded.gasPrice)).to.equal(tx.gasPrice); + expect(ethers.BigNumber.from(txDecoded.gasLimit)).to.equal(tx.gasLimit); + expect(ethers.BigNumber.from(txDecoded.to)).to.equal(ethers.BigNumber.from(tx.to)); + expect(ethers.BigNumber.from(txDecoded.value)).to.equal(tx.value); + expect(Number(txDecoded.chainID)).to.equal(tx.chainId); } catch (error) { expect(txData.customRawTx).to.equal(undefined); } diff --git a/test/src/zk-EVM/executor.test.js b/test/src/zk-EVM/processor.test.js similarity index 99% rename from test/src/zk-EVM/executor.test.js rename to test/src/zk-EVM/processor.test.js index 62a520d94..0d9d67827 100644 --- a/test/src/zk-EVM/executor.test.js +++ b/test/src/zk-EVM/processor.test.js @@ -12,12 +12,12 @@ const path = require('path'); const MemDB = require('../../../src/zk-EVM/zkproverjs/memdb'); const SMT = require('../../../src/zk-EVM/zkproverjs/smt'); const stateUtils = require('../../../src/zk-EVM/helpers/state-utils'); -const { rawTxToCustomRawTx, toHexStringRlp } = require('../../../src/zk-EVM/helpers/executor-utils'); +const { rawTxToCustomRawTx, toHexStringRlp } = require('../../../src/zk-EVM/helpers/processor-utils'); const ZkEVMDB = require('../../../src/zk-EVM/zkevm-db'); const { setGenesisBlock } = require('./helpers/test-helpers'); -describe('Executor Test', async function () { +describe('Processor Test', async function () { this.timeout(60000); let poseidon; let F; diff --git a/test/src/zk-EVM/utils.test.js b/test/src/zk-EVM/utils.test.js index 28229ee49..95b3689dd 100644 --- a/test/src/zk-EVM/utils.test.js +++ b/test/src/zk-EVM/utils.test.js @@ -8,7 +8,7 @@ const path = require('path'); const { Scalar } = require('ffjavascript'); const { rawTxToCustomRawTx, toHexStringRlp, arrayToEncodedString, encodedStringToArray, -} = require('../../../src/zk-EVM/helpers/executor-utils'); +} = require('../../../src/zk-EVM/helpers/processor-utils'); describe('Encode and decode transactions in RLP', () => { let testVectors; diff --git a/test/src/zk-EVM/zkevm-db.test.js b/test/src/zk-EVM/zkevm-db.test.js index 380da1fd0..eca9a513f 100644 --- a/test/src/zk-EVM/zkevm-db.test.js +++ b/test/src/zk-EVM/zkevm-db.test.js @@ -16,7 +16,7 @@ const { getValue } = require('../../../src/zk-EVM/helpers/db-key-value-utils'); const ZkEVMDB = require('../../../src/zk-EVM/zkevm-db'); const { setGenesisBlock } = require('./helpers/test-helpers'); -const { rawTxToCustomRawTx, toHexStringRlp } = require('../../../src/zk-EVM/helpers/executor-utils'); +const { rawTxToCustomRawTx, toHexStringRlp } = require('../../../src/zk-EVM/helpers/processor-utils'); describe('zkEVM-db Test', () => { let poseidon; diff --git a/tools/calldata-test-vectors/calldata-test-vector.json b/tools/calldata-test-vectors/calldata-test-vector.json index de0cf8205..b30abefba 100644 --- a/tools/calldata-test-vectors/calldata-test-vector.json +++ b/tools/calldata-test-vectors/calldata-test-vector.json @@ -175,7 +175,7 @@ "gasPrice": "1", "chainId": 1001, "rawTx": "0xee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e980801186622d03b6b8da7cf111d1ccba5bb185c56deae6a322cebc6dda0556f3cb9700910c26408b64b51c5da36ba2f38ef55ba1cee719d5a6c012259687999074321b", - "reason": "TX INVALID: Failed to RLP decode signing data" + "reason": "TX INVALID: Failed signature" } ], "batchL2Data": "0xee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e980801186622d03b6b8da7cf111d1ccba5bb185c56deae6a322cebc6dda0556f3cb9700910c26408b64b51c5da36ba2f38ef55ba1cee719d5a6c0122596879990", diff --git a/tools/update-test-vectors/update-test-vectors.js b/tools/update-test-vectors/update-test-vectors.js index 82ecf96ac..d380d2cc3 100644 --- a/tools/update-test-vectors/update-test-vectors.js +++ b/tools/update-test-vectors/update-test-vectors.js @@ -11,7 +11,7 @@ const path = require('path'); const MemDB = require('../../src/zk-EVM/zkproverjs/memdb'); const SMT = require('../../src/zk-EVM/zkproverjs/smt'); const stateUtils = require('../../src/zk-EVM/helpers/state-utils'); -const { rawTxToCustomRawTx, toHexStringRlp } = require('../../src/zk-EVM/helpers/executor-utils'); +const { rawTxToCustomRawTx, toHexStringRlp } = require('../../src/zk-EVM/helpers/processor-utils'); const ZkEVMDB = require('../../src/zk-EVM/zkevm-db'); const { setGenesisBlock } = require('../../test/src/zk-EVM/helpers/test-helpers'); From 30bb070c816b62f3583384f49b4820f8c663e996 Mon Sep 17 00:00:00 2001 From: invocamanman Date: Fri, 4 Feb 2022 22:40:02 +0100 Subject: [PATCH 2/2] PR fixex --- src/zk-EVM/helpers/processor-utils.js | 50 +++++++++++++++++++++++++++ src/zk-EVM/zkevm-db.js | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/zk-EVM/helpers/processor-utils.js b/src/zk-EVM/helpers/processor-utils.js index 823ddcc82..d39b229b8 100644 --- a/src/zk-EVM/helpers/processor-utils.js +++ b/src/zk-EVM/helpers/processor-utils.js @@ -2,6 +2,13 @@ const { ethers } = require('hardhat'); const { Scalar } = require('ffjavascript'); const Constants = require('../constants'); +/** + * Extract an integer from a byte array + * @param {Uint8Array} data - Byte array + * @param {Number} offset - Offset of the data array + * @param {Number} length - Length of the integer in bytes + * @returns {Number} - Extracted integer + */ function unarrayifyInteger(data, offset, length) { let result = 0; for (let i = 0; i < length; i++) { @@ -10,6 +17,11 @@ function unarrayifyInteger(data, offset, length) { return result; } +/** + * Convert a number type to a hex string starting with 0x and with a integer number of bytes + * @param {Number | BigInt | BigNumber | Object} num - Number + * @returns {Number} - Hex string + */ function toHexStringRlp(num) { let numHex; if (typeof num === 'number' || typeof num === 'bigint' || typeof num === 'object') { @@ -23,6 +35,12 @@ function toHexStringRlp(num) { return numHex; } +/** + * Convert a standar rawTx of ethereum [rlp(nonce,gasprice,gaslimit,to,value,data,r,s,v)] + * to our custom raw tx [rlp(nonce,gasprice,gaslimit,to,value,data,0,0)|r|s|v] + * @param {String} rawTx - Standar raw transaction + * @returns {String} - Custom raw transaction + */ function rawTxToCustomRawTx(rawTx) { const tx = ethers.utils.parseTransaction(rawTx); const signData = ethers.utils.RLP.encode([ @@ -43,6 +61,12 @@ function rawTxToCustomRawTx(rawTx) { return signData.concat(r).concat(s).concat(v); } +/** + * Convert a custom rawTx [rlp(nonce,gasprice,gaslimit,to,value,data,0,0)|r|s|v] + * to a standar raw tx [rlp(nonce,gasprice,gaslimit,to,value,data,r,s,v)] + * @param {String} customRawTx - Custom raw transaction + * @returns {String} - Standar raw transaction + */ function customRawTxToRawTx(customRawTx) { const signatureCharacters = Constants.signatureBytes * 2; const rlpSignData = customRawTx.slice(0, -signatureCharacters); @@ -60,10 +84,20 @@ function customRawTxToRawTx(customRawTx) { return ethers.utils.RLP.encode(rlpFields); } +/** + * Reduce an array of rawTx to a single string wich will be the BatchL2Data + * @param {Array} rawTxs - Array of rawTxs + * @returns {String} - Reduced array + */ function arrayToEncodedString(rawTxs) { return rawTxs.reduce((previousValue, currentValue) => previousValue + currentValue.slice(2), '0x'); } +/** + * Decode the BatchL2Data to an array of rawTxs + * @param {String} encodedTransactions - Reduced array + * @returns {Array} - Array of rawTxs + */ function encodedStringToArray(encodedTransactions) { const encodedTxBytes = ethers.utils.arrayify(encodedTransactions); const decodedRawTx = []; @@ -101,6 +135,12 @@ function encodedStringToArray(encodedTransactions) { return decodedRawTx; } +/** + * Decode The next string in rlp, wich has 0-55 bytes long + * @param {Uint8Array} data - Byte array + * @param {Number} offset - Offset of the data array + * @returns {Object} - Return the bytes consumed and the result encoded in hex string + */ function decodeNextShortStringRLP(encodedTxBytes, offset) { if (encodedTxBytes[offset] >= 0xb8) { throw new Error('Should be a short string RLP'); @@ -113,6 +153,11 @@ function decodeNextShortStringRLP(encodedTxBytes, offset) { } } +/** + * Decode The next string in rlp + * @param {String} encodedTxBytes - Reduced array + * @returns {Array} - Array of rawTxs + */ function decodeNextStringRLP(encodedTxBytes, offset) { if (encodedTxBytes[offset] >= 0xb8) { const lengthLength = encodedTxBytes[offset] - 0xb7; @@ -123,6 +168,11 @@ function decodeNextStringRLP(encodedTxBytes, offset) { return decodeNextShortStringRLP(encodedTxBytes, offset); } +/** + * Decode the BatchL2Data to an array of rawTxs using the prover method + * @param {String} encodedTransactions - Reduced array + * @returns {Object} - The object contain the Array of rawTxs and the rlpSignData as the prover does + */ function decodeCustomRawTxProverMethod(encodedTransactions) { // should check total len before read const encodedTxBytes = ethers.utils.arrayify(encodedTransactions); diff --git a/src/zk-EVM/zkevm-db.js b/src/zk-EVM/zkevm-db.js index d7cc68b04..95e11e0ef 100644 --- a/src/zk-EVM/zkevm-db.js +++ b/src/zk-EVM/zkevm-db.js @@ -146,7 +146,7 @@ class ZkEVMDB { * @param {Object} seqChainID - Sequencer chian id * @param {Object} poseidon - Poseidon object * @param {String} sequencerAddress - Sequencer address - * @param {Uint8Array} root - Processor object + * @param {Uint8Array} root - Merkle root * @returns {Object} ZkEVMDB object */ static async newZkEVM(db, seqChainID, arity, poseidon, sequencerAddress, stateRoot, localExitRoot, globalExitRoot) {