Skip to content

Commit

Permalink
chore(p2p): tx serialization cleanup (#7620)
Browse files Browse the repository at this point in the history
  • Loading branch information
Maddiaa0 authored Jul 26, 2024
1 parent cf571c9 commit 022a899
Show file tree
Hide file tree
Showing 3 changed files with 8 additions and 137 deletions.
6 changes: 3 additions & 3 deletions yarn-project/p2p/src/service/libp2p_service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Tx } from '@aztec/circuit-types';
import { Tx } from '@aztec/circuit-types';
import { SerialQueue } from '@aztec/foundation/fifo';
import { createDebugLogger } from '@aztec/foundation/log';
import { RunningPromise } from '@aztec/foundation/running-promise';
Expand All @@ -21,7 +21,7 @@ import { convertToMultiaddr } from '../util.js';
import { AztecDatastore } from './data_store.js';
import { PeerManager } from './peer_manager.js';
import type { P2PService, PeerDiscoveryService } from './service.js';
import { AztecTxMessageCreator, fromTxMessage } from './tx_messages.js';
import { AztecTxMessageCreator } from './tx_messages.js';

export interface PubSubLibp2p extends Libp2p {
services: {
Expand Down Expand Up @@ -239,7 +239,7 @@ export class LibP2PService implements P2PService {
return;
}

const tx = fromTxMessage(Buffer.from(data));
const tx = Tx.fromBuffer(Buffer.from(data));
await this.processTxFromPeer(tx);
}

Expand Down
8 changes: 3 additions & 5 deletions yarn-project/p2p/src/service/tx_messages.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { type Tx, mockTx } from '@aztec/circuit-types';
import { Tx, mockTx } from '@aztec/circuit-types';

import { expect } from '@jest/globals';

import { fromTxMessage, toTxMessage } from './tx_messages.js';

const verifyTx = (actual: Tx, expected: Tx) => {
expect(actual.data.toBuffer()).toEqual(expected.data.toBuffer());
expect(actual.clientIvcProof.toBuffer()).toEqual(expected.clientIvcProof.toBuffer());
Expand All @@ -13,8 +11,8 @@ const verifyTx = (actual: Tx, expected: Tx) => {
describe('Messages', () => {
it('Correctly serializes and deserializes a single private transaction', () => {
const transaction = mockTx();
const message = toTxMessage(transaction);
const decodedTransaction = fromTxMessage(message);
const message = transaction.toBuffer();
const decodedTransaction = Tx.fromBuffer(message);
verifyTx(decodedTransaction, transaction);
});
});
131 changes: 2 additions & 129 deletions yarn-project/p2p/src/service/tx_messages.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
import {
EncryptedNoteTxL2Logs,
EncryptedTxL2Logs,
PublicExecutionRequest,
Tx,
UnencryptedTxL2Logs,
} from '@aztec/circuit-types';
import { ClientIvcProof, PrivateKernelTailCircuitPublicInputs } from '@aztec/circuits.js';
import { numToUInt32BE } from '@aztec/foundation/serialize';
import { type Tx } from '@aztec/circuit-types';

import { type SemVer } from 'semver';

Expand All @@ -19,7 +11,7 @@ export class AztecTxMessageCreator {
}

createTxMessage(tx: Tx) {
const messageData = toTxMessage(tx);
const messageData = tx.toBuffer();

return { topic: this.topic, data: messageData };
}
Expand All @@ -28,122 +20,3 @@ export class AztecTxMessageCreator {
return this.topic;
}
}

/**
* Decode a POOLED_TRANSACTIONS message into the original transaction objects.
* @param message - The binary message to be decoded.
* @returns - The array of transactions originally encoded into the message.
*/
export function decodeTransactionsMessage(message: Buffer) {
const lengthSize = 4;
let offset = 0;
const txs: Tx[] = [];
while (offset < message.length) {
const dataSize = message.readUInt32BE(offset);
const totalSizeOfMessage = lengthSize + dataSize;
txs.push(fromTxMessage(message.subarray(offset, offset + totalSizeOfMessage)));
offset += totalSizeOfMessage;
}
return txs;
}

/**
* Creates a tx 'message' for sending to a peer.
* @param tx - The transaction to convert to a message.
* @returns - The message.
*/
export function toTxMessage(tx: Tx): Buffer {
// eslint-disable-next-line jsdoc/require-jsdoc
const createMessageComponent = (obj?: { toBuffer: () => Buffer }) => {
if (!obj) {
// specify a length of 0 bytes
return numToUInt32BE(0);
}
const buffer = obj.toBuffer();
return Buffer.concat([numToUInt32BE(buffer.length), buffer]);
};
// eslint-disable-next-line jsdoc/require-jsdoc
const createMessageComponents = (obj?: { toBuffer: () => Buffer }[]) => {
if (!obj || !obj.length) {
// specify a length of 0 bytes
return numToUInt32BE(0);
}
const allComponents = Buffer.concat(obj.map(createMessageComponent));
return Buffer.concat([numToUInt32BE(obj.length), allComponents]);
};
const messageBuffer = Buffer.concat([
createMessageComponent(tx.data),
createMessageComponent(tx.clientIvcProof),
createMessageComponent(tx.noteEncryptedLogs),
createMessageComponent(tx.encryptedLogs),
createMessageComponent(tx.unencryptedLogs),
createMessageComponents(tx.enqueuedPublicFunctionCalls),
createMessageComponent(tx.publicTeardownFunctionCall),
]);
const messageLength = numToUInt32BE(messageBuffer.length);
return Buffer.concat([messageLength, messageBuffer]);
}

/**
* Reproduces a transaction from a transaction 'message'
* @param buffer - The message buffer to convert to a tx.
* @returns - The reproduced transaction.
*/
export function fromTxMessage(buffer: Buffer): Tx {
// eslint-disable-next-line jsdoc/require-jsdoc
const toObject = <T>(objectBuffer: Buffer, factory: { fromBuffer: (b: Buffer) => T }) => {
const objectSize = objectBuffer.readUint32BE(0);
return {
remainingData: objectBuffer.subarray(objectSize + 4),
obj: objectSize === 0 ? undefined : factory.fromBuffer(objectBuffer.subarray(4, objectSize + 4)),
};
};

// eslint-disable-next-line jsdoc/require-jsdoc
const toObjectArray = <T>(objectBuffer: Buffer, factory: { fromBuffer: (b: Buffer) => T }) => {
const output: T[] = [];
const numItems = objectBuffer.readUint32BE(0);
let workingBuffer = objectBuffer.subarray(4);
for (let i = 0; i < numItems; i++) {
const obj = toObject<T>(workingBuffer, factory);
workingBuffer = obj.remainingData;
if (obj !== undefined) {
output.push(obj.obj!);
}
}
return {
remainingData: workingBuffer,
objects: output,
};
};
// this is the opposite of the 'toMessage' function
// so the first 4 bytes is the complete length, skip it
const publicInputs = toObject(buffer.subarray(4), PrivateKernelTailCircuitPublicInputs);
const clientIvcProof = toObject(publicInputs.remainingData, ClientIvcProof);

const noteEncryptedLogs = toObject(clientIvcProof.remainingData, EncryptedNoteTxL2Logs);
if (!noteEncryptedLogs.obj) {
noteEncryptedLogs.obj = new EncryptedNoteTxL2Logs([]);
}
const encryptedLogs = toObject(noteEncryptedLogs.remainingData, EncryptedTxL2Logs);
if (!encryptedLogs.obj) {
encryptedLogs.obj = new EncryptedTxL2Logs([]);
}
const unencryptedLogs = toObject(encryptedLogs.remainingData, UnencryptedTxL2Logs);
if (!unencryptedLogs.obj) {
unencryptedLogs.obj = new UnencryptedTxL2Logs([]);
}

const publicCalls = toObjectArray(unencryptedLogs.remainingData, PublicExecutionRequest);

const publicTeardownCall = toObject(publicCalls.remainingData, PublicExecutionRequest);
return new Tx(
publicInputs.obj!,
clientIvcProof.obj!,
noteEncryptedLogs.obj,
encryptedLogs.obj,
unencryptedLogs.obj,
publicCalls.objects,
publicTeardownCall.obj!,
);
}

0 comments on commit 022a899

Please sign in to comment.