Skip to content

Commit

Permalink
Merge pull request #906 from EYBlockchain/RogerTaule/variable-length-…
Browse files Browse the repository at this point in the history
…merkle-tree-transactions

Variable height merkle trees for transactions
  • Loading branch information
daveroga authored Sep 11, 2022
2 parents e642e5c + 4476d9d commit ea83d6e
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 35 deletions.
3 changes: 1 addition & 2 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ module.exports = {
EXCLUDE_DIRS: 'common',
MAX_QUEUE: 5,
TIMBER_HEIGHT: 32,
TXHASH_TREE_HEIGHT: 5,
CONFIRMATION_POLL_TIME: 1000,
CONFIRMATIONS: 12,
DEFAULT_ACCOUNT_NUM: 10,
Expand Down Expand Up @@ -84,7 +83,7 @@ module.exports = {
CURVE: process.env.CURVE || 'bn128',

TRANSACTIONS_PER_BLOCK: Number(process.env.TRANSACTIONS_PER_BLOCK) || 2,
RETRIES: Number(process.env.AUTOSTART_RETRIES) || 50,
RETRIES: Number(process.env.AUTOSTART_RETRIES) || 150,
USE_STUBS: process.env.USE_STUBS === 'true',
VK_IDS: { deposit: 0, transfer: 1, withdraw: 2 }, // used as an enum to mirror the Shield contracts enum for vk types. The keys of this object must correspond to a 'folderpath' (the .zok file without the '.zok' bit)
BN128_GROUP_ORDER: 21888242871839275222246405745257275088548364400416034343698204186575808495617n,
Expand Down
21 changes: 11 additions & 10 deletions nightfall-client/src/event-handlers/block-proposed.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from '../services/database.mjs';
import { decryptCommitment } from '../services/commitment-sync.mjs';

const { TIMBER_HEIGHT, TXHASH_TREE_HEIGHT, HASH_TYPE, TXHASH_TREE_HASH_TYPE } = config;
const { TIMBER_HEIGHT, HASH_TYPE, TXHASH_TREE_HASH_TYPE } = config;
const { ZERO } = constants;

/**
Expand Down Expand Up @@ -148,36 +148,37 @@ async function blockProposedEventHandler(data, syncing) {
}),
);

let height = 1;
while (2 ** height < block.transactionHashes.length) {
++height;
}

// If this L2 block contains withdraw transactions known to this client,
// the following needs to be saved for later to be used during finalise/instant withdraw
// 1. Save sibling path for the withdraw transaction hash that is present in transaction hashes timber tree
// 2. Save transactions hash of the transactions in this L2 block that contains withdraw transactions for this client
// transactions hash is a linear hash of the transactions in an L2 block which is calculated during proposeBlock in
// the contract
if ((await countWithdrawTransactionHashes(block.transactionHashes)) > 0) {
const transactionHashesTimber = new Timber(
...[, , , ,],
TXHASH_TREE_HASH_TYPE,
TXHASH_TREE_HEIGHT,
);
const updatedTransctionHashesTimber = Timber.statelessUpdate(
const transactionHashesTimber = new Timber(...[, , , ,], TXHASH_TREE_HASH_TYPE, height);
const updatedTransactionHashesTimber = Timber.statelessUpdate(
transactionHashesTimber,
block.transactionHashes,
TXHASH_TREE_HASH_TYPE,
TXHASH_TREE_HEIGHT,
height,
);

await Promise.all(
// eslint-disable-next-line consistent-return
block.transactionHashes.map(async (transactionHash, i) => {
if (await isTransactionHashWithdraw(transactionHash)) {
const siblingPathTransactionHash =
updatedTransctionHashesTimber.getSiblingPath(transactionHash);
updatedTransactionHashesTimber.getSiblingPath(transactionHash);
return setTransactionHashSiblingInfo(
transactionHash,
siblingPathTransactionHash,
transactionHashesTimber.leafCount + i,
updatedTransctionHashesTimber.root,
updatedTransactionHashesTimber.root,
);
}
}),
Expand Down
2 changes: 1 addition & 1 deletion nightfall-deployer/contracts/Config.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ contract Config is Ownable, Structures {
uint256 constant ROTATE_PROPOSER_BLOCKS = 4;
uint256 constant COOLING_OFF_PERIOD = 1 weeks;
bytes32 constant ZERO = bytes32(0);
uint256 constant TXHASH_TREE_HEIGHT = 5;
uint256 constant TRANSACTIONS_PER_BLOCK = 32;

address bootProposer;
address bootChallenger;
Expand Down
6 changes: 3 additions & 3 deletions nightfall-deployer/contracts/Shield.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ contract Shield is Stateful, Config, Key_Registry, ReentrancyGuardUpgradeable, P
Block calldata b,
Transaction calldata t,
uint256 index,
bytes32[6] calldata siblingPath
bytes32[] calldata siblingPath
) external view returns (bool) {
// check this block is a real one, in the queue, not something made up.
state.areBlockAndTransactionReal(b, t, index, siblingPath);
Expand Down Expand Up @@ -149,7 +149,7 @@ contract Shield is Stateful, Config, Key_Registry, ReentrancyGuardUpgradeable, P
Block calldata b,
Transaction calldata t,
uint256 index,
bytes32[6] calldata siblingPath
bytes32[] calldata siblingPath
) external {
// check this block is a real one, in the queue, not something made up and that the transaction exists in the block
state.areBlockAndTransactionReal(b, t, index, siblingPath);
Expand Down Expand Up @@ -224,7 +224,7 @@ contract Shield is Stateful, Config, Key_Registry, ReentrancyGuardUpgradeable, P
Block calldata b,
Transaction calldata t,
uint256 index,
bytes32[6] calldata siblingPath
bytes32[] calldata siblingPath
) external payable nonReentrant {
// The transaction is a withdrawal transaction
require(t.transactionType == TransactionTypes.WITHDRAW, 'Can only advance withdrawals');
Expand Down
15 changes: 12 additions & 3 deletions nightfall-deployer/contracts/State.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ contract State is Initializable, ReentrancyGuardUpgradeable, Pausable, Config {
require(BLOCK_STAKE <= msg.value, 'The stake payment is incorrect');
require(b.proposer == msg.sender, 'The proposer address is not the sender');
// set the maximum tx/block to prevent unchallengably large blocks
require(t.length < 33, 'The block has too many transactions');
require(t.length <= TRANSACTIONS_PER_BLOCK, 'The block has too many transactions');

uint256 feePaymentsEth = 0;
uint256 feePaymentsMatic = 0;
Expand Down Expand Up @@ -126,8 +126,17 @@ contract State is Initializable, ReentrancyGuardUpgradeable, Pausable, Config {
}
let transactionHashesRoot
// calculate and store transaction hashes root
let height := 1
for {
let i := 5

} lt(exp(2, height), t.length) {

} {
height := add(height, 1)
}

for {
let i := height
} gt(i, 0) {
i := sub(i, 1)
} {
Expand Down Expand Up @@ -328,7 +337,7 @@ contract State is Initializable, ReentrancyGuardUpgradeable, Pausable, Config {
Block calldata b,
Transaction calldata t,
uint256 index,
bytes32[6] calldata siblingPath
bytes32[] calldata siblingPath
) public view {
bytes32 blockHash = Utils.hashBlock(b);
require(blockHashes[b.blockNumberL2].blockHash == blockHash, 'This block does not exist');
Expand Down
14 changes: 11 additions & 3 deletions nightfall-deployer/contracts/Utils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,16 @@ library Utils {
} {
mstore(add(transactionHashesPos, mul(0x20, i)), mload(add(leavesPos, mul(0x20, i))))
}
let height := 1
for {
let i := 5

} lt(exp(2, height), length) {

} {
height := add(height, 1)
}
for {
let i := height
} gt(i, 0) {
i := sub(i, 1)
} {
Expand All @@ -178,11 +186,11 @@ library Utils {
}

function checkPath(
bytes32[6] calldata siblingPath,
bytes32[] calldata siblingPath,
uint256 leafIndex,
bytes32 node
) public pure returns (bool) {
for (uint256 i = 5; i > 0; i--) {
for (uint256 i = siblingPath.length - 1; i > 0; i--) {
if (leafIndex % 2 == 0) {
node = keccak256(abi.encodePacked(node, siblingPath[i]));
} else {
Expand Down
11 changes: 8 additions & 3 deletions nightfall-optimist/src/classes/block.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import constants from 'common-files/constants/index.mjs';
import { getLatestBlockInfo, getTreeByBlockNumberL2 } from '../services/database.mjs';
import { buildBlockSolidityStruct, calcBlockHash } from '../services/block-utils.mjs';

const { TIMBER_HEIGHT, TXHASH_TREE_HEIGHT, HASH_TYPE, TXHASH_TREE_HASH_TYPE } = config;
const { TIMBER_HEIGHT, HASH_TYPE, TXHASH_TREE_HASH_TYPE } = config;
const { ZERO } = constants;

/**
Expand Down Expand Up @@ -162,12 +162,17 @@ class Block {

static calcTransactionHashesRoot(transactions) {
const transactionHashes = transactions.map(t => t.transactionHash);
const timber = new Timber(...[, , , ,], TXHASH_TREE_HASH_TYPE, TXHASH_TREE_HEIGHT);
let height = 1;
while (2 ** height < transactionHashes.length) {
++height;
}

const timber = new Timber(...[, , , ,], TXHASH_TREE_HASH_TYPE, height);
const updatedTimber = Timber.statelessUpdate(
timber,
transactionHashes,
TXHASH_TREE_HASH_TYPE,
TXHASH_TREE_HEIGHT,
height,
);
return updatedTimber.root;
}
Expand Down
21 changes: 11 additions & 10 deletions wallet/src/nightfall-browser/event-handlers/block-proposed.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
} from '../services/database';
import { edwardsDecompress } from '../../common-files/utils/curve-maths/curves';

const { TIMBER_HEIGHT, TXHASH_TREE_HEIGHT, HASH_TYPE, TXHASH_TREE_HASH_TYPE } = global.config;
const { TIMBER_HEIGHT, HASH_TYPE, TXHASH_TREE_HASH_TYPE } = global.config;
const { ZERO } = global.nightfallConstants;

/**
Expand Down Expand Up @@ -154,37 +154,38 @@ async function blockProposedEventHandler(data, zkpPrivateKeys, nullifierKeys) {
}),
);

let height = 1;
while (2 ** height < block.transactionHashes.length) {
++height;
}

// If this L2 block contains withdraw transactions known to this client,
// the following needs to be saved for later to be used during finalise/instant withdraw
// 1. Save sibling path for the withdraw transaction hash that is present in transaction hashes timber tree
// 2. Save transactions hash of the transactions in this L2 block that contains withdraw transactions for this client
// transactions hash is a linear hash of the transactions in an L2 block which is calculated during proposeBlock in
// the contract
if ((await countWithdrawTransactionHashes(block.transactionHashes)) > 0) {
const transactionHashesTimber = new Timber(
...[, , , ,],
TXHASH_TREE_HASH_TYPE,
TXHASH_TREE_HEIGHT,
);
const transactionHashesTimber = new Timber(...[, , , ,], TXHASH_TREE_HASH_TYPE, height);

const updatedTransctionHashesTimber = Timber.statelessUpdate(
const updatedTransactionHashesTimber = Timber.statelessUpdate(
transactionHashesTimber,
block.transactionHashes,
TXHASH_TREE_HASH_TYPE,
TXHASH_TREE_HEIGHT,
height,
);

await Promise.all(
// eslint-disable-next-line consistent-return
block.transactionHashes.map(async (transactionHash, i) => {
if (await isTransactionHashWithdraw(transactionHash)) {
const siblingPathTransactionHash =
updatedTransctionHashesTimber.getSiblingPath(transactionHash);
updatedTransactionHashesTimber.getSiblingPath(transactionHash);
return setTransactionHashSiblingInfo(
transactionHash,
siblingPathTransactionHash,
transactionHashesTimber.leafCount + i,
updatedTransctionHashesTimber.root,
updatedTransactionHashesTimber.root,
);
}
}),
Expand Down

0 comments on commit ea83d6e

Please sign in to comment.