Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blocks can be made at any point in time #630

Merged
merged 1 commit into from
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cli/lib/nf3.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ class Nf3 {

/**
Gets the number of unprocessed transactions on the optimist
@method
@async
*/

Expand All @@ -190,6 +191,16 @@ class Nf3 {
return mempool.filter(e => e.mempool).length;
}

/**
Forces optimist to make a block with whatever transactions it has to hand i.e. it won't wait
until it has TRANSACTIONS_PER_BLOCK of them
@method
@async
*/
async makeBlockNow() {
return axios.get(`${this.optimistBaseUrl}/block/make-now`);
}

/**
Method for signing and submitting an Ethereum transaction to the
blockchain.
Expand Down
11 changes: 11 additions & 0 deletions nightfall-optimist/src/routes/block.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
getBlockByRoot,
getTransactionsByTransactionHashes,
} from '../services/database.mjs';
import { setMakeNow } from '../services/block-assembler.mjs';

const router = express.Router();

Expand All @@ -26,6 +27,16 @@ router.post('/check', async (req, res, next) => {
}
});

router.get('/make-now', async (req, res, next) => {
logger.debug('make-now endpoint received GET');
try {
setMakeNow();
res.send('Making short block');
} catch (err) {
next(err);
}
});

router.get('/transaction-hash/:transactionHash', async (req, res, next) => {
logger.debug('block endpoint received get');
try {
Expand Down
22 changes: 18 additions & 4 deletions nightfall-optimist/src/services/block-assembler.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ import { waitForContract } from '../event-handlers/subscribe.mjs';
const { TRANSACTIONS_PER_BLOCK, STATE_CONTRACT_NAME } = config;

let ws;
let makeNow = false;

export function setBlockAssembledWebSocketConnection(_ws) {
ws = _ws;
}

export function setMakeNow(_makeNow = true) {
makeNow = _makeNow;
}

async function makeBlock(proposer, number = TRANSACTIONS_PER_BLOCK) {
logger.debug('Block Assembler - about to make a new block');
// we retrieve un-processed transactions from our local database, relying on
Expand All @@ -47,9 +52,12 @@ export async function conditionalMakeBlock(proposer) {
// transaction. If not, we must wait until either we have enough (hooray)
// or we're no-longer the proposer (boo).
if (proposer.isMe) {
const numberOfProposableL2Blocks = Math.floor(
(await numberOfUnprocessedTransactions()) / TRANSACTIONS_PER_BLOCK,
);
const unprocessed = await numberOfUnprocessedTransactions();
let numberOfProposableL2Blocks = Math.floor(unprocessed / TRANSACTIONS_PER_BLOCK);
// if we want to make a block right now but there aren't enough transactions, this logic
// tells us to go anyway
if (makeNow && unprocessed > 0 && numberOfProposableL2Blocks === 0)
numberOfProposableL2Blocks = 1;

if (numberOfProposableL2Blocks >= 1) {
// TODO set an upper limit to numberOfProposableL2Blocks because a proposer
Expand All @@ -58,7 +66,13 @@ export async function conditionalMakeBlock(proposer) {
// the transactions will fail and proposer will lose gas fees
logger.debug(`Block Assembler will create ${numberOfProposableL2Blocks} blocks at once`);
for (let i = 0; i < numberOfProposableL2Blocks; i++) {
const { block, transactions } = await makeBlock(proposer.address);
// work out if this is a normal size block or a short one
const numberOfTransactionsInBlock = makeNow ? unprocessed : TRANSACTIONS_PER_BLOCK;
makeNow = false; // reset the makeNow so we only make one block with a short number of transactions
const { block, transactions } = await makeBlock(
proposer.address,
numberOfTransactionsInBlock,
);
logger.info(`Block Assembler - New Block created, ${JSON.stringify(block, null, 2)}`);
// propose this block to the Shield contract here
const unsignedProposeBlockTransaction = await (
Expand Down
21 changes: 20 additions & 1 deletion test/e2e/tokens/erc1155.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ let stateAddress;
let eventLogs = [];
let availableTokenIds;

/*
/*
This function tries to zero the number of unprocessed transactions in the optimist node
that nf3 is connected to. We call it extensively on the tests, as we want to query stuff from the
L2 layer, which is dependent on a block being made. We also need 0 unprocessed transactions by the end
Expand Down Expand Up @@ -164,6 +164,25 @@ describe('ERC1155 tests', () => {
expect(balanceAfter[0] - balanceBefore[0]).to.be.equal(transferValue);
expect(balanceAfter[1] - balanceBefore[1]).to.be.equal(transferValue);
});

it('should deposit some ERC1155 crypto into a ZKP commitment and make a block with a single transaction', async function () {
// We create enough transactions to fill blocks full of deposits.
const res0 = await nf3Proposer1.makeBlockNow();
expect(res0.data).to.be.equal('Making short block');
const res = await nf3Users[0].deposit(
erc1155Address,
tokenTypeERC1155,
transferValue,
availableTokenIds[2],
fee,
);
expectTransaction(res);

// Wait until we see the right number of blocks appear
eventLogs = await web3Client.waitForEvent(eventLogs, ['blockProposed']);

await emptyL2(nf3Users[0]);
});
});

describe('Transfer', () => {
Expand Down