tornado-trees/test/tornadoTrees.test.js

228 lines
8.3 KiB
JavaScript
Raw Normal View History

2021-02-02 12:38:11 +01:00
/* global ethers */
2021-02-02 12:27:58 +01:00
const { expect } = require('chai')
2021-02-01 14:40:32 +01:00
const { toFixedHex, poseidonHash2, randomBN } = require('../src/utils')
const MerkleTree = require('fixed-merkle-tree')
2021-02-02 12:20:59 +01:00
const controller = require('../src/controller')
2021-02-01 14:40:32 +01:00
async function register(note, tornadoTrees, from) {
2021-02-02 12:27:58 +01:00
await tornadoTrees
.connect(from)
.register(
note.instance,
toFixedHex(note.commitment),
toFixedHex(note.nullifierHash),
note.depositBlock,
note.withdrawalBlock,
)
2021-02-01 14:40:32 +01:00
}
const levels = 20
const CHUNK_TREE_HEIGHT = 2
2021-02-02 12:20:59 +01:00
const instances = [
'0x1111000000000000000000000000000000001111',
'0x2222000000000000000000000000000000002222',
'0x3333000000000000000000000000000000003333',
'0x4444000000000000000000000000000000004444',
]
2021-02-01 14:40:32 +01:00
2021-02-02 12:20:59 +01:00
const blocks = ['0xaaaaaaaa', '0xbbbbbbbb', '0xcccccccc', '0xdddddddd']
2021-02-01 14:40:32 +01:00
2021-02-02 12:27:58 +01:00
describe('TornadoTrees', function () {
2021-02-02 12:20:59 +01:00
let tree
let operator
let tornadoProxy
let verifier
let tornadoTrees
2021-02-04 15:17:21 +01:00
let tornadoTreesV1
2021-02-02 12:20:59 +01:00
let notes
2021-02-02 20:46:51 +01:00
const depositEvents = []
const withdrawalEvents = []
2021-02-02 12:20:59 +01:00
2021-02-02 12:27:58 +01:00
beforeEach(async function () {
2021-02-02 12:20:59 +01:00
tree = new MerkleTree(levels, [], { hashFunction: poseidonHash2 })
;[operator, tornadoProxy] = await ethers.getSigners()
2021-02-02 12:27:58 +01:00
const BatchTreeUpdateVerifier = await ethers.getContractFactory('BatchTreeUpdateVerifier')
2021-02-02 12:20:59 +01:00
verifier = await BatchTreeUpdateVerifier.deploy()
2021-02-04 15:17:21 +01:00
const TornadoTreesV1 = await ethers.getContractFactory('TornadoTreesV1Mock')
tornadoTreesV1 = await TornadoTreesV1.deploy(0, 0, tree.root(), tree.root())
2021-02-01 14:40:32 +01:00
2021-02-02 12:20:59 +01:00
notes = []
2021-02-01 14:40:32 +01:00
for (let i = 0; i < 2 ** CHUNK_TREE_HEIGHT; i++) {
notes[i] = {
instance: instances[i % instances.length],
depositBlock: blocks[i % blocks.length],
withdrawalBlock: 2 + i + i * 4 * 60 * 24,
commitment: randomBN(),
nullifierHash: randomBN(),
}
2021-02-04 15:17:21 +01:00
await register(notes[i], tornadoTreesV1, tornadoProxy)
2021-02-02 20:46:51 +01:00
depositEvents[i] = {
hash: toFixedHex(notes[i].commitment),
instance: toFixedHex(notes[i].instance, 20),
block: toFixedHex(notes[i].depositBlock, 4),
}
withdrawalEvents[i] = {
hash: toFixedHex(notes[i].nullifierHash),
instance: toFixedHex(notes[i].instance, 20),
block: toFixedHex(notes[i].withdrawalBlock, 4),
}
2021-02-01 14:40:32 +01:00
}
2021-02-04 15:17:21 +01:00
const TornadoTrees = await ethers.getContractFactory('TornadoTreesMock')
tornadoTrees = await TornadoTrees.deploy(
operator.address,
tornadoProxy.address,
tornadoTreesV1.address,
verifier.address,
)
2021-02-01 14:40:32 +01:00
})
2021-02-02 20:46:51 +01:00
describe('#updateDepositTree', () => {
it('should check hash', async () => {
const { args } = controller.batchTreeUpdate(tree, depositEvents)
const solHash = await tornadoTrees.updateDepositTreeMock(...args.slice(1))
expect(solHash).to.be.equal(args[0])
})
2021-02-04 18:14:06 +01:00
it('should prove snark', async () => {
2021-02-02 20:46:51 +01:00
const { input, args } = controller.batchTreeUpdate(tree, depositEvents)
const proof = await controller.prove(input, './artifacts/circuits/BatchTreeUpdate')
await tornadoTrees.updateDepositTree(proof, ...args)
const updatedRoot = await tornadoTrees.depositRoot()
expect(updatedRoot).to.be.equal(tree.root())
})
it('should work for non-empty tree', async () => {
let { input, args } = controller.batchTreeUpdate(tree, depositEvents)
let proof = await controller.prove(input, './artifacts/circuits/BatchTreeUpdate')
await tornadoTrees.updateDepositTree(proof, ...args)
let updatedRoot = await tornadoTrees.depositRoot()
expect(updatedRoot).to.be.equal(tree.root())
//
for (let i = 0; i < notes.length; i++) {
await register(notes[i], tornadoTrees, tornadoProxy)
}
;({ input, args } = controller.batchTreeUpdate(tree, depositEvents))
proof = await controller.prove(input, './artifacts/circuits/BatchTreeUpdate')
await tornadoTrees.updateDepositTree(proof, ...args)
updatedRoot = await tornadoTrees.depositRoot()
expect(updatedRoot).to.be.equal(tree.root())
})
2021-02-05 18:38:52 +01:00
it('should work with events from contracts', async () => {
let { input, args } = controller.batchTreeUpdate(tree, depositEvents)
let proof = await controller.prove(input, './artifacts/circuits/BatchTreeUpdate')
await tornadoTrees.updateDepositTree(proof, ...args)
let updatedRoot = await tornadoTrees.depositRoot()
expect(updatedRoot).to.be.equal(tree.root())
const filter = tornadoTrees.filters.DepositData()
const migratedEvents = await tornadoTrees.queryFilter(filter)
2021-02-05 18:41:20 +01:00
migratedEvents.forEach((e, i) => {
expect(e.args.index).to.be.equal(i)
})
2021-02-05 18:38:52 +01:00
//
for (let i = 0; i < notes.length; i++) {
await register(notes[i], tornadoTrees, tornadoProxy)
}
let registeredEvents = await tornadoTrees.queryFilter(filter)
registeredEvents = registeredEvents.map((e) => ({
hash: toFixedHex(e.args.hash),
instance: toFixedHex(e.args.instance, 20),
block: toFixedHex(e.args.block, 4),
}))
;({ input, args } = controller.batchTreeUpdate(tree, registeredEvents))
proof = await controller.prove(input, './artifacts/circuits/BatchTreeUpdate')
await tornadoTrees.updateDepositTree(proof, ...args)
updatedRoot = await tornadoTrees.depositRoot()
expect(updatedRoot).to.be.equal(tree.root())
})
2021-02-02 20:46:51 +01:00
it('should reject for partially filled tree')
it('should reject for outdated deposit root')
it('should reject for incorrect insert index')
it('should reject for overflows of newRoot')
it('should reject for invalid sha256 args')
2021-02-01 14:40:32 +01:00
})
2021-02-02 20:46:51 +01:00
describe('#getRegisteredDeposits', () => {
it('should work', async () => {
2021-02-05 18:19:36 +01:00
for (let i = 0; i < 2 ** CHUNK_TREE_HEIGHT; i++) {
notes[i] = {
instance: instances[i % instances.length],
depositBlock: blocks[i % blocks.length],
withdrawalBlock: 2 + i + i * 4 * 60 * 24,
commitment: randomBN(),
nullifierHash: randomBN(),
}
await register(notes[i], tornadoTrees, tornadoProxy)
}
2021-02-02 20:46:51 +01:00
const abi = new ethers.utils.AbiCoder()
2021-02-04 18:47:47 +01:00
const count = await tornadoTrees.depositsLength()
const _deposits = await tornadoTrees.getRegisteredDeposits()
2021-02-05 18:19:36 +01:00
expect(count).to.be.equal(notes.length * 2)
2021-02-02 20:46:51 +01:00
_deposits.forEach((hash, i) => {
2021-02-05 18:19:36 +01:00
if (i < notes.length) {
expect(hash).to.be.equal('0x0000000000000000000000000000000000000000000000000000000000000000')
} else {
const index = i - notes.length
const encodedData = abi.encode(
['address', 'bytes32', 'uint256'],
[notes[index].instance, toFixedHex(notes[index].commitment), notes[index].depositBlock],
)
const leaf = ethers.utils.keccak256(encodedData)
expect(leaf).to.be.equal(hash)
}
2021-02-02 20:46:51 +01:00
})
// res.length.should.be.equal(1)
// res[0].should.be.true
// await tornadoTrees.updateRoots([note1DepositLeaf], [])
// res = await tornadoTrees.getRegisteredDeposits()
// res.length.should.be.equal(0)
// await registerDeposit(note2, tornadoTrees)
// res = await tornadoTrees.getRegisteredDeposits()
// // res[0].should.be.true
})
2021-02-01 14:40:32 +01:00
})
2021-02-02 12:20:59 +01:00
2021-02-02 20:46:51 +01:00
describe('#getRegisteredWithdrawals', () => {
it('should work', async () => {
2021-02-05 18:19:36 +01:00
for (let i = 0; i < 2 ** CHUNK_TREE_HEIGHT; i++) {
notes[i] = {
instance: instances[i % instances.length],
depositBlock: blocks[i % blocks.length],
withdrawalBlock: 2 + i + i * 4 * 60 * 24,
commitment: randomBN(),
nullifierHash: randomBN(),
}
await register(notes[i], tornadoTrees, tornadoProxy)
}
2021-02-02 20:46:51 +01:00
const abi = new ethers.utils.AbiCoder()
2021-02-04 18:47:47 +01:00
const count = await tornadoTrees.withdrawalsLength()
const _withdrawals = await tornadoTrees.getRegisteredWithdrawals()
2021-02-05 18:19:36 +01:00
expect(count).to.be.equal(notes.length * 2)
2021-02-02 20:46:51 +01:00
_withdrawals.forEach((hash, i) => {
2021-02-05 18:19:36 +01:00
if (i < notes.length) {
expect(hash).to.be.equal('0x0000000000000000000000000000000000000000000000000000000000000000')
} else {
const index = i - notes.length
const encodedData = abi.encode(
['address', 'bytes32', 'uint256'],
[notes[index].instance, toFixedHex(notes[index].nullifierHash), notes[index].withdrawalBlock],
)
const leaf = ethers.utils.keccak256(encodedData)
expect(leaf).to.be.equal(hash)
}
2021-02-02 20:46:51 +01:00
})
})
})
2021-02-01 14:40:32 +01:00
})