-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #134 from 0xPolygonHermez/develop
Develop
- Loading branch information
Showing
43 changed files
with
5,904 additions
and
681 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ on: | |
branches: | ||
- main | ||
- develop | ||
- feature/fork-etrog | ||
|
||
jobs: | ||
build: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; |
Oops, something went wrong.