import { hexStrToBuf , bufToHexString , BigNumber , keccak256 , } from '@pigi/core-utils' ; import { newInMemoryDB , SparseMerkleTreeImpl } from '@pigi/core-db' ; import { utils } from 'ethers' ; interface BlockHeader { ethBlockNumber : number ; elementsMerkleRoot : string ; numElementsInBlock : number ; cumulativePrevElements : number ; } interface ElementInclusionProof { blockIndex : number ; blockHeader : BlockHeader ; indexInBlock : number ; siblings : string [ ] ; } export class DefaultRollupBlock { public ethBlockNumber : number ; public blockIndex : number ; public cumulativePrevElements : number ; public elements : string [ ] ; public elementsMerkleTree : SparseMerkleTreeImpl ; constructor ( ethBlockNumber , blockIndex , cumulativePrevElements , elements ) { this . ethBlockNumber = ethBlockNumber ; this . blockIndex = blockIndex ; this . cumulativePrevElements = cumulativePrevElements ; this . elements = elements ; } public async generateTree ( ) { const treeHeight = Math . ceil ( Math . log2 ( this . elements . length ) ) + 1 ; this . elementsMerkleTree = await SparseMerkleTreeImpl . create ( newInMemoryDB ( ) , undefined , treeHeight ) ; for ( let i = 0 ; i < this . elements . length ; i ++ ) { await this . elementsMerkleTree . update ( new BigNumber ( i , 10 ) , hexStrToBuf ( this . elements [ i ] ) ) ; } } public getPosition ( elementIndex ) { return this . cumulativePrevElements + elementIndex ; } public async getSiblings ( elementIndex ) { const blockInclusion = await this . elementsMerkleTree . getMerkleProof ( new BigNumber ( elementIndex ) , hexStrToBuf ( this . elements [ elementIndex ] ) ) ; const path = bufToHexString ( blockInclusion . key . toBuffer ( 'B' , 32 ) ) ; const siblings = blockInclusion . siblings . map ( ( sibBuf ) => bufToHexString ( sibBuf ) ) ; return siblings ; } public async hashBlockHeader ( ) { const bufferRoot = await this . elementsMerkleTree . getRootHash ( ) ; const abiCoder = new utils . AbiCoder ( ) ; const encoding = abiCoder . encode ( [ 'uint' , 'bytes32' , 'uint' , 'uint' ] , [ this . ethBlockNumber , bufToHexString ( bufferRoot ) , this . elements . length , this . cumulativePrevElements , ] ) ; return bufToHexString ( Buffer . from ( keccak256 ( encoding ) , 'hex' ) ) ; } public async getElementInclusionProof ( elementIndex ) { const bufferRoot = await this . elementsMerkleTree . getRootHash ( ) ; return { blockIndex : this . blockIndex , blockHeader : { ethBlockNumber : this . ethBlockNumber , elementsMerkleRoot : bufToHexString ( bufferRoot ) , numElementsInBlock : this . elements . length , cumulativePrevElements : this . cumulativePrevElements , } , indexInBlock : elementIndex , siblings : await this . getSiblings ( elementIndex ) , } ; } }