Skip to content

Commit

Permalink
Merge pull request #639 from EYBlockchain/chait/txHashes
Browse files Browse the repository at this point in the history
transactionHashesRoot calculated in proposeBlock without challenge
  • Loading branch information
Ilyas Ridhuan authored May 6, 2022
2 parents 4a94f93 + dc18355 commit cb73321
Show file tree
Hide file tree
Showing 30 changed files with 237 additions and 685 deletions.
48 changes: 34 additions & 14 deletions common-files/classes/transaction.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,51 @@
/**
An optimistic Transaction class
*/
import config from 'config';
import gen from 'general-number';
import Web3 from '../utils/web3.mjs';
import { compressProof } from '../utils/curve-maths/curves.mjs';

const { generalise } = gen;

const TOKEN_TYPES = { ERC20: 0, ERC721: 1, ERC1155: 2 };
const { TRANSACTION_TYPES } = config;

// function to compute the keccak hash of a transaction
function keccak(preimage) {
const web3 = Web3.connection();
// compute the solidity hash, using suitable type conversions
return web3.utils.soliditySha3(
{ t: 'uint112', v: preimage.value },
...preimage.historicRootBlockNumberL2.map(hi => ({ t: 'uint256', v: hi })),
{ t: 'uint8', v: preimage.transactionType },
{ t: 'uint8', v: preimage.tokenType },
{ t: 'bytes32', v: preimage.tokenId },
{ t: 'bytes32', v: preimage.ercAddress },
{ t: 'bytes32', v: preimage.recipientAddress },
...preimage.commitments.map(ch => ({ t: 'bytes32', v: ch })),
...preimage.nullifiers.map(nh => ({ t: 'bytes32', v: nh })),
...preimage.compressedSecrets.map(es => ({ t: 'bytes32', v: es })),
...compressProof(preimage.proof).map(p => ({ t: 'uint', v: p })),
);
const {
value,
historicRootBlockNumberL2,
transactionType,
tokenType,
tokenId,
ercAddress,
recipientAddress,
commitments,
nullifiers,
compressedSecrets,
} = preimage;
let { proof } = preimage;
proof = compressProof(proof);
const transaction = [
value,
historicRootBlockNumberL2,
transactionType,
tokenType,
tokenId,
ercAddress,
recipientAddress,
commitments,
nullifiers,
compressedSecrets,
proof,
];
const encodedTransaction = web3.eth.abi.encodeParameters([TRANSACTION_TYPES], [transaction]);
return web3.utils.soliditySha3({
t: 'bytes',
v: encodedTransaction,
});
}

class Transaction {
Expand Down
3 changes: 3 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ module.exports = {
BN128_GROUP_ORDER: 21888242871839275222246405745257275088548364400416034343698204186575808495617n,
BN128_PRIME_FIELD: 21888242871839275222246405745257275088696311157297823662689037894645226208583n,
TRANSACTIONS_PER_BLOCK: Number(process.env.TRANSACTIONS_PER_BLOCK) || 2,
BLOCK_TYPES: '(uint48,address,bytes32,uint256,bytes32,bytes32)',
TRANSACTION_TYPES:
'(uint112,uint64[2],uint8,uint8,bytes32,bytes32,bytes32,bytes32[2],bytes32[2],bytes32[8],uint[4])',
PROPOSE_BLOCK_TYPES: [
'(uint48,address,bytes32,uint256,bytes32,bytes32)',
'(uint112,uint64[2],uint8,uint8,bytes32,bytes32,bytes32,bytes32[2],bytes32[2],bytes32[8],uint[4])[]',
Expand Down
2 changes: 0 additions & 2 deletions nightfall-client/src/event-handlers/block-proposed.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
saveTransaction,
saveBlock,
setTransactionHashSiblingInfo,
setTransactionsHashForBlock,
} from '../services/database.mjs';
import { decryptCommitment } from '../services/commitment-sync.mjs';

Expand Down Expand Up @@ -114,7 +113,6 @@ async function blockProposedEventHandler(data) {
if (await isTransactionHashWithdraw(transactionHash)) {
const siblingPathTransactionHash =
updatedTransctionHashesTimber.getSiblingPath(transactionHash);
await setTransactionsHashForBlock(transactionHash, block.transactionsHash);
return setTransactionHashSiblingInfo(
transactionHash,
siblingPathTransactionHash,
Expand Down
11 changes: 0 additions & 11 deletions nightfall-client/src/services/database.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -266,17 +266,6 @@ export async function getTransactionByTransactionHash(transactionHash) {
return db.collection(TRANSACTIONS_COLLECTION).findOne(query);
}

// function to set the path of the transaction hash leaf in transaction hash timber
export async function setTransactionsHashForBlock(transactionHash, transactionsHash) {
const connection = await mongo.connection(MONGO_URL);
const query = { transactionHash };
const update = {
$set: { transactionsHash },
};
const db = connection.db(COMMITMENTS_DB);
return db.collection(TRANSACTIONS_COLLECTION).updateMany(query, update);
}

// function to set the path of the transaction hash leaf in transaction hash timber
export async function setTransactionHashSiblingInfo(
transactionHash,
Expand Down
1 change: 0 additions & 1 deletion nightfall-client/src/services/finalise-withdrawal.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export async function finaliseWithdrawal(transactionHash) {
const rawTransaction = await shieldContractInstance.methods
.finaliseWithdrawal(
buildSolidityStruct(block),
block.transactionsHash,
Transaction.buildSolidityStruct(transactions[index]),
index,
siblingPath,
Expand Down
1 change: 0 additions & 1 deletion nightfall-client/src/services/instant-withdrawal.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const setInstantWithdrawl = async ({ transactionHash }) => {
const rawTransaction = await shieldContractInstance.methods
.setAdvanceWithdrawalFee(
buildSolidityStruct(block),
block.transactionsHash,
Transaction.buildSolidityStruct(transactions[index]),
index,
siblingPath,
Expand Down
6 changes: 0 additions & 6 deletions nightfall-client/src/services/process-calldata.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,6 @@ async function getProposeBlockCalldata(eventData) {
});

block.transactionHashes = transactions.map(t => t.transactionHash);
const encodedTransactions = `0x${tx.input.slice(394)}`; // retrieve only transactions data
block.transactionsHash = web3.utils.soliditySha3({
t: 'bytes',
v: encodedTransactions,
});

return { transactions, block };
}

Expand Down
1 change: 0 additions & 1 deletion nightfall-client/src/services/valid-withdrawal.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export async function isValidWithdrawal({ block, transaction, index, siblingPath
const valid = await shieldContractInstance.methods
.isValidWithdrawal(
buildSolidityStruct(block),
block.transactionsHash,
Transaction.buildSolidityStruct(transaction),
index,
siblingPath,
Expand Down
46 changes: 16 additions & 30 deletions nightfall-deployer/contracts/Challenges.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ contract Challenges is Stateful, Key_Registry, Config {
) external onlyBootChallenger {
checkCommit(msg.data);
// check if the block hash is correct and the block hash exists for the block and prior block. Also if the transactions are part of these block
state.isBlockReal(priorBlockL2, priorBlockTransactions);
state.isBlockReal(blockL2, transactions);
state.areBlockAndTransactionsReal(priorBlockL2, priorBlockTransactions);
state.areBlockAndTransactionsReal(blockL2, transactions);
ChallengesUtil.libChallengeLeafCountCorrect(
priorBlockL2,
priorBlockTransactions,
Expand Down Expand Up @@ -73,8 +73,8 @@ contract Challenges is Stateful, Key_Registry, Config {
) external onlyBootChallenger {
checkCommit(msg.data);
// check if the block hash is correct and the block hash exists for the block and prior block
state.isBlockReal(priorBlockL2, priorBlockTransactions);
state.isBlockReal(blockL2, transactions);
state.areBlockAndTransactionsReal(priorBlockL2, priorBlockTransactions);
state.areBlockAndTransactionsReal(blockL2, transactions);
// see if the challenge is valid
ChallengesUtil.libChallengeNewRootCorrect(
priorBlockL2,
Expand Down Expand Up @@ -102,8 +102,8 @@ contract Challenges is Stateful, Key_Registry, Config {
) external onlyBootChallenger {
checkCommit(msg.data);
// first, check we have real, in-train, contiguous blocks
state.isBlockReal(block1, transactions1);
state.isBlockReal(block2, transactions2);
state.areBlockAndTransactionsReal(block1, transactions1);
state.areBlockAndTransactionsReal(block2, transactions2);
// If the duplicate exists in the same block, the index cannot be the same
if (block1.blockNumberL2 == block2.blockNumberL2)
require(transactionIndex1 != transactionIndex2, 'Cannot be the same index');
Expand All @@ -128,7 +128,7 @@ contract Challenges is Stateful, Key_Registry, Config {
bytes32 salt
) external onlyBootChallenger {
checkCommit(msg.data);
state.isBlockReal(blockL2, transactions);
state.areBlockAndTransactionsReal(blockL2, transactions);
ChallengesUtil.libChallengeTransactionType(transactions[transactionIndex]);
// Delete the latest block of the two
challengeAccepted(blockL2);
Expand All @@ -143,7 +143,7 @@ contract Challenges is Stateful, Key_Registry, Config {
bytes32 salt
) external onlyBootChallenger {
checkCommit(msg.data);
state.isBlockReal(blockL2, transactions);
state.areBlockAndTransactionsReal(blockL2, transactions);
// first check the transaction and block do not overflow
ChallengesUtil.libCheckOverflows(blockL2, transactions[transactionIndex]);
// now we need to check that the proof is correct
Expand Down Expand Up @@ -171,8 +171,8 @@ contract Challenges is Stateful, Key_Registry, Config {
bytes32 salt
) external onlyBootChallenger {
checkCommit(msg.data);
state.isBlockReal(blockL2, transactions);
state.isBlockReal(
state.areBlockAndTransactionsReal(blockL2, transactions);
state.areBlockAndTransactionsReal(
blockL2ContainingHistoricRoot,
transactionsOfblockL2ContainingHistoricRoot
);
Expand Down Expand Up @@ -209,12 +209,12 @@ contract Challenges is Stateful, Key_Registry, Config {
bytes32 salt
) external onlyBootChallenger {
checkCommit(msg.data);
state.isBlockReal(blockL2, transactions);
state.isBlockReal(
state.areBlockAndTransactionsReal(blockL2, transactions);
state.areBlockAndTransactionsReal(
blockL2ContainingHistoricRoot[0],
transactionsOfblockL2ContainingHistoricRoot
);
state.isBlockReal(
state.areBlockAndTransactionsReal(
blockL2ContainingHistoricRoot[1],
transactionsOfblockL2ContainingHistoricRoot2
);
Expand Down Expand Up @@ -264,8 +264,8 @@ contract Challenges is Stateful, Key_Registry, Config {
txs2[transactionIndex2],
nullifierIndex2
);
state.isBlockReal(block1, txs1);
state.isBlockReal(block2, txs2);
state.areBlockAndTransactionsReal(block1, txs1);
state.areBlockAndTransactionsReal(block2, txs2);

// The blocks are different and we prune the later block of the two
// as we have a block number, it's easy to see which is the latest.
Expand All @@ -288,7 +288,7 @@ contract Challenges is Stateful, Key_Registry, Config {
bytes32 salt
) external onlyBootChallenger {
checkCommit(msg.data);
state.isBlockReal(blockL2, transactions);
state.areBlockAndTransactionsReal(blockL2, transactions);
if (
transactions[transactionIndex].transactionType ==
Structures.TransactionTypes.DOUBLE_TRANSFER
Expand Down Expand Up @@ -319,20 +319,6 @@ contract Challenges is Stateful, Key_Registry, Config {
challengeAccepted(blockL2);
}

/*
This is a challenge that transactionHashesRoot is incorrectly calculated
*/
function challengeTransactionHashesRoot(
Block memory blockL2,
Transaction[] memory transactions,
bytes32 salt
) external onlyBootChallenger {
checkCommit(msg.data);
bytes32 currentBlockHash = state.isBlockReal(blockL2, transactions);
ChallengesUtil.libChallengeTransactionHashesRoot(blockL2, transactions, currentBlockHash);
challengeAccepted(blockL2);
}

// This gets called when a challenge succeeds
function challengeAccepted(Block memory badBlock) private {
// Check to ensure that the block being challenged is less than a week old
Expand Down
48 changes: 16 additions & 32 deletions nightfall-deployer/contracts/ChallengesUtil.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import './Structures.sol';
library ChallengesUtil {
bytes32 public constant ZERO =
0x0000000000000000000000000000000000000000000000000000000000000000;
uint256 public constant MAX31 = 2 ** 249 - 1;
uint256 public constant MAX20 = 2 ** 161 - 1;
uint256 public constant BN128_GROUP_ORDER = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 public constant MAX31 = 2**249 - 1;
uint256 public constant MAX20 = 2**161 - 1;
uint256 public constant BN128_GROUP_ORDER =
21888242871839275222246405745257275088548364400416034343698204186575808495617;

function libChallengeLeafCountCorrect(
Structures.Block memory priorBlockL2,
Expand Down Expand Up @@ -207,16 +208,19 @@ library ChallengesUtil {
}

function libCheckOverflows(
Structures.Block calldata blockL2,
Structures.Transaction calldata transaction
Structures.Block calldata blockL2,
Structures.Transaction calldata transaction
) public pure {
require(uint256(transaction.ercAddress) <= MAX20, 'ERC address out of range');
require(uint256(transaction.recipientAddress) <= MAX20, 'Recipient ERC address out of range');
require(uint256(transaction.commitments[0]) <= MAX31, 'Commitment 0 out of range');
require(uint256(transaction.commitments[1]) <= MAX31, 'Commitment 1 out of range');
require(uint256(transaction.nullifiers[0]) <= MAX31, 'Nullifier 0 out of range');
require(uint256(transaction.nullifiers[1]) <= MAX31, 'Nullifier 1 out of range');
require(uint256(blockL2.root) < BN128_GROUP_ORDER, 'root out of range');
require(uint256(transaction.ercAddress) <= MAX20, 'ERC address out of range');
require(
uint256(transaction.recipientAddress) <= MAX20,
'Recipient ERC address out of range'
);
require(uint256(transaction.commitments[0]) <= MAX31, 'Commitment 0 out of range');
require(uint256(transaction.commitments[1]) <= MAX31, 'Commitment 1 out of range');
require(uint256(transaction.nullifiers[0]) <= MAX31, 'Nullifier 0 out of range');
require(uint256(transaction.nullifiers[1]) <= MAX31, 'Nullifier 1 out of range');
require(uint256(blockL2.root) < BN128_GROUP_ORDER, 'root out of range');
}

function libChallengeNullifier(
Expand All @@ -234,24 +238,4 @@ library ChallengesUtil {
'Transactions need to be different'
);
}

function libChallengeTransactionHashesRoot(
Structures.Block memory blockL2,
Structures.Transaction[] memory transactions,
bytes32 currentBlockHash
) public pure {
bytes32 correctBlockHash =
keccak256(
abi.encode(
blockL2.leafCount,
blockL2.proposer,
blockL2.root,
blockL2.blockNumberL2,
blockL2.previousBlockHash,
Utils.hashTransactionHashes(transactions),
transactions
)
);
require(correctBlockHash != currentBlockHash, 'txHashRoot incorrect');
}
}
Loading

0 comments on commit cb73321

Please sign in to comment.