Skip to content
This repository has been archived by the owner on Jun 29, 2023. It is now read-only.

Commit

Permalink
Merge pull request #670 from b-tarczynski/contracts/c2t-to-nonexisten…
Browse files Browse the repository at this point in the history
…t-public-key

Allow disputing Create2Transfer with nonexistent receiver
  • Loading branch information
jacque006 authored Nov 3, 2021
2 parents c1d1f19 + 674cc8d commit 2258195
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 5 deletions.
7 changes: 7 additions & 0 deletions contracts/libs/Authenticity.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ library Authenticity {
using Tx for bytes;
using Types for Types.UserState;

bytes32 public constant ZERO_BYTES32 =
0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563;

function verifyTransfer(
Types.AuthCommon memory common,
Types.SignatureProof memory proof
Expand Down Expand Up @@ -184,6 +187,10 @@ library Authenticity {
"Authenticity: to account does not exists"
);

if (proof.pubkeyHashesReceiver[i] == ZERO_BYTES32) {
return Types.Result.NonexistentReceiver;
}

// construct the message

uint256 nonce = proof.states[i].nonce - 1;
Expand Down
3 changes: 2 additions & 1 deletion contracts/libs/Types.sol
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ library Types {
BadWithdrawRoot,
BadCompression,
TooManyTx,
BadPrecompileCall
BadPrecompileCall,
NonexistentReceiver
}
}
85 changes: 83 additions & 2 deletions test/slow/rollup.create2Transfer.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { deployAll } from "../../ts/deploy";
import { TESTING_PARAMS } from "../../ts/constants";
import { TESTING_PARAMS, ZERO_BYTES32 } from "../../ts/constants";
import { ethers } from "hardhat";
import { StateTree } from "../../ts/stateTree";
import { AccountRegistry } from "../../ts/accountTree";
Expand All @@ -14,9 +14,14 @@ import {
} from "../../ts/commitments";
import { USDT } from "../../ts/decimal";
import { hexToUint8Array } from "../../ts/utils";
import { Group, txCreate2TransferFactory } from "../../ts/factory";
import {
Group,
txCreate2TransferFactory,
txCreate2TransferToNonexistentReceiver
} from "../../ts/factory";
import { deployKeyless } from "../../ts/deployment/deploy";
import { handleNewBatch } from "../../ts/client/batchHandler";
import { Result } from "../../ts/interfaces";

chai.use(chaiAsPromised);

Expand Down Expand Up @@ -177,4 +182,80 @@ describe("Rollup Create2Transfer", async function() {
"Good state transition should not rollback"
);
}).timeout(120000);

it("submit create2Transfer batch to nonexistent receiver and dispute", async function() {
const feeReceiver = usersWithStates.getUser(0).stateID;
const { rollup } = contracts;

const {
txs,
signature,
sender
} = txCreate2TransferToNonexistentReceiver(
usersWithStates,
usersWithoutState
);

stateTree.processCreate2TransferCommit(txs, feeReceiver);
const postStateRoot = stateTree.root;
const serialized = serialize(txs);

const root = registry.root();
const rootOnchain = await registry.registry.root();
assert.equal(root, rootOnchain, "mismatch pubkey tree root");

const commitment = Create2TransferCommitment.new(
postStateRoot,
root,
signature,
feeReceiver,
serialized
);

const targetBatch = commitment.toBatch();
const c2TBatchID = 1;
const _txSubmit = await targetBatch.submit(
rollup,
c2TBatchID,
TESTING_PARAMS.STAKE_AMOUNT
);
console.log(
"submitBatch execution cost",
(await _txSubmit.wait()).gasUsed.toNumber()
);

const commitmentMP = targetBatch.proof(0);
const postProofs = txs.map(tx => stateTree.getState(tx.fromIndex));
const proof = {
states: postProofs.map(proof => proof.state),
stateWitnesses: postProofs.map(proof => proof.witness),
pubkeysSender: [sender.pubkey],
pubkeyWitnessesSender: [registry.witness(sender.pubkeyID)],
pubkeyHashesReceiver: [ZERO_BYTES32],
pubkeyWitnessesReceiver: txs.map(tx =>
registry.witness(tx.toPubkeyID)
)
};
const _tx = await rollup.disputeSignatureCreate2Transfer(
c2TBatchID,
commitmentMP,
proof,
{ gasLimit: 1000000 }
);

const receipt = await _tx.wait();
console.log("disputeBatch execution cost", receipt.gasUsed.toNumber());
const [[status], [event]] = await Promise.all([
rollup.queryFilter(rollup.filters.RollbackStatus(), _tx.blockHash),
rollup.queryFilter(
rollup.filters.RollbackTriggered(),
_tx.blockHash
)
]);
assert.equal(Number(event.args.batchID), c2TBatchID);
assert.equal(Number(await rollup.invalidBatchMarker()), 0);
assert.isTrue(status.args?.completed);
assert.equal(Number(status.args?.nDeleted), 1);
assert.equal(event.args.result, Result.NonexistentReceiver);
}).timeout(120000);
});
43 changes: 42 additions & 1 deletion ts/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { PubkeyDatabaseEngine, StateDatabaseEngine } from "./client/database";
import { StorageManager } from "./client/storageEngine";
import { BatchMemoryStorage } from "./client/storageEngine/batches/memory";
import { TransactionMemoryStorage } from "./client/storageEngine/transactions/memory";
import { DEFAULT_MNEMONIC } from "./constants";
import { DEFAULT_MNEMONIC, ZERO_BYTES32 } from "./constants";
import { float16, USDT } from "./decimal";
import { UserNotExist } from "./exceptions";
import { Domain, solG1 } from "./mcl";
Expand All @@ -17,6 +17,7 @@ import {
SignableTx,
getAggregateSig
} from "./tx";
import { solidityPack } from "ethers/lib/utils";

export class User {
private tokenIDtoStateID: Record<number, number>;
Expand Down Expand Up @@ -303,6 +304,46 @@ export function txMassMigrationFactory(
return { txs, signature, senders };
}

export function txCreate2TransferToNonexistentReceiver(
registered: Group,
unregistered: Group
): {
txs: TxCreate2Transfer[];
signature: solG1;
sender: User;
} {
const sender = registered.getUser(0);
const receiver = unregistered.getUser(0);
const senderState = registered.getState(sender);
const amount = float16.round(senderState.balance.div(10));
const fee = float16.round(amount.div(10));

const tx = new TxCreate2Transfer(
sender.stateID,
receiver.stateID,
receiver.pubkey,
1000,
amount,
fee,
senderState.nonce.toNumber()
);
const txMessage = create2TransferMessage(tx, ZERO_BYTES32);
tx.signature = sender.signRaw(txMessage);
const txs = [tx];

return { txs: txs, signature: getAggregateSig(txs), sender };
}

function create2TransferMessage(
tx: TxCreate2Transfer,
pubkeyHash: string
): string {
return solidityPack(
["uint256", "uint256", "bytes32", "uint256", "uint256", "uint256"],
["0x03", tx.fromIndex, pubkeyHash, tx.nonce, tx.amount, tx.fee]
);
}

interface StorageManagerFactoryOptions {
stateTreeDepth?: number;
pubkeyTreeDepth?: number;
Expand Down
4 changes: 3 additions & 1 deletion ts/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ export enum Result {
MismatchedAmount,
BadWithdrawRoot,
BadCompression,
TooManyTx
TooManyTx,
BadPrecompileCall,
NonexistentReceiver
}

export type Wei = string;
Expand Down

0 comments on commit 2258195

Please sign in to comment.