optimize sloads

This commit is contained in:
poma 2021-03-11 22:51:09 +03:00
parent 127a61e21f
commit 3ad634594e
No known key found for this signature in database
GPG Key ID: BA20CB01FE165657
3 changed files with 33 additions and 41 deletions

View File

@ -20,36 +20,35 @@ contract MerkleTreeWithHistory {
uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 public constant ZERO_VALUE = 21663839004416932945382355908790599225266501822907911457504978515578255421292; // = keccak256("tornado") % FIELD_SIZE uint256 public constant ZERO_VALUE = 21663839004416932945382355908790599225266501822907911457504978515578255421292; // = keccak256("tornado") % FIELD_SIZE
uint32 public levels; IHasher public immutable hasher;
uint32 public immutable levels;
// the following variables are made public for easier testing and debugging and // the following variables are made public for easier testing and debugging and
// are not supposed to be accessed in regular code // are not supposed to be accessed in regular code
bytes32[] public filledSubtrees;
bytes32[] public zeros; // filledSubtrees, zeros, and roots could be bytes32[size], but using mappings makes it cheaper because
// it removes index range check on every interaction
mapping(uint256 => bytes32) public filledSubtrees;
mapping(uint256 => bytes32) public zeros;
mapping(uint256 => bytes32) public roots;
uint32 public constant ROOT_HISTORY_SIZE = 30;
uint32 public currentRootIndex = 0; uint32 public currentRootIndex = 0;
uint32 public nextIndex = 0; uint32 public nextIndex = 0;
uint32 public constant ROOT_HISTORY_SIZE = 100;
bytes32[ROOT_HISTORY_SIZE] public roots;
IHasher public immutable hasher;
constructor(uint32 _treeLevels, IHasher _hasher) public {
require(_treeLevels > 0, "_treeLevels should be greater than zero");
require(_treeLevels < 32, "_treeLevels should be less than 32");
levels = _treeLevels;
constructor(uint32 _levels, IHasher _hasher) public {
require(_levels > 0, "_levels should be greater than zero");
require(_levels < 32, "_levels should be less than 32");
levels = _levels;
hasher = _hasher; hasher = _hasher;
bytes32 currentZero = bytes32(ZERO_VALUE); bytes32 currentZero = bytes32(ZERO_VALUE);
zeros.push(currentZero); for (uint32 i = 0; i < _levels; i++) {
filledSubtrees.push(currentZero); zeros[i] = currentZero;
filledSubtrees[i] = currentZero;
for (uint32 i = 1; i < levels; i++) {
currentZero = hashLeftRight(_hasher, currentZero, currentZero); currentZero = hashLeftRight(_hasher, currentZero, currentZero);
zeros.push(currentZero);
filledSubtrees.push(currentZero);
} }
roots[0] = hashLeftRight(_hasher, currentZero, currentZero); roots[0] = currentZero;
} }
/** /**
@ -71,9 +70,9 @@ contract MerkleTreeWithHistory {
} }
function _insert(bytes32 _leaf) internal returns (uint32 index) { function _insert(bytes32 _leaf) internal returns (uint32 index) {
uint32 currentIndex = nextIndex; uint32 _nextIndex = nextIndex;
require(currentIndex != uint32(2)**levels, "Merkle tree is full. No more leafs can be added"); require(_nextIndex != uint32(2)**levels, "Merkle tree is full. No more leaves can be added");
nextIndex += 1; uint32 currentIndex = _nextIndex;
bytes32 currentLevelHash = _leaf; bytes32 currentLevelHash = _leaf;
bytes32 left; bytes32 left;
bytes32 right; bytes32 right;
@ -82,21 +81,20 @@ contract MerkleTreeWithHistory {
if (currentIndex % 2 == 0) { if (currentIndex % 2 == 0) {
left = currentLevelHash; left = currentLevelHash;
right = zeros[i]; right = zeros[i];
filledSubtrees[i] = currentLevelHash; filledSubtrees[i] = currentLevelHash;
} else { } else {
left = filledSubtrees[i]; left = filledSubtrees[i];
right = currentLevelHash; right = currentLevelHash;
} }
currentLevelHash = hashLeftRight(hasher, left, right); currentLevelHash = hashLeftRight(hasher, left, right);
currentIndex /= 2; currentIndex /= 2;
} }
currentRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE; uint32 newRootIndex = (currentRootIndex + 1) % ROOT_HISTORY_SIZE;
roots[currentRootIndex] = currentLevelHash; currentRootIndex = newRootIndex;
return nextIndex - 1; roots[newRootIndex] = currentLevelHash;
nextIndex = _nextIndex + 1;
return _nextIndex;
} }
/** /**
@ -106,7 +104,8 @@ contract MerkleTreeWithHistory {
if (_root == 0) { if (_root == 0) {
return false; return false;
} }
uint32 i = currentRootIndex; uint32 _currentRootIndex = currentRootIndex;
uint32 i = _currentRootIndex;
do { do {
if (_root == roots[i]) { if (_root == roots[i]) {
return true; return true;
@ -115,7 +114,7 @@ contract MerkleTreeWithHistory {
i = ROOT_HISTORY_SIZE; i = ROOT_HISTORY_SIZE;
} }
i--; i--;
} while (i != currentRootIndex); } while (i != _currentRootIndex);
return false; return false;
} }

View File

@ -20,19 +20,12 @@ interface IVerifier {
} }
abstract contract Tornado is MerkleTreeWithHistory, ReentrancyGuard { abstract contract Tornado is MerkleTreeWithHistory, ReentrancyGuard {
uint256 public denomination; IVerifier public immutable verifier;
uint256 public immutable denomination;
mapping(bytes32 => bool) public nullifierHashes; mapping(bytes32 => bool) public nullifierHashes;
// we store all commitments just to prevent accidental deposits with the same commitment // we store all commitments just to prevent accidental deposits with the same commitment
mapping(bytes32 => bool) public commitments; mapping(bytes32 => bool) public commitments;
IVerifier public immutable verifier;
// operator can update snark verification key
// after the final trusted setup ceremony operator rights are supposed to be transferred to zero address
address public operator;
modifier onlyOperator {
require(msg.sender == operator, "Only operator can call this function.");
_;
}
event Deposit(bytes32 indexed commitment, uint32 leafIndex, uint256 timestamp); event Deposit(bytes32 indexed commitment, uint32 leafIndex, uint256 timestamp);
event Withdrawal(address to, bytes32 nullifierHash, address indexed relayer, uint256 fee); event Withdrawal(address to, bytes32 nullifierHash, address indexed relayer, uint256 fee);

View File

@ -159,10 +159,10 @@ contract('MerkleTreeWithHistory', (accounts) => {
} }
let error = await merkleTreeWithHistory.insert(toFixedHex(1337)).should.be.rejected let error = await merkleTreeWithHistory.insert(toFixedHex(1337)).should.be.rejected
error.reason.should.be.equal('Merkle tree is full. No more leafs can be added') error.reason.should.be.equal('Merkle tree is full. No more leaves can be added')
error = await merkleTreeWithHistory.insert(toFixedHex(1)).should.be.rejected error = await merkleTreeWithHistory.insert(toFixedHex(1)).should.be.rejected
error.reason.should.be.equal('Merkle tree is full. No more leafs can be added') error.reason.should.be.equal('Merkle tree is full. No more leaves can be added')
}) })
it.skip('hasher gas', async () => { it.skip('hasher gas', async () => {