This commit is contained in:
Alexey 2021-02-03 20:59:35 +03:00
parent 5fe2429b89
commit 3ba0f8e4e3
4 changed files with 123 additions and 34 deletions

@ -4,17 +4,17 @@ pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "torn-token/contracts/ENS.sol"; import "torn-token/contracts/ENS.sol";
import "./interfaces/ITornadoTrees.sol"; import "./interfaces/ITornadoTreesV1.sol";
import "./interfaces/IVerifier.sol"; import "./interfaces/IVerifier.sol";
contract TornadoTrees is ITornadoTrees, EnsResolve { contract TornadoTrees is EnsResolve {
address public immutable governance; address public immutable governance;
bytes32 public depositRoot; bytes32 public depositRoot;
bytes32 public previousDepositRoot; bytes32 public previousDepositRoot;
bytes32 public withdrawalRoot; bytes32 public withdrawalRoot;
bytes32 public previousWithdrawalRoot; bytes32 public previousWithdrawalRoot;
address public tornadoProxy; address public tornadoProxy;
IVerifier public immutable treeUpdateVerifier; IVerifier public treeUpdateVerifier;
// make sure CHUNK_TREE_HEIGHT has the same value in BatchTreeUpdate.circom // make sure CHUNK_TREE_HEIGHT has the same value in BatchTreeUpdate.circom
uint256 public constant CHUNK_TREE_HEIGHT = 2; uint256 public constant CHUNK_TREE_HEIGHT = 2;
@ -29,6 +29,8 @@ contract TornadoTrees is ITornadoTrees, EnsResolve {
bytes32[] public withdrawals; bytes32[] public withdrawals;
uint256 public lastProcessedWithdrawalLeaf; uint256 public lastProcessedWithdrawalLeaf;
bool public initialized;
event DepositData(address instance, bytes32 indexed hash, uint256 block, uint256 index); event DepositData(address instance, bytes32 indexed hash, uint256 block, uint256 index);
event WithdrawalData(address instance, bytes32 indexed hash, uint256 block, uint256 index); event WithdrawalData(address instance, bytes32 indexed hash, uint256 block, uint256 index);
@ -55,30 +57,100 @@ contract TornadoTrees is ITornadoTrees, EnsResolve {
_; _;
} }
constructor( modifier onlyInitialized() {
bytes32 _governance, require(initialized, "The contract is in the process of the migration");
bytes32 _tornadoProxy, _;
bytes32 _treeUpdateVerifier,
bytes32 _depositRoot,
bytes32 _withdrawalRoot
) public {
governance = resolve(_governance);
tornadoProxy = resolve(_tornadoProxy);
treeUpdateVerifier = IVerifier(resolve(_treeUpdateVerifier));
depositRoot = _depositRoot;
withdrawalRoot = _withdrawalRoot;
} }
function registerDeposit(address _instance, bytes32 _commitment) external override onlyTornadoProxy { constructor(
address _governance,
address _tornadoProxy,
ITornadoTreesV1 _tornadoTreesV1,
IVerifier _treeUpdateVerifier
) public {
governance = _governance;
tornadoProxy = _tornadoProxy;
treeUpdateVerifier = _treeUpdateVerifier;
depositRoot = _tornadoTreesV1.depositRoot();
withdrawalRoot = _tornadoTreesV1.withdrawalRoot();
uint256 _lastProcessedDepositLeaf = _tornadoTreesV1.lastProcessedDepositLeaf();
require(_lastProcessedDepositLeaf % CHUNK_SIZE == 0, "Incorrect TornadoTrees contract state");
lastProcessedDepositLeaf = _lastProcessedDepositLeaf;
uint256 _lastProcessedWithdrawalLeaf = _tornadoTreesV1.lastProcessedWithdrawalLeaf();
require(_lastProcessedWithdrawalLeaf % CHUNK_SIZE == 0, "Incorrect TornadoTrees contract state");
lastProcessedWithdrawalLeaf = _lastProcessedWithdrawalLeaf;
uint256 i = _lastProcessedDepositLeaf + 1;
// todo deposits.length = _tornadoTreesV1.deposits.length
while (true) {
bytes32 deposit = _tornadoTreesV1.deposits(i);
if (deposit == bytes32(0)) {
break;
}
i++;
deposits.push(deposit);
}
i = _lastProcessedWithdrawalLeaf + 1;
while (true) {
bytes32 withdrawal = _tornadoTreesV1.withdrawals(i);
if (withdrawal == bytes32(0)) {
break;
}
i++;
withdrawals.push(withdrawal);
}
}
function registerDeposit(address _instance, bytes32 _commitment) external onlyTornadoProxy onlyInitialized {
deposits.push(keccak256(abi.encode(_instance, _commitment, blockNumber()))); deposits.push(keccak256(abi.encode(_instance, _commitment, blockNumber())));
emit DepositData(_instance, _commitment, blockNumber(), deposits.length - 1); emit DepositData(_instance, _commitment, blockNumber(), deposits.length - 1);
} }
function registerWithdrawal(address _instance, bytes32 _nullifierHash) external override onlyTornadoProxy { function registerWithdrawal(address _instance, bytes32 _nullifierHash) external onlyTornadoProxy onlyInitialized {
withdrawals.push(keccak256(abi.encode(_instance, _nullifierHash, blockNumber()))); withdrawals.push(keccak256(abi.encode(_instance, _nullifierHash, blockNumber())));
emit WithdrawalData(_instance, _nullifierHash, blockNumber(), withdrawals.length - 1); emit WithdrawalData(_instance, _nullifierHash, blockNumber(), withdrawals.length - 1);
} }
function migrate(TreeLeaf[] calldata _depositEvents, TreeLeaf[] calldata _withdrawalEvents) external {
require(!initialized, "Already migrated");
uint256 _lastProcessedDepositLeaf = lastProcessedDepositLeaf;
uint256 _depositLength = deposits.length;
for (uint256 i = 0; i < _depositLength - _lastProcessedDepositLeaf; i++) {
bytes32 leafHash = keccak256(abi.encode(_depositEvents[i].instance, _depositEvents[i].hash, _depositEvents[i].block));
require(leafHash == deposits[_lastProcessedDepositLeaf + i], "Incorrect deposit");
emit DepositData(
_depositEvents[i].instance,
_depositEvents[i].hash,
_depositEvents[i].block,
_lastProcessedDepositLeaf + i
);
}
uint256 _withdrawalLength = withdrawals.length;
uint256 _lastProcessedWithdrawalLeaf = lastProcessedWithdrawalLeaf;
for (uint256 i = 0; i < _withdrawalLength - _lastProcessedWithdrawalLeaf; i++) {
bytes32 leafHash = keccak256(
abi.encode(_withdrawalEvents[i].instance, _withdrawalEvents[i].hash, _withdrawalEvents[i].block)
);
require(leafHash == withdrawals[_lastProcessedWithdrawalLeaf + i], "Incorrect deposit");
emit DepositData(
_withdrawalEvents[i].instance,
_withdrawalEvents[i].hash,
_withdrawalEvents[i].block,
_lastProcessedWithdrawalLeaf + i
);
}
initialized = true;
}
// если чтото загрузит руты на старый контракт во время миграции то пизда
// todo !!! ensure that during migration the tree is filled evenly // todo !!! ensure that during migration the tree is filled evenly
function updateDepositTree( function updateDepositTree(
bytes calldata _proof, bytes calldata _proof,
@ -87,7 +159,7 @@ contract TornadoTrees is ITornadoTrees, EnsResolve {
bytes32 _newRoot, bytes32 _newRoot,
uint32 _pathIndices, uint32 _pathIndices,
TreeLeaf[CHUNK_SIZE] calldata _events TreeLeaf[CHUNK_SIZE] calldata _events
) public { ) public onlyInitialized {
uint256 offset = lastProcessedDepositLeaf; uint256 offset = lastProcessedDepositLeaf;
require(_newRoot != previousDepositRoot, "Outdated deposit root"); require(_newRoot != previousDepositRoot, "Outdated deposit root");
require(_currentRoot == depositRoot, "Proposed deposit root is invalid"); require(_currentRoot == depositRoot, "Proposed deposit root is invalid");
@ -127,7 +199,7 @@ contract TornadoTrees is ITornadoTrees, EnsResolve {
bytes32 _newRoot, bytes32 _newRoot,
uint256 _pathIndices, uint256 _pathIndices,
TreeLeaf[CHUNK_SIZE] calldata _events TreeLeaf[CHUNK_SIZE] calldata _events
) public { ) public onlyInitialized {
uint256 offset = lastProcessedWithdrawalLeaf; uint256 offset = lastProcessedWithdrawalLeaf;
require(_newRoot != previousWithdrawalRoot, "Outdated withdrawal root"); require(_newRoot != previousWithdrawalRoot, "Outdated withdrawal root");
require(_currentRoot == withdrawalRoot, "Proposed withdrawal root is invalid"); require(_currentRoot == withdrawalRoot, "Proposed withdrawal root is invalid");
@ -187,6 +259,10 @@ contract TornadoTrees is ITornadoTrees, EnsResolve {
tornadoProxy = _tornadoProxy; tornadoProxy = _tornadoProxy;
} }
function setVerifierContract(IVerifier _treeUpdateVerifier) external onlyGovernance {
treeUpdateVerifier = _treeUpdateVerifier;
}
function blockNumber() public view virtual returns (uint256) { function blockNumber() public view virtual returns (uint256) {
return block.number; return block.number;
} }

@ -1,9 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
interface ITornadoTrees {
function registerDeposit(address instance, bytes32 commitment) external;
function registerWithdrawal(address instance, bytes32 nullifier) external;
}

@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
interface ITornadoTreesV1 {
function lastProcessedDepositLeaf() external view returns (uint256);
function lastProcessedWithdrawalLeaf() external view returns (uint256);
function depositRoot() external view returns (bytes32);
function withdrawalRoot() external view returns (bytes32);
function deposits(uint256 i) external view returns (bytes32);
function withdrawals(uint256 i) external view returns (bytes32);
function registerDeposit(address instance, bytes32 commitment) external;
function registerWithdrawal(address instance, bytes32 nullifier) external;
}

@ -4,17 +4,18 @@ pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
import "../TornadoTrees.sol"; import "../TornadoTrees.sol";
import "../interfaces/ITornadoTreesV1.sol";
import "../interfaces/IVerifier.sol";
contract TornadoTreesMock is TornadoTrees { contract TornadoTreesMock is TornadoTrees {
uint256 public currentBlock; uint256 public currentBlock;
constructor( constructor(
bytes32 _governance, address _governance,
bytes32 _tornadoProxy, address _tornadoProxy,
bytes32 _treeUpdateVerifier, ITornadoTreesV1 _tornadoTreesV1,
bytes32 _depositRoot, IVerifier _treeUpdateVerifier
bytes32 _withdrawalRoot ) public TornadoTrees(_governance, _tornadoProxy, _tornadoTreesV1, _treeUpdateVerifier) {}
) public TornadoTrees(_governance, _tornadoProxy, _treeUpdateVerifier, _depositRoot, _withdrawalRoot) {}
function resolve(bytes32 _addr) public view override returns (address) { function resolve(bytes32 _addr) public view override returns (address) {
return address(uint160(uint256(_addr) >> (12 * 8))); return address(uint160(uint256(_addr) >> (12 * 8)));