Skip to content

Commit

Permalink
wip: [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
just-mitch committed Mar 23, 2024
1 parent efa0842 commit cdd0d2b
Show file tree
Hide file tree
Showing 20 changed files with 862 additions and 78 deletions.
65 changes: 40 additions & 25 deletions l1-contracts/src/core/libraries/decoders/TxsDecoder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,38 @@ import {Hash} from "../Hash.sol";
* -------------------
* L2 Body Data Specification
* -------------------
* | byte start | num bytes | name
* | --- | --- | ---
* | 0x0 | 0x4 | len(numTxs) (denoted t)
* | | | TxEffect 0 {
* | 0x4 | 0x1 | len(newNoteHashes) (denoted b)
* | 0x4 + 0x1 | b * 0x20 | newNoteHashes
* | 0x4 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c)
* | 0x4 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers
* | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d)
* | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs
* | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e)
* | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites
* | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f)
* | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs
* | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g)
* | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs
* | | | },
* | | | TxEffect 1 {
* | | | ...
* | | | },
* | | | ...
* | | | TxEffect (t - 1) {
* | | | ...
* | | | },
* | byte start | num bytes | name
* | --- | --- | ---
* | 0x0 | 0x4 | len(numTxs) (denoted t)
* | | | TxEffect 0 {
* | 0x4 | 0x8 | daGasUsed
* | 0x4 + 0x8 | 0x8 | computeGasUsed
* | 0x4 + 0x8 + 0x8 | 0x1 | revertCode
* | 0x4 + 0x8 + 0x8 + 0x1 | 0x1 | len(newNoteHashes) (denoted b)
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 | b * 0x20 | newNoteHashes
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c)
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d)
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e)
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f)
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g)
* | 0x4 + 0x8 + 0x8 + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs
* | | | },
* | | | TxEffect 1 {
* | | | ...
* | | | },
* | | | ...
* | | | TxEffect (t - 1) {
* | | | ...
* | | | },
*/
library TxsDecoder {
struct ArrayOffsets {
uint256 daGasUsed;
uint256 computeGasUsed;
uint256 revertCode;
uint256 noteHash;
uint256 nullifier;
Expand Down Expand Up @@ -105,6 +110,14 @@ library TxsDecoder {
* Zero values.
*/

// daGasUsed
offsets.daGasUsed = offset;
offset += 0x8;

// computeGasUsed
offsets.computeGasUsed = offset;
offset += 0x8;

// Revert Code
offsets.revertCode = offset;
offset += 0x1;
Expand Down Expand Up @@ -146,7 +159,9 @@ library TxsDecoder {

// Insertions are split into multiple `bytes.concat` to work around stack too deep.
vars.baseLeaf = bytes.concat(
// pad the revert code to 32 bytes to match the hash preimage
// pad these values to 32 bytes to match the hash preimage
sliceAndPadLeft(_body, offsets.daGasUsed, 0x8, 0x20),
sliceAndPadLeft(_body, offsets.computeGasUsed, 0x8, 0x20),
sliceAndPadLeft(_body, offsets.revertCode, 0x1, 0x20),
bytes.concat(
sliceAndPadRight(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod base_rollup_inputs;
mod state_diff_hints;
mod calldata_gas;

use base_rollup_inputs::BaseRollupInputs;
use crate::abis::base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use dep::types::abis::accumulated_data::CombinedAccumulatedData;
use dep::types::abis::side_effect::{SideEffect, SideEffectLinkedToNoteHash};
use dep::types::traits::is_empty;
use dep::types::constants::{
MAX_NEW_NULLIFIERS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX,
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
};

global FIXED_DA_GAS: u64 = 272;
global DA_GAS_PER_BYTE: u64 = 16;

pub fn compute_calldata_da_gas(data: CombinedAccumulatedData) -> u64 {
let mut non_zero_bytes = (data.unencrypted_log_preimages_length + data.encrypted_log_preimages_length) as u64;

for i in 0..MAX_NEW_NOTE_HASHES_PER_TX {
if !is_empty(data.new_note_hashes[i]) {
non_zero_bytes += 32;
}
}

for i in 0..MAX_NEW_NULLIFIERS_PER_TX {
if !is_empty(data.new_nullifiers[i]) {
non_zero_bytes += 32;
}
}

for i in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX {
if !is_empty(data.new_l2_to_l1_msgs[i]) {
non_zero_bytes += 32;
}
}

for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX {
if !is_empty(data.public_data_update_requests[i]) {
non_zero_bytes += 64;
}
}

non_zero_bytes * DA_GAS_PER_BYTE + FIXED_DA_GAS
}

pub fn compute_calldata_compute_gas(data: CombinedAccumulatedData) -> u64 {
data.compute_gas_used
}

mod tests {

use dep::types::abis::accumulated_data::{CombinedAccumulatedDataBuilder, CombinedAccumulatedData};

use crate::base::calldata_gas::compute_calldata_da_gas;

#[test]
fn test_compute_calldata_gas() {
let mut builder: CombinedAccumulatedDataBuilder = dep::std::unsafe::zeroed();
builder.unencrypted_log_preimages_length = 4;
builder.encrypted_log_preimages_length = 4;
let data = builder.finish();
// see calldata_tx_effect_factory.test.ts for the expected value
assert_eq(compute_calldata_da_gas(data), 400);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use crate::{
call_request::CallRequest, caller_context::CallerContext,
public_data_update_request::PublicDataUpdateRequest,
side_effect::{SideEffect, SideEffectLinkedToNoteHash}
}
},
traits::Empty
};
use crate::constants::{
MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX,
Expand All @@ -21,6 +22,9 @@ use crate::traits::is_empty;
use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec};

struct CombinedAccumulatedData {
da_gas_used: u64,
compute_gas_used: u64,

revert_code: u8,

new_note_hashes: [SideEffect; MAX_NEW_NOTE_HASHES_PER_TX],
Expand Down Expand Up @@ -52,6 +56,8 @@ impl CombinedAccumulatedData {
revertible: PublicAccumulatedRevertibleData
) -> CombinedAccumulatedData {
CombinedAccumulatedData {
da_gas_used: 0,
compute_gas_used: 1,
revert_code: non_revertible.revert_code,
new_note_hashes: array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes),
new_nullifiers: array_concat(non_revertible.new_nullifiers, revertible.new_nullifiers),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ impl CombinedAccumulatedDataBuilder {

pub fn finish(self) -> CombinedAccumulatedData {
CombinedAccumulatedData {
da_gas_used: 0,
compute_gas_used: 1,
revert_code: self.revert_code,
new_note_hashes: self.new_note_hashes.storage,
new_nullifiers: self.new_nullifiers.storage,
Expand Down
12 changes: 12 additions & 0 deletions yarn-project/circuit-types/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { Config } from 'jest';

const config: Config = {
preset: 'ts-jest/presets/default-esm',
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.[cm]?js$': '$1',
},
testRegex: './src/.*\\.test\\.(js|mjs|ts)$',
rootDir: './src',
};

export default config;
11 changes: 0 additions & 11 deletions yarn-project/circuit-types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,6 @@
"formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src",
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests"
},
"inherits": [
"../package.common.json"
],
"jest": {
"preset": "ts-jest/presets/default-esm",
"moduleNameMapper": {
"^(\\.{1,2}/.*)\\.[cm]?js$": "$1"
},
"testRegex": "./src/.*\\.test\\.(js|mjs|ts)$",
"rootDir": "./src"
},
"dependencies": {
"@aztec/circuits.js": "workspace:^",
"@aztec/ethereum": "workspace:^",
Expand Down
34 changes: 34 additions & 0 deletions yarn-project/circuit-types/src/calldata_tx_effect_factory.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
Fr,
MAX_NEW_L2_TO_L1_MSGS_PER_TX,
MAX_NEW_NOTE_HASHES_PER_TX,
MAX_NEW_NULLIFIERS_PER_TX,
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
RevertCode,
} from '@aztec/circuits.js';
import { makeTuple } from '@aztec/foundation/array';

import { CalldataTxEffectFactory, DA_BYTE_GAS, FIXED_DA_GAS, TxL2Logs } from './index.js';
import { PublicDataWrite } from './public_data_write.js';
import { ITxEffectWithoutGasUsed } from './tx_effect.js';

describe('calldata_tx_effect_factory', () => {
it('correctly calculates DA gas for empty TxEffect', () => {
const effect: ITxEffectWithoutGasUsed = {
revertCode: RevertCode.OK,
noteHashes: makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, Fr.zero),
nullifiers: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero),
l2ToL1Msgs: makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero),
publicDataWrites: makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite.empty),
encryptedLogs: TxL2Logs.empty(),
unencryptedLogs: TxL2Logs.empty(),
};

const gasUsed = CalldataTxEffectFactory.build(effect).daGasUsed;

// 4n for each log, due to encoding of the length of the logs
expect(gasUsed.value).toEqual(FIXED_DA_GAS + 4n * DA_BYTE_GAS + 4n * DA_BYTE_GAS);
});

// TODO(@just-mitch) more tests please
});
78 changes: 78 additions & 0 deletions yarn-project/circuit-types/src/calldata_tx_effect_factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { Fr, GasUsed, RevertCode } from '@aztec/circuits.js';
import { arrayNonEmptyLength } from '@aztec/foundation/collection';

import { PublicDataWrite } from './public_data_write.js';
import { GasProfiler, GasType, ITxEffectWithoutGasUsed, TxEffect, TxEffectFactory } from './tx_effect.js';

export const DA_BYTE_GAS = 16n;

export const FIXED_BYTES = // 17 bytes
GasUsed.PACKED_SIZE_IN_BYTES + // da_gas_used
GasUsed.PACKED_SIZE_IN_BYTES + // compute_gas_used
RevertCode.PACKED_SIZE_IN_BYTES; // revert_code

export const FIXED_DA_GAS = FIXED_BYTES * DA_BYTE_GAS; // 272n

const getComputeGasUsed = (_effect: ITxEffectWithoutGasUsed) => {
// Just a dummy for now
return new GasUsed(1n);
};

/**
* Note. This does not exactly match ethereum calldata cost.
* It is correlated, but simplified to ease circuit calculations:
* We don't want to bitwise deconstruct the calldata to count the non-zero bytes in the circuit.
*
* We overcompensate by
* - assuming our FIXED_BYTE "header" is always non-zero.
* - assuming there is no zero byte in any non-zero field
*
* We undercompensate by
* - not counting the bytes used to store the lengths of the various arrays
*
* @param effect the TxEffect to calculate the DA gas used for
* @returns our interpretation of the DA gas used
*/
const getDAGasUsed = (effect: ITxEffectWithoutGasUsed) => {
const nonEmptyFields =
arrayNonEmptyLength(effect.noteHashes, Fr.isZero) +
arrayNonEmptyLength(effect.nullifiers, Fr.isZero) +
arrayNonEmptyLength(effect.l2ToL1Msgs, Fr.isZero) +
2 * arrayNonEmptyLength(effect.publicDataWrites, PublicDataWrite.isEmpty);

const gasUsed =
FIXED_DA_GAS +
DA_BYTE_GAS *
BigInt(
Fr.SIZE_IN_BYTES * nonEmptyFields +
effect.encryptedLogs.getSerializedLength() +
effect.unencryptedLogs.getSerializedLength(),
);

return new GasUsed(gasUsed);
};

const gasProfiler: GasProfiler = (effect: ITxEffectWithoutGasUsed) => {
return {
[GasType.DA]: getDAGasUsed(effect),
[GasType.COMPUTE]: getComputeGasUsed(effect),
};
};

export const CalldataTxEffectFactory: TxEffectFactory = {
gasProfiler,
build(effect: ITxEffectWithoutGasUsed) {
const { [GasType.DA]: daGasUsed, [GasType.COMPUTE]: computeGasUsed } = this.gasProfiler(effect);
return new TxEffect(
daGasUsed,
computeGasUsed,
effect.revertCode,
effect.noteHashes,
effect.nullifiers,
effect.l2ToL1Msgs,
effect.publicDataWrites,
effect.encryptedLogs,
effect.unencryptedLogs,
);
},
};
21 changes: 11 additions & 10 deletions yarn-project/circuit-types/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
export { CompleteAddress, GrumpkinPrivateKey, PartialAddress, PublicKey } from '@aztec/circuits.js';
export * from './auth_witness.js';
export * from './aztec_node/rpc/index.js';
export * from './body.js';
export * from './calldata_tx_effect_factory.js';
export * from './function_call.js';
export * from './interfaces/index.js';
export * from './keys/index.js';
export * from './notes/index.js';
export * from './messaging/index.js';
export * from './l2_block.js';
export * from './body.js';
export * from './l2_block_context.js';
export * from './l2_block_downloader/index.js';
export * from './l2_block_source.js';
export * from './tx_effect.js';
export * from './logs/index.js';
export * from './merkle_tree_id.js';
export * from './messaging/index.js';
export * from './mocks.js';
export * from './notes/index.js';
export * from './packed_arguments.js';
export * from './public_data_write.js';
export * from './simulation_error.js';
export * from './sibling_path/index.js';
export * from './simulation_error.js';
export * from './tx/index.js';
export * from './tx_effect.js';
export * from './tx_execution_request.js';
export * from './packed_arguments.js';
export * from './interfaces/index.js';
export * from './auth_witness.js';
export * from './aztec_node/rpc/index.js';
export { CompleteAddress, PublicKey, PartialAddress, GrumpkinPrivateKey } from '@aztec/circuits.js';
Loading

0 comments on commit cdd0d2b

Please sign in to comment.