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

feat: tx verification & peer scoring on p2p layer #8298

Merged
merged 27 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
081bff2
feat: tx verification on p2p layer
spypsy Aug 30, 2024
d28e5cd
remove unecessary complexity from p2p tx validation
spypsy Sep 2, 2024
a6c7551
update tests
spypsy Sep 2, 2024
aa77b00
update validator factory
spypsy Sep 2, 2024
df11b41
remove unnecessary global var builder
spypsy Sep 2, 2024
b9a2b82
Merge branch 'master' into spy/p2p-tx-validation
spypsy Sep 2, 2024
6659334
fix server tests
spypsy Sep 4, 2024
baea32b
use mockFn
spypsy Sep 4, 2024
d13cd69
merge with master
spypsy Sep 4, 2024
0d79216
fix test
spypsy Sep 4, 2024
b7327cf
Merge branch 'master' into spy/p2p-tx-validation
spypsy Sep 4, 2024
cafa5be
peer scoring according to tx validation errors
spypsy Sep 5, 2024
eae3fc6
Remove console statement
spypsy Sep 5, 2024
0a39e38
Merge branch 'master' into spy/p2p-tx-validation
spypsy Sep 9, 2024
3b08b7a
rm unused file
spypsy Sep 9, 2024
ceece5f
add unit tests for peer scoring
spypsy Sep 12, 2024
3e74c93
expose gossipsub config values
spypsy Sep 12, 2024
fad3232
remove set-up job
spypsy Sep 12, 2024
494c3f1
merge master conflicts
spypsy Sep 13, 2024
82b888f
fix build
spypsy Sep 13, 2024
90ad1ed
fix formatting
spypsy Sep 13, 2024
cc7bd10
Merge branch 'master' into spy/p2p-tx-validation
spypsy Sep 16, 2024
9d0be48
more gossipsub config values
spypsy Sep 16, 2024
3ac7ef5
Merge branch 'master' into spy/p2p-tx-validation
spypsy Sep 16, 2024
7ca89d8
accept peer scoring values in random order
spypsy Sep 17, 2024
b2042a6
merge with master
spypsy Sep 17, 2024
83568e8
feat: add bot support for EasyPrivateToken (#8566)
spypsy Sep 17, 2024
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
66 changes: 8 additions & 58 deletions yarn-project/aztec-node/src/aztec-node/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import {
type L2LogsSource,
type MerkleTreeAdminOperations,
MerkleTreeId,
type WorldStateSynchronizer,
mockTxForRollup,
} from '@aztec/circuit-types';
import { AztecAddress, EthAddress, Fr, GasFees, GlobalVariables, MaxBlockNumber } from '@aztec/circuits.js';
import { EthAddress, Fr, MaxBlockNumber } from '@aztec/circuits.js';
import { type P2P } from '@aztec/p2p';
import { type GlobalVariableBuilder } from '@aztec/sequencer-client';
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
import { type ContractDataSource } from '@aztec/types/contracts';
import { type WorldStateSynchronizer } from '@aztec/world-state';

import { type MockProxy, mock, mockFn } from 'jest-mock-extended';
import { type MockProxy, mock } from 'jest-mock-extended';

import { type AztecNodeConfig, getConfigEnvVars } from './config.js';
import { AztecNodeService } from './server.js';
Expand All @@ -30,10 +30,6 @@ describe('aztec node', () => {
let node: AztecNode;

const chainId = new Fr(12345);
const version = Fr.ZERO;
const coinbase = EthAddress.random();
const feeRecipient = AztecAddress.random();
const gasFees = GasFees.empty();

beforeEach(() => {
lastBlockNumber = 0;
Expand All @@ -48,7 +44,7 @@ describe('aztec node', () => {
});

const l2BlockSource = mock<L2BlockSource>({
getBlockNumber: mockFn().mockResolvedValue(lastBlockNumber),
getBlockNumber: () => Promise.resolve(lastBlockNumber),
});

const l2LogsSource = mock<L2LogsSource>();
Expand Down Expand Up @@ -80,7 +76,7 @@ describe('aztec node', () => {
l1ToL2MessageSource,
worldState,
undefined,
31337,
12345,
1,
globalVariablesBuilder,
new TestCircuitVerifier(),
Expand All @@ -96,21 +92,7 @@ describe('aztec node', () => {
});
const doubleSpendTx = txs[0];
const doubleSpendWithExistingTx = txs[1];

const mockedGlobalVariables = new GlobalVariables(
chainId,
version,
new Fr(lastBlockNumber + 1),
new Fr(1),
Fr.ZERO,
coinbase,
feeRecipient,
gasFees,
);

globalVariablesBuilder.buildGlobalVariables
.mockResolvedValueOnce(mockedGlobalVariables)
.mockResolvedValueOnce(mockedGlobalVariables);
lastBlockNumber += 1;

expect(await node.isValidTx(doubleSpendTx)).toBe(true);

Expand All @@ -119,10 +101,6 @@ describe('aztec node', () => {

expect(await node.isValidTx(doubleSpendTx)).toBe(false);

globalVariablesBuilder.buildGlobalVariables
.mockResolvedValueOnce(mockedGlobalVariables)
.mockResolvedValueOnce(mockedGlobalVariables);

expect(await node.isValidTx(doubleSpendWithExistingTx)).toBe(true);

// We make a nullifier from `doubleSpendWithExistingTx` a part of the nullifier tree, so it gets rejected as double spend
Expand All @@ -134,27 +112,13 @@ describe('aztec node', () => {
});

expect(await node.isValidTx(doubleSpendWithExistingTx)).toBe(false);
lastBlockNumber = 0;
});

it('tests that the node correctly validates chain id', async () => {
const tx = mockTxForRollup(0x10000);
tx.data.constants.txContext.chainId = chainId;

const mockedGlobalVariables = new GlobalVariables(
chainId,
version,
new Fr(lastBlockNumber + 1),
new Fr(1),
Fr.ZERO,
coinbase,
feeRecipient,
gasFees,
);

globalVariablesBuilder.buildGlobalVariables
.mockResolvedValueOnce(mockedGlobalVariables)
.mockResolvedValueOnce(mockedGlobalVariables);

expect(await node.isValidTx(tx)).toBe(true);

// We make the chain id on the tx not equal to the configured chain id
Expand Down Expand Up @@ -185,21 +149,7 @@ describe('aztec node', () => {
toBuffer: () => Fr.ZERO.toBuffer(),
};

const mockedGlobalVariables = new GlobalVariables(
chainId,
version,
new Fr(lastBlockNumber + 5),
new Fr(1),
Fr.ZERO,
coinbase,
feeRecipient,
gasFees,
);

globalVariablesBuilder.buildGlobalVariables
.mockResolvedValueOnce(mockedGlobalVariables)
.mockResolvedValueOnce(mockedGlobalVariables)
.mockResolvedValueOnce(mockedGlobalVariables);
lastBlockNumber = 3;

// Default tx with no max block number should be valid
expect(await node.isValidTx(noMaxBlockNumberMetadata)).toBe(true);
Expand Down
50 changes: 25 additions & 25 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
TxReceipt,
TxStatus,
type TxValidator,
type WorldStateSynchronizer,
partitionReverts,
} from '@aztec/circuit-types';
import {
Expand All @@ -52,20 +53,22 @@ import { createDebugLogger } from '@aztec/foundation/log';
import { Timer } from '@aztec/foundation/timer';
import { openTmpStore } from '@aztec/kv-store/utils';
import { SHA256Trunc, StandardTree, UnbalancedTree } from '@aztec/merkle-tree';
import { InMemoryAttestationPool, type P2P, createP2PClient } from '@aztec/p2p';
import { getCanonicalClassRegisterer } from '@aztec/protocol-contracts/class-registerer';
import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice';
import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer';
import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry';
import { getCanonicalMultiCallEntrypointAddress } from '@aztec/protocol-contracts/multi-call-entrypoint';
import {
AggregateTxValidator,
DataTxValidator,
DoubleSpendTxValidator,
GlobalVariableBuilder,
InMemoryAttestationPool,
MetadataTxValidator,
SequencerClient,
} from '@aztec/sequencer-client';
type P2P,
TxProofValidator,
createP2PClient,
} from '@aztec/p2p';
import { getCanonicalClassRegisterer } from '@aztec/protocol-contracts/class-registerer';
import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice';
import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer';
import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry';
import { getCanonicalMultiCallEntrypointAddress } from '@aztec/protocol-contracts/multi-call-entrypoint';
import { GlobalVariableBuilder, SequencerClient } from '@aztec/sequencer-client';
import { PublicProcessorFactory, WASMSimulator, WorldStateDB, createSimulationProvider } from '@aztec/simulator';
import { type TelemetryClient } from '@aztec/telemetry-client';
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
Expand All @@ -76,11 +79,10 @@ import {
type ProtocolContractAddresses,
} from '@aztec/types/contracts';
import { createValidatorClient } from '@aztec/validator-client';
import { type WorldStateSynchronizer, createWorldStateSynchronizer } from '@aztec/world-state';
import { createWorldStateSynchronizer } from '@aztec/world-state';

import { type AztecNodeConfig, getPackageInfo } from './config.js';
import { NodeMetrics } from './node_metrics.js';
import { TxProofValidator } from './tx_validator/tx_proof_validator.js';

/**
* The aztec node.
Expand Down Expand Up @@ -145,17 +147,23 @@ export class AztecNodeService implements AztecNode {
// this may well change in future
config.transactionProtocol = `/aztec/tx/${config.l1Contracts.rollupAddress.toString()}`;

// create the tx pool and the p2p client, which will need the l2 block source
const p2pClient = await createP2PClient(config, new InMemoryAttestationPool(), archiver, telemetry);

// now create the merkle trees and the world state synchronizer
const worldStateSynchronizer = await createWorldStateSynchronizer(config, archiver, telemetry);
const proofVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();

// create the tx pool and the p2p client, which will need the l2 block source
const p2pClient = await createP2PClient(
config,
new InMemoryAttestationPool(),
archiver,
proofVerifier,
worldStateSynchronizer,
telemetry,
);

// start both and wait for them to sync from the block source
await Promise.all([p2pClient.start(), worldStateSynchronizer.start()]);

const proofVerifier = config.realProofs ? await BBCircuitVerifier.new(config) : new TestCircuitVerifier();

const simulationProvider = await createSimulationProvider(config, log);

const validatorClient = createValidatorClient(config, p2pClient);
Expand Down Expand Up @@ -749,20 +757,12 @@ export class AztecNodeService implements AztecNode {

public async isValidTx(tx: Tx, isSimulation: boolean = false): Promise<boolean> {
const blockNumber = (await this.blockSource.getBlockNumber()) + 1;

const newGlobalVariables = await this.globalVariableBuilder.buildGlobalVariables(
new Fr(blockNumber),
// We only need chainId and block number, thus coinbase and fee recipient can be set to 0.
EthAddress.ZERO,
AztecAddress.ZERO,
);

// These validators are taken from the sequencer, and should match.
// The reason why `phases` and `gas` tx validator is in the sequencer and not here is because
// those tx validators are customizable by the sequencer.
const txValidators: TxValidator<Tx | ProcessedTx>[] = [
new DataTxValidator(),
new MetadataTxValidator(newGlobalVariables),
new MetadataTxValidator(new Fr(this.l1ChainId), new Fr(blockNumber)),
new DoubleSpendTxValidator(new WorldStateDB(this.worldStateSynchronizer.getLatest())),
];

Expand Down
21 changes: 21 additions & 0 deletions yarn-project/circuit-types/src/global_variable_builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { AztecAddress, EthAddress, Fr, GlobalVariables } from '@aztec/circuits.js';

/**
* Interface for building global variables for Aztec blocks.
*/
export interface GlobalVariableBuilder {
/**
* Builds global variables for a given block.
* @param blockNumber - The block number to build global variables for.
* @param coinbase - The address to receive block reward.
* @param feeRecipient - The address to receive fees.
* @param slotNumber - Optional. The slot number to use for the global variables. If undefined, it will be calculated.
* @returns A promise that resolves to the GlobalVariables for the given block number.
*/
buildGlobalVariables(
blockNumber: Fr,
coinbase: EthAddress,
feeRecipient: AztecAddress,
slotNumber?: bigint,
): Promise<GlobalVariables>;
}
1 change: 1 addition & 0 deletions yarn-project/circuit-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from './tx/index.js';
export * from './tx_effect.js';
export * from './tx_execution_request.js';
export * from './p2p/index.js';
export * from './global_variable_builder.js';
1 change: 1 addition & 0 deletions yarn-project/circuit-types/src/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export * from './server_circuit_prover.js';
export * from './private_kernel_prover.js';
export * from './tx-provider.js';
export * from './merkle_tree_operations.js';
export * from './world_state.js';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type MerkleTreeAdminOperations, type MerkleTreeOperations } from '../world-state-db/index.js';
import type { MerkleTreeAdminOperations, MerkleTreeOperations } from './merkle_tree_operations.js';

/**
* Defines the possible states of the world state synchronizer.
Expand Down
Loading
Loading