classic-ui-dev/scripts/updateTree.js

150 lines
4.2 KiB
JavaScript

import 'dotenv/config'
import fs from 'fs'
import BloomFilter from 'bloomfilter.js'
import { MerkleTree } from 'fixed-merkle-tree'
import { buildMimcSponge } from 'circomlibjs'
import networkConfig from '../networkConfig'
import { loadCachedEvents, save } from './helpers'
const TREES_FOLDER = 'static/trees'
const TREES_PATH = './static/trees/'
const EVENTS_PATH = './static/events/'
const EVENTS = ['deposit']
const enabledChains = ['1', '56', '100', '137' ]
let mimcHash
const trees = {
PARTS_COUNT: 4,
LEVELS: 20 // const from contract
}
function getName({ path, type, instance, format = '.json', currName = 'eth' }) {
return `${path}${type.toLowerCase()}s_${currName}_${instance}${format}`
}
function createTreeZip(netId) {
try {
const { tokens, nativeCurrency, currencyName } = networkConfig[`netId${netId}`]
const CONTRACTS = tokens[nativeCurrency].instanceAddress
for (const type of EVENTS) {
for (const [instance] of Object.entries(CONTRACTS)) {
const baseFilename = getName({
type,
instance,
format: '',
path: TREES_PATH,
currName: currencyName.toLowerCase()
})
const treesFolder = fs.readdirSync(TREES_FOLDER)
treesFolder.forEach((fileName) => {
fileName = `${TREES_PATH}${fileName}`
const isInstanceFile = !fileName.includes('.gz') && fileName.includes(baseFilename)
if (isInstanceFile) {
save(fileName)
}
})
}
}
} catch {}
}
async function createTree(netId) {
try {
const config = networkConfig[`netId${netId}`]
const { nativeCurrency, currencyName, deployedBlock } = config
const CONTRACTS = config.tokens[nativeCurrency].instanceAddress
for (const type of EVENTS) {
for (const [instance] of Object.entries(CONTRACTS)) {
const filePath = getName({
type,
instance,
format: '',
path: TREES_PATH,
currName: currencyName.toLowerCase()
})
console.log('createTree', { type, instance })
const { events } = await loadCachedEvents({
name: `${type}s_${nativeCurrency}_${instance}.json`,
directory: EVENTS_PATH,
deployedBlock
})
console.log('events', events.length)
const bloom = new BloomFilter(events.length) // to reduce the number of false positives
const eventsData = events.reduce(
(acc, { leafIndex, commitment, ...rest }, i) => {
if (leafIndex !== i) {
throw new Error(`leafIndex (${leafIndex}) !== i (${i})`)
}
const leave = commitment.toString()
acc.leaves.push(leave)
acc.metadata[leave] = { ...rest, leafIndex }
return acc
},
{ leaves: [], metadata: {} }
)
console.log('leaves', eventsData.leaves.length)
const tree = new MerkleTree(trees.LEVELS, eventsData.leaves, {
zeroElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
hashFunction: mimcHash
})
const slices = tree.getTreeSlices(trees.PARTS_COUNT) // [edge(PARTS_COUNT)]
slices.forEach((slice, index) => {
slice.metadata = slice.elements.reduce((acc, curr) => {
if (index < trees.PARTS_COUNT - 1) {
bloom.add(curr)
}
acc.push(eventsData.metadata[curr])
return acc
}, [])
const sliceJson = JSON.stringify(slice, null, 2) + '\n'
fs.writeFileSync(`${filePath}_slice${index + 1}.json`, sliceJson)
})
const bloomCache = bloom.serialize()
fs.writeFileSync(`${filePath}_bloom.json`, bloomCache)
}
}
} catch (e) {
console.error(e.message)
}
}
async function initMimc() {
const mimcSponge = await buildMimcSponge()
mimcHash = (left, right) => mimcSponge.F.toString(mimcSponge.multiHash([BigInt(left), BigInt(right)]))
}
async function main() {
const [, , , chain] = process.argv
if (!enabledChains.includes(chain)) {
throw new Error(`Supported chain ids ${enabledChains.join(', ')}`)
}
await initMimc()
await createTree(chain)
await createTreeZip(chain)
}
main()