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 21 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
112 changes: 112 additions & 0 deletions .github/workflows/sepolia-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Deploy to Sepolia network
on:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
IMAGE_TAG: latest
DEPLOY_TAG: sepolianet
CONTRACT_S3_BUCKET: s3://static.aztec.network

# TF Variables
TF_VAR_IMAGE_TAG: latest
TF_VAR_DEPLOY_TAG: sepolianet
TF_VAR_L1_CHAIN_ID: 11155111
TF_VAR_ETHEREUM_HOST: https://sepolia.infura.io/v3/${{ secrets.SEPOLIA_API_KEY }}
TF_VAR_PROVING_ENABLED: false
TF_VAR_API_KEY: ${{ secrets.SEPOLIANET_API_KEY }}
# Node / Sequencer
TF_VAR_BOOTSTRAP_NODES: ""
TF_VAR_P2P_ENABLED: "false"
TF_VAR_NODE_P2P_PRIVATE_KEYS: '[""]'
TF_VAR_SEQ_MIN_TX_PER_BLOCK: 1
TF_VAR_SEQ_MAX_TX_PER_BLOCK: 64
TF_VAR_NODE_LB_RULE_PRIORITY: 7000
TF_VAR_NODE_P2P_TCP_PORT: 40500
TF_VAR_NODE_P2P_UDP_PORT: 45500
# Address 0x652575Ff941e7c2850fB89f2B207efF6B06BC7B4
TF_VAR_SEQUENCER_PRIVATE_KEYS: '["${{ secrets.SEPOLIA_SEQ_PRIVATE_KEY }}"]'

# Prover Node
TF_VAR_PROVER_NODE_LB_RULE_PRIORITY: 7100
# Address 0xE3b8F9F23b8D4BD7d437218Bff3bcED1ce5E70B3
TF_VAR_PROVER_PRIVATE_KEYS: '["${{ secrets.SEPOLIA_PROVER_PRIVATE_KEY }}"]'

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: "${{ github.sha }}"

- uses: ./.github/ci-setup-action

- uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.7.5

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-west-2

- name: Deploy L1 Contracts to Sepolia
run: |
set -e
docker pull aztecprotocol/aztec:${{ env.IMAGE_TAG }}
docker run aztecprotocol/aztec:${{ env.IMAGE_TAG }} deploy-l1-contracts \
--private-key ${{ secrets.SEPOLIA_SEQ_PRIVATE_KEY }} \
--rpc-url ${{ env.TF_VAR_ETHEREUM_HOST }} \
--l1-chain-id ${{ env.TF_VAR_L1_CHAIN_ID }} \
--salt ${{ github.run_id }} \
--json | tee ./l1_contracts.json

# upload contract addresses to S3
aws s3 cp ./l1_contracts.json ${{ env.CONTRACT_S3_BUCKET }}/${{ env.DEPLOY_TAG }}/l1_contracts.json

# export contract addresses so they can be used by subsequent terraform deployments
function extract() {
jq -r ".$1" ./l1_contracts.json
}

echo "TF_VAR_ROLLUP_CONTRACT_ADDRESS=$(extract rollupAddress)" >>$GITHUB_ENV
echo "TF_VAR_REGISTRY_CONTRACT_ADDRESS=$(extract registryAddress)" >>$GITHUB_ENV
echo "TF_VAR_INBOX_CONTRACT_ADDRESS=$(extract inboxAddress)" >>$GITHUB_ENV
echo "TF_VAR_OUTBOX_CONTRACT_ADDRESS=$(extract outboxAddress)" >>$GITHUB_ENV
echo "TF_VAR_AVAILABILITY_ORACLE_CONTRACT_ADDRESS=$(extract availabilityOracleAddress)" >>$GITHUB_ENV
echo "TF_VAR_FEE_JUICE_CONTRACT_ADDRESS=$(extract feeJuiceAddress)" >>$GITHUB_ENV
echo "TF_VAR_FEE_JUICE_PORTAL_CONTRACT_ADDRESS=$(extract feeJuicePortalAddress)" >>$GITHUB_ENV

- name: Apply l1-contracts Terraform
working-directory: ./l1-contracts/terraform
run: |
env
terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/l1-contracts"
terraform apply -input=false -auto-approve

- name: Deploy Aztec Node
working-directory: ./yarn-project/aztec/terraform/node
run: |
terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/aztec-node"
terraform apply -input=false -auto-approve

- name: Deploy Aztec Prover Node
working-directory: ./yarn-project/aztec/terraform/prover-node
run: |
terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/aztec-prover-node"
terraform apply -input=false -auto-approve

- name: Deploy PXE
working-directory: ./yarn-project/aztec/terraform/pxe
run: |
terraform init -input=false -backend-config="key=${{ env.DEPLOY_TAG }}/pxe"
terraform apply -input=false -auto-approve -replace="aws_efs_file_system.pxe_data_store"
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 @@ -79,7 +75,7 @@ describe('aztec node', () => {
l1ToL2MessageSource,
worldState,
undefined,
31337,
12345,
1,
globalVariablesBuilder,
new TestCircuitVerifier(),
Expand All @@ -95,21 +91,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 @@ -118,10 +100,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 @@ -133,27 +111,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 @@ -184,21 +148,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 @@ -144,17 +146,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 @@ -748,20 +756,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
Loading
Loading