Skip to content

Commit

Permalink
test: testing all values in PublicGlobalVariables and `PrivateGloba…
Browse files Browse the repository at this point in the history
…lVariables` (AztecProtocol#4481)

Expanding tests of global variables
  • Loading branch information
benesjan authored Feb 8, 2024
1 parent 6d9c73a commit bc25f9b
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 87 deletions.
23 changes: 18 additions & 5 deletions yarn-project/noir-contracts/contracts/test_contract/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,27 @@ contract Test {
storage.example_constant.initialize(&mut note, false);
}

#[aztec(public)]
fn assert_coinbase(coinbase: EthAddress) {
assert(context.coinbase().eq(coinbase), "Invalid coinbase");
#[aztec(private)]
fn assert_private_global_vars(chain_id: Field, version: Field) {
assert(context.chain_id() == chain_id, "Invalid chain id");
assert(context.version() == version, "Invalid version");
}

#[aztec(public)]
fn assert_fee_recipient(fee_recipient: AztecAddress) {
assert(context.fee_recipient().eq(fee_recipient), "Invalid fee recipient");
fn assert_public_global_vars(
chain_id: Field,
version: Field,
block_number: Field,
timestamp: Field,
coinbase: EthAddress,
fee_recipient: AztecAddress
) {
assert(context.chain_id() == chain_id, "Invalid chain id");
assert(context.version() == version, "Invalid version");
assert(context.block_number() == block_number, "Invalid block number");
assert(context.timestamp() == timestamp, "Invalid timestamp");
assert(context.coinbase() == coinbase, "Invalid coinbase");
assert(context.fee_recipient() == fee_recipient, "Invalid fee recipient");
}

unconstrained fn get_constant() -> pub Field {
Expand Down
37 changes: 37 additions & 0 deletions yarn-project/simulator/src/client/private_execution.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1129,4 +1129,41 @@ describe('Private Execution test suite', () => {
expect(result.returnValues).toEqual(portalContractAddress.toField().value);
});
});

describe('Private global variables', () => {
let chainId: Fr;
let version: Fr;
let args: any[];
let artifact: FunctionArtifact;

beforeAll(() => {
chainId = Fr.random();
version = Fr.random();
args = [chainId, version];

artifact = getFunctionArtifact(TestContractArtifact, 'assert_private_global_vars');
oracle.getFunctionArtifact.mockImplementation(() => Promise.resolve(artifact));
});

it('Private global vars are correctly set', () => {
// Chain id and version set in tx context is the same as the ones we pass via args so this should not throw
expect(() => runSimulator({ artifact, msgSender: owner, args, txContext: { chainId, version } })).not.toThrow();
});

it('Throws when chainId is incorrectly set', async () => {
// We set the chainId in the tx context to a different value than the one we pass via args so the simulator should throw
const unexpectedChainId = Fr.random();
await expect(
runSimulator({ artifact, msgSender: owner, args, txContext: { chainId: unexpectedChainId, version } }),
).rejects.toThrowError('Invalid chain id');
});

it('Throws when version is incorrectly set', async () => {
// We set the version in the tx context to a different value than the one we pass via args so the simulator should throw
const unexpectedVersion = Fr.random();
await expect(
runSimulator({ artifact, msgSender: owner, args, txContext: { chainId, version: unexpectedVersion } }),
).rejects.toThrowError('Invalid version');
});
});
});
144 changes: 62 additions & 82 deletions yarn-project/simulator/src/public/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,7 @@ describe('ACIR public execution simulator', () => {
const initialValue = 3n;

const functionData = new FunctionData(parentEntryPointFnSelector, isInternal ?? false, false, false);
const args = encodeArguments(parentEntryPointFn, [
childContractAddress.toField(),
childValueFnSelector.toField(),
initialValue,
]);
const args = encodeArguments(parentEntryPointFn, [childContractAddress, childValueFnSelector, initialValue]);

const callContext = CallContext.from({
msgSender: AztecAddress.random(),
Expand Down Expand Up @@ -311,7 +307,7 @@ describe('ACIR public execution simulator', () => {
const msgSender = AztecAddress.random();
const secretHash = Fr.random();

const args = encodeArguments(shieldArtifact, [msgSender.toField(), amount, secretHash, Fr.ZERO]);
const args = encodeArguments(shieldArtifact, [msgSender, amount, secretHash, Fr.ZERO]);

const callContext = CallContext.from({
msgSender: msgSender,
Expand Down Expand Up @@ -436,9 +432,9 @@ describe('ACIR public execution simulator', () => {

const computeArgs = () =>
encodeArguments(mintPublicArtifact, [
tokenRecipient.toField(),
tokenRecipient,
bridgedAmount,
canceller.toField(),
canceller,
messageKey ?? preimage.hash(),
secret,
]);
Expand Down Expand Up @@ -636,6 +632,14 @@ describe('ACIR public execution simulator', () => {
describe('Global variables in public context', () => {
let contractAddress: AztecAddress;
let callContext: CallContext;
let assertGlobalVarsArtifact: FunctionArtifact;
let functionData: FunctionData;

const modifyGlobalVariables = (globalVariables: GlobalVariables, propertyIndex: number, value: any) => {
const globalVariablesFields = GlobalVariables.getFields(globalVariables) as unknown as any[];
globalVariablesFields[propertyIndex] = value;
return GlobalVariables.fromFields(globalVariablesFields);
};

beforeAll(() => {
contractAddress = AztecAddress.random();
Expand All @@ -649,92 +653,68 @@ describe('ACIR public execution simulator', () => {
isStaticCall: false,
startSideEffectCounter: 0,
});
assertGlobalVarsArtifact = TestContractArtifact.functions.find(f => f.name === 'assert_public_global_vars')!;
functionData = FunctionData.fromAbi(assertGlobalVarsArtifact);
});

const computeGlobalVariables = (coinbase: EthAddress, feeRecipient: AztecAddress) =>
new GlobalVariables(new Fr(1), new Fr(2), Fr.ZERO, Fr.ZERO, coinbase, feeRecipient);

describe('Coinbase', () => {
let expectedCoinbase: EthAddress;
let globalVariables: GlobalVariables;
let assertCoinbaseArtifact: FunctionArtifact;
let functionData: FunctionData;

beforeAll(() => {
expectedCoinbase = EthAddress.random();
globalVariables = computeGlobalVariables(expectedCoinbase, AztecAddress.random());

assertCoinbaseArtifact = TestContractArtifact.functions.find(f => f.name === 'assert_coinbase')!;
functionData = FunctionData.fromAbi(assertCoinbaseArtifact);
});

beforeEach(() => {
publicContracts.getBytecode.mockResolvedValue(Buffer.from(assertCoinbaseArtifact.bytecode, 'base64'));
});

it('Valid', () => {
// We set the coinbase function arg to one we set in global vars
const args = encodeArguments(assertCoinbaseArtifact, [expectedCoinbase]);

const execution: PublicExecution = { contractAddress, functionData, args, callContext };
executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header);

// Now we check that the global vars value was correctly set by checking if the assert func throws
expect(() => executor.simulate(execution, globalVariables)).not.toThrow();
});

it('Invalid', async () => {
// We set the coinbase function arg to a random invalid value
const invalidCoinbase = EthAddress.random();
const args = encodeArguments(assertCoinbaseArtifact, [invalidCoinbase]);

const execution: PublicExecution = { contractAddress, functionData, args, callContext };
executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header);

// Now we check that the function throws in case of invalid coinbase
await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Invalid coinbase');
});
beforeEach(() => {
publicContracts.getBytecode.mockResolvedValue(Buffer.from(assertGlobalVarsArtifact.bytecode, 'base64'));
});

describe('Fee recipient', () => {
let expectedFeeRecipient: AztecAddress;
let globalVariables: GlobalVariables;
let assertFeeRecipientArtifact: FunctionArtifact;
let functionData: FunctionData;
// Note: Order here has to match the order of the properties in GlobalVariables.getFields(...) function.
const testCases = [
{ value: new Fr(1), invalidValue: Fr.random(), description: 'Chain ID' },
{ value: new Fr(1), invalidValue: Fr.random(), description: 'Version' },
{ value: new Fr(1), invalidValue: Fr.random(), description: 'Block number' },
{ value: new Fr(1), invalidValue: Fr.random(), description: 'Timestamp' },
{ value: EthAddress.random(), invalidValue: EthAddress.random(), description: 'Coinbase' },
{
value: AztecAddress.random(),
invalidValue: AztecAddress.random(),
description: 'Fee recipient',
},
];

beforeAll(() => {
expectedFeeRecipient = AztecAddress.random();
globalVariables = computeGlobalVariables(EthAddress.random(), expectedFeeRecipient);
testCases.forEach(({ value, invalidValue, description }, i: number) => {
describe(`${description}`, () => {
let globalVariables: GlobalVariables;

assertFeeRecipientArtifact = TestContractArtifact.functions.find(f => f.name === 'assert_fee_recipient')!;
functionData = FunctionData.fromAbi(assertFeeRecipientArtifact);
});

beforeEach(() => {
publicContracts.getBytecode.mockResolvedValue(Buffer.from(assertFeeRecipientArtifact.bytecode, 'base64'));
});
beforeAll(() => {
// We create a new global variables object containing non-zero value in place of the tested property
globalVariables = modifyGlobalVariables(GlobalVariables.empty(), i, value);
});

it('Valid', () => {
// We set the fee recipient function arg to one we set in global vars
const args = encodeArguments(assertFeeRecipientArtifact, [expectedFeeRecipient]);
it('Valid', () => {
let args: Fr[];
{
// We create the args by just serializing the reference global variables object
const rawArgs = GlobalVariables.getFields(globalVariables) as unknown as any[];
args = encodeArguments(assertGlobalVarsArtifact, rawArgs);
}

const execution: PublicExecution = { contractAddress, functionData, args, callContext };
executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header);
const execution: PublicExecution = { contractAddress, functionData, args, callContext };
executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header);

// Now we check that the global vars value was correctly set by checking if the assert func throws
expect(() => executor.simulate(execution, globalVariables)).not.toThrow();
});
expect(() => executor.simulate(execution, globalVariables)).not.toThrow();
});

it('Invalid', async () => {
// We set the fee recipient function arg to a random invalid value
const invalidFeeRecipient = AztecAddress.random();
const args = encodeArguments(assertFeeRecipientArtifact, [invalidFeeRecipient]);
it('Invalid', async () => {
let args: Fr[];
{
// We create the args by modifying the global variables object to contain an invalid value in place of
// the tested property
const modifiedGlobalVariables = modifyGlobalVariables(globalVariables, i, invalidValue);
const rawArgs = GlobalVariables.getFields(modifiedGlobalVariables) as unknown as any[];
args = encodeArguments(assertGlobalVarsArtifact, rawArgs);
}

const execution: PublicExecution = { contractAddress, functionData, args, callContext };
executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header);
const execution: PublicExecution = { contractAddress, functionData, args, callContext };
executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header);

// Now we check that the function throws in case of invalid fee recipient
await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Invalid fee recipient');
await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError(
`Invalid ${description.toLowerCase()}`,
);
});
});
});
});
Expand Down

0 comments on commit bc25f9b

Please sign in to comment.