Skip to content

Commit

Permalink
Merge pull request #134 from 0xPolygonHermez/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
krlosMata authored Feb 1, 2024
2 parents 2a5fee0 + 8e09d92 commit fefa98e
Show file tree
Hide file tree
Showing 43 changed files with 5,904 additions and 681 deletions.
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ module.exports = {
'no-console': [2, { allow: ['warn', 'error'] }],
'import/prefer-default-export': [0],
'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }],
'multiline-comment-style': 'error',
'no-await-in-loop': 'off',
'newline-before-return': 'error',
},
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ on:
branches:
- main
- develop
- feature/fork-etrog

jobs:
build:
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,7 @@ test/cache
package-lock.json

# ignore genesis
tools/fill-genesis/*.ignore.json
tools/fill-genesis/*.ignore.json

# input examples
tools/inputs-examples/
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ module.exports.getPoseidon = require('./src/poseidon_opt');
module.exports.MTBridge = require('./src/mt-bridge');
module.exports.mtBridgeUtils = require('./src/mt-bridge-utils');
module.exports.Database = require('./src/database');
module.exports.l1InfoTreeUtils = require('./src/l1-info-tree-utils');
module.exports.VirtualCountersManager = require('./src/virtual-counters-manager');
module.exports.blockUtils = require('./src/block-utils');
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
"main": "index.js",
"scripts": {
"setup": "npm i",
"test": "cd test && npx hardhat compile && cd .. && npx mocha ./test/*.test.js && npm run test:e2e && npm run test:blockinfo && npm run test:selfdestruct",
"test": "cd test && npx hardhat compile && cd .. && npx mocha ./test/*.test.js && npm run test:e2e && npm run test:blockinfo && npm run test:selfdestruct && npm run test:etrog",
"test:etrog": "npx mocha ./test/processor.test.js --etrog",
"test:e2e": "npx mocha ./test/processor.test.js --e2e",
"test:blockinfo": "npx mocha ./test/processor.test.js --blockinfo",
"test:selfdestruct": "npx mocha ./test/processor.test.js --selfdestruct",
"eslint": "npx eslint src/** test/*.test.js && npx eslint tools",
"eslint:fix": "npx eslint src/** test/*.test.js --fix && npx eslint tools --fix",
"test:update": "./tools/update-tests/update-tests.sh",
"test:database": "npx mocha ./test/database.test.js"
"test:database": "npx mocha ./test/database.test.js",
"build:inputs": "npx mocha ./test/processor.test.js --update --geninputs && npx mocha ./test/processor.test.js --etrog --update --geninputs"
},
"repository": {
"type": "git",
Expand All @@ -35,7 +37,7 @@
},
"homepage": "https://github.com/0xPolygonHermez/zkevm-commonjs#readme",
"devDependencies": {
"@0xpolygonhermez/zkevm-contracts": "github:0xPolygonHermez/zkevm-contracts#v3.0.0-rc.1-fork.6",
"@0xpolygonhermez/zkevm-contracts": "github:0xPolygonHermez/zkevm-contracts#feature/l1-info-tree",
"@ethersproject/abi": "^5.6.4",
"@nomiclabs/hardhat-ethers": "^2.1.0",
"@nomiclabs/hardhat-waffle": "^2.0.2",
Expand All @@ -51,7 +53,7 @@
"@ethereumjs/block": "^3.6.2",
"@ethereumjs/tx": "^3.4.0",
"@polygon-hermez/common": "2.6.4",
"@polygon-hermez/vm": "5.7.36",
"@polygon-hermez/vm": "6.0.11",
"ethereumjs-util": "^7.1.4",
"ethers": "^5.5.4",
"ffjavascript": "^0.2.55",
Expand Down
137 changes: 137 additions & 0 deletions src/block-keys-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/* eslint-disable max-len */
const { Scalar } = require('ffjavascript');

const constants = require('./constants');
const getPoseidon = require('./poseidon');
const { scalar2fea, stringToH4 } = require('./smt-utils');

/**
* Leaf type 7:
* hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0])
* key: H([blockHeaderParams[0:4], blockHeaderParams[4:8], blockHeaderParams[8:12], blockHeaderParams[12:16], blockHeaderParams[16:20], 0, SMT_KEY_BLOCK_HEADER_PARAM, 0], [hk0[0], hk0[1], hk0[2], hk0[3]])
* @param {Number} txIndex - current tx index
* @returns {Scalar} - key computed
*/
async function keyBlockHeaderParams(paramKey) {
const poseidon = await getPoseidon();
const { F } = poseidon;

const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_PARAM);
const blockHeaderParams = scalar2fea(F, Scalar.e(paramKey));

const key1 = [blockHeaderParams[0], blockHeaderParams[1], blockHeaderParams[2], blockHeaderParams[3], blockHeaderParams[4], blockHeaderParams[5], constant, F.zero];
const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES);

return poseidon(key1, key1Capacity);
}

/**
* Leaf type 8:
* hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0])
* key: H([txIndex[0:4], txIndex[4:8], txIndex[8:12], txIndex[12:16], txIndex[16:20], 0, SMT_KEY_BLOCK_HEADER_TRANSACTION_HASH, 0], [hk0[0], hk0[1], hk0[2], hk0[3]])
* @param {Number} txIndex - current tx index
* @returns {Scalar} - key computed
*/
async function keyTxHash(_txIndex) {
const poseidon = await getPoseidon();
const { F } = poseidon;

const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_TRANSACTION_HASH);
const txIndex = scalar2fea(F, Scalar.e(_txIndex));

const key1 = [txIndex[0], txIndex[1], txIndex[2], txIndex[3], txIndex[4], txIndex[5], constant, F.zero];
const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES);

return poseidon(key1, key1Capacity);
}

/**
* Leaf type 9:
* hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0])
* key: H([txIndex[0:4], txIndex[4:8], txIndex[8:12], txIndex[12:16], txIndex[16:20], 0, SMT_KEY_BLOCK_HEADER_STATUS, 0], [hk0[0], hk0[1], hk0[2], hk0[3]])
* @param {Number} txIndex - current tx index
* @returns {Scalar} - key computed
*/
async function keyTxStatus(_txIndex) {
const poseidon = await getPoseidon();
const { F } = poseidon;

const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_STATUS);
const txIndex = scalar2fea(F, Scalar.e(_txIndex));

const key1 = [txIndex[0], txIndex[1], txIndex[2], txIndex[3], txIndex[4], txIndex[5], constant, F.zero];
const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES);

return poseidon(key1, key1Capacity);
}

/**
* Leaf type 10:
* hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0])
* key: H([txIndex[0:4], txIndex[4:8], txIndex[8:12], txIndex[12:16], txIndex[16:20], 0, SMT_KEY_BLOCK_HEADER_CUMULATIVE_GAS_USED, 0], [hk0[0], hk0[1], hk0[2], hk0[3]])
* @param {Number} txIndex - current tx index
* @returns {Scalar} - key computed
*/
async function keyTxCumulativeGasUsed(_txIndex) {
const poseidon = await getPoseidon();
const { F } = poseidon;

const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_CUMULATIVE_GAS_USED);
const txIndex = scalar2fea(F, Scalar.e(_txIndex));

const key1 = [txIndex[0], txIndex[1], txIndex[2], txIndex[3], txIndex[4], txIndex[5], constant, F.zero];
const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES);

return poseidon(key1, key1Capacity);
}

/**
* Leaf type 11:
* hk0: H([logIndex[0:4], logIndex[4:8], logIndex[8:12], logIndex[12:16], logIndex[16:20], logIndex[20:24], logIndex[24:28], logIndex[28:32], [0, 0, 0, 0])
* key: H([logIndexKey[0:4], logIndexKey[4:8], logIndexKey[8:12], logIndexKey[12:16], logIndexKey[16:20], 0, SMT_KEY_BLOCK_HEADER_LOGS, 0], [hk0[0], hk0[1], hk0[2], hk0[3]])
* @param {Number} logIndex - current log index
* @returns {Scalar} - key computed
*/
async function keyTxLogs(_txIndex, _logIndex) {
const poseidon = await getPoseidon();
const { F } = poseidon;

const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_LOGS);
const txIndexKey = scalar2fea(F, Scalar.e(_txIndex));

const key1 = [txIndexKey[0], txIndexKey[1], txIndexKey[2], txIndexKey[3], txIndexKey[4], txIndexKey[5], constant, F.zero];
const logIndex = Scalar.e(_logIndex);
const logIndexArray = scalar2fea(F, logIndex);
const hk0 = poseidon(logIndexArray, [F.zero, F.zero, F.zero, F.zero]);

return poseidon(key1, hk0);
}

/**
* Leaf type 12:
* hk0: H([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0])
* key: H([txIndex[0:4], txIndex[4:8], txIndex[8:12], txIndex[12:16], txIndex[16:20], 0, SMT_KEY_BLOCK_HEADER_EFFECTIVE_PERCENTAGE, 0], [hk0[0], hk0[1], hk0[2], hk0[3]])
* @param {Number} txIndex - current tx index
* @returns {Scalar} - key computed
*/
async function keyTxEffectivePercentage(_txIndex) {
const poseidon = await getPoseidon();
const { F } = poseidon;

const constant = F.e(constants.SMT_KEY_BLOCK_HEADER_EFFECTIVE_PERCENTAGE);
const txIndex = scalar2fea(F, Scalar.e(_txIndex));

const key1 = [txIndex[0], txIndex[1], txIndex[2], txIndex[3], txIndex[4], txIndex[5], constant, F.zero];
const key1Capacity = stringToH4(constants.HASH_POSEIDON_ALL_ZEROES);

return poseidon(key1, key1Capacity);
}

module.exports = {
keyBlockHeaderParams,
keyTxLogs,
keyTxStatus,
keyTxHash,
keyTxCumulativeGasUsed,
keyTxEffectivePercentage,
};
189 changes: 189 additions & 0 deletions src/block-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-undef */
const { Scalar } = require('ffjavascript');

const constants = require('./constants');
const {
keyBlockHeaderParams, keyTxLogs, keyTxStatus, keyTxHash, keyTxCumulativeGasUsed, keyTxEffectivePercentage,
} = require('./block-keys-utils');
const { linearPoseidon } = require('./smt-utils');

/**
* Set a state of an ethereum address
* @param {Object} smt merkle tree structure
* @param {Array[Field]} root merkle tree root
* @param {String} oldBlockHash old block hash
* @param {String} coinbase block coinbase
* @param {Scalar|Number} blockNumber block number
* @param {Scalar|Number} gasLimit block gas limit
* @param {Scalar|Number} timestamp block timestamp
* @param {String} GER block's global exit root
* @param {String} blockHashL1 block hash L1
* @returns {Array[Field]} new state root
*/
async function initBlockHeader(smt, root, oldBlockHash, coinbase, blockNumber, gasLimit, timestamp, GER, blockHashL1) {
const keyBlockHash = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_BLOCK_HASH);
const keyCoinbase = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_COINBASE);
const keyBlockNumber = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_NUMBER);
const keyGasLimit = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_GAS_LIMIT);
const keyTimestamp = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_TIMESTAMP);
const keyGER = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_GER);
const keyBlockHashL1 = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_BLOCK_HASH_L1);

let result = await smt.set(root, keyBlockHash, Scalar.e(oldBlockHash));
result = await smt.set(result.newRoot, keyCoinbase, Scalar.e(coinbase));
result = await smt.set(result.newRoot, keyBlockNumber, Scalar.e(blockNumber));
result = await smt.set(result.newRoot, keyGasLimit, Scalar.e(gasLimit));
result = await smt.set(result.newRoot, keyTimestamp, Scalar.e(timestamp));
result = await smt.set(result.newRoot, keyGER, Scalar.e(GER));
result = await smt.set(result.newRoot, keyBlockHashL1, Scalar.e(blockHashL1));

return result.newRoot;
}

/**
* Set a state of an ethereum address
* @param {Object} smt merkle tree structure
* @param {Array[Field]} root merkle tree root
* @param {Scalar|Number} gasUsed block gasUsed
* @returns {Array[Field]} new state root
*/
async function setBlockGasUsed(smt, root, gasUsed) {
const keyGasUsed = await keyBlockHeaderParams(constants.INDEX_BLOCK_HEADER_PARAM_GAS_USED);
const result = await smt.set(root, keyGasUsed, Scalar.e(gasUsed));

return result.newRoot;
}

/**
* Set tx hash to smt
* @param {Object} smt merkle tree structure
* @param {Array[Field]} root merkle tree root
* @param {Number} txIndex transaction index
* @param {String} hash transaction status
* @returns {Array[Field]} new state root
*/
async function setL2TxHash(smt, root, txIndex, hash) {
const keyHash = await keyTxHash(txIndex);
const result = await smt.set(root, keyHash, Scalar.e(hash));

return result.newRoot;
}

/**
* Set tx status to smt
* @param {Object} smt merkle tree structure
* @param {Array[Field]} root merkle tree root
* @param {Number} txIndex transaction index
* @param {Number} status transaction status
* @returns {Array[Field]} new state root
*/
async function setTxStatus(smt, root, txIndex, status) {
const keyStatus = await keyTxStatus(txIndex);
const result = await smt.set(root, keyStatus, Scalar.e(status));

return result.newRoot;
}

/**
* Set cumulative gas used to smt
* @param {Object} smt merkle tree structure
* @param {Array[Field]} root merkle tree root
* @param {Number} txIndex transaction index
* @param {Number} cumulativeGasUsed transaction cumulativeGasUsed
* @returns {Array[Field]} new state root
*/
async function setCumulativeGasUsed(smt, root, txIndex, cumulativeGasUsed) {
const keyStatus = await keyTxCumulativeGasUsed(txIndex);
const result = await smt.set(root, keyStatus, Scalar.e(cumulativeGasUsed));

return result.newRoot;
}

/**
* Set effective percentage to smt
* @param {Object} smt merkle tree structure
* @param {Array[Field]} root merkle tree root
* @param {Number} txIndex transaction index
* @param {Number|String} effectivePercentage transaction effectivePercentage
* @returns {Array[Field]} new state root
*/
async function setEffectivePercentage(smt, root, txIndex, effectivePercentage) {
const keyStatus = await keyTxEffectivePercentage(txIndex);
const result = await smt.set(root, keyStatus, Scalar.e(effectivePercentage));

return result.newRoot;
}

/**
* Set logs to smt
* @param {Number} logIndex current tx index
* @param {Object} smt merkle tree structure
* @param {String} logHash linear poseidon hash of log value H(topics + data)
* @param {Array[Field]} root merkle tree root
* @returns {Array[Field]} new state root
*/
async function setTxLog(smt, root, txIndex, logIndex, logValue) {
// Get smt key from txIndex
const key = await keyTxLogs(txIndex, logIndex);
// Put log value in smt
const res = await smt.set(root, key, logValue);

return res.newRoot;
}

/**
* Fill block info tree with tx receipt
* @param {Object} smt sparse merkle tree structure
* @param {Array[Field]} currentBlockInfoRoot smt current root
* @param {Number} txIndex current transaction index
* @param {Object} logs array object of logs
* @param {Number} logIndex current log index in the block
* @param {Number} status value 0/1
* @param {String} l2TxHash l2 transaction hash in hex string
* @param {Number} cumulativeGasUsed cumulative gas used in the block
* @param {String} effectivePercentage effective percentage in hex string (1 byte)
* @returns new block info root
*/
async function fillReceiptTree(
smt,
currentBlockInfoRoot,
txIndex,
logs,
logIndex,
status,
l2TxHash,
cumulativeGasUsed,
effectivePercentage,
) {
// Set tx hash at smt
currentBlockInfoRoot = await setL2TxHash(smt, currentBlockInfoRoot, txIndex, l2TxHash);
// Set tx status at smt
currentBlockInfoRoot = await setTxStatus(smt, currentBlockInfoRoot, txIndex, status);
// Set tx gas used at smt
currentBlockInfoRoot = await setCumulativeGasUsed(smt, currentBlockInfoRoot, txIndex, cumulativeGasUsed);
for (const log of logs) {
// Loop logs
const bTopics = log[1];
const topics = bTopics.reduce((previousValue, currentValue) => previousValue + currentValue.toString('hex'), '');
// Encode log: linearPoseidon(logData + topics)
const encoded = await linearPoseidon(`0x${log[2].toString('hex')}${topics}`);
currentBlockInfoRoot = await setTxLog(smt, currentBlockInfoRoot, txIndex, logIndex, encoded);
logIndex += 1;
}
// Set tx effective percentage at smt
currentBlockInfoRoot = await setEffectivePercentage(smt, currentBlockInfoRoot, txIndex, effectivePercentage);

return currentBlockInfoRoot;
}

module.exports = {
initBlockHeader,
setBlockGasUsed,
setL2TxHash,
setTxStatus,
setCumulativeGasUsed,
setTxLog,
setEffectivePercentage,
fillReceiptTree,
};
Loading

0 comments on commit fefa98e

Please sign in to comment.