forked from visoftsolutions/noir_rs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: avm executor - layout and groundwork (AztecProtocol#3928)
- Loading branch information
Showing
28 changed files
with
1,042 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,3 +12,5 @@ cmake-build-debug | |
|
||
# Local Netlify folder | ||
.netlify | ||
|
||
.graphite* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
describe('Avm', () => { | ||
it('Executes a simple call', () => {}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
import { AvmMachineState } from './avm_machine_state.js'; | ||
import { AvmMessageCallResult } from './avm_message_call_result.js'; | ||
import { AvmStateManager } from './avm_state_manager.js'; | ||
import { AvmInterpreter } from './interpreter/index.js'; | ||
import { interpretBytecode } from './opcodes/from_bytecode.js'; | ||
import { Instruction } from './opcodes/index.js'; | ||
|
||
/** | ||
* Avm Executor manages the execution of the AVM | ||
* | ||
* It stores a state manager | ||
*/ | ||
export class AvmContext { | ||
private stateManager: AvmStateManager; | ||
|
||
constructor(stateManager: AvmStateManager) { | ||
this.stateManager = stateManager; | ||
} | ||
|
||
/** | ||
* Call a contract with the given calldata | ||
* | ||
* - We get the contract from storage | ||
* - We interpret the bytecode | ||
* - We run the interpreter | ||
* | ||
* @param contractAddress - | ||
* @param calldata - | ||
*/ | ||
public call(contractAddress: Fr, calldata: Fr[]): AvmMessageCallResult { | ||
// NOTE: the following is mocked as getPublicBytecode does not exist yet | ||
// const bytecode = stateManager.journal.hostStorage.contractsDb.getBytecode(contractAddress); | ||
const bytecode = Buffer.from('0x01000100020003'); | ||
|
||
const instructions: Instruction[] = interpretBytecode(bytecode); | ||
|
||
const context = new AvmMachineState(calldata); | ||
const interpreter = new AvmInterpreter(context, this.stateManager, instructions); | ||
|
||
return interpreter.run(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
/** | ||
* Store's data for an Avm execution frame | ||
*/ | ||
export class AvmMachineState { | ||
/** - */ | ||
public readonly calldata: Fr[]; | ||
private returnData: Fr[]; | ||
|
||
// TODO: implement tagged memory | ||
/** - */ | ||
public memory: Fr[]; | ||
|
||
/** - */ | ||
public pc: number; | ||
/** - */ | ||
public callStack: number[]; | ||
|
||
/** | ||
* Create a new avm context | ||
* @param calldata - | ||
*/ | ||
constructor(calldata: Fr[]) { | ||
this.calldata = calldata; | ||
this.returnData = []; | ||
this.memory = []; | ||
|
||
this.pc = 0; | ||
this.callStack = []; | ||
} | ||
|
||
/** | ||
* Return data must NOT be modified once it is set | ||
* @param returnData - | ||
*/ | ||
public setReturnData(returnData: Fr[]) { | ||
this.returnData = returnData; | ||
Object.freeze(returnData); | ||
} | ||
|
||
/** - */ | ||
public getReturnData(): Fr[] { | ||
return this.returnData; | ||
} | ||
|
||
/** - | ||
* @param offset - | ||
*/ | ||
public readMemory(offset: number): Fr { | ||
// TODO: check offset is within bounds | ||
return this.memory[offset] ?? Fr.ZERO; | ||
} | ||
|
||
/** - | ||
* @param offset - | ||
* @param size - | ||
*/ | ||
public readMemoryChunk(offset: number, size: number): Fr[] { | ||
// TODO: bounds -> initialise to 0 | ||
return this.memory.slice(offset, offset + size); | ||
} | ||
|
||
/** - | ||
* @param offset - | ||
* @param value - | ||
*/ | ||
public writeMemory(offset: number, value: Fr): void { | ||
this.memory[offset] = value; | ||
} | ||
|
||
/** - | ||
* @param offset - | ||
* @param values - | ||
*/ | ||
public writeMemoryChunk(offset: number, values: Fr[]): void { | ||
this.memory.splice(offset, values.length, ...values); | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
yarn-project/acir-simulator/src/avm/avm_message_call_result.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
/** | ||
* AVM message call result. | ||
*/ | ||
export class AvmMessageCallResult { | ||
/** - */ | ||
public readonly reverted: boolean; | ||
/** .- */ | ||
public readonly output: Fr[]; | ||
|
||
constructor(reverted: boolean, output: Fr[]) { | ||
this.reverted = reverted; | ||
this.output = output; | ||
} | ||
|
||
/** | ||
* Terminate a call as a success | ||
* @param output - Return data | ||
* @returns instance of AvmMessageCallResult | ||
*/ | ||
public static success(output: Fr[]): AvmMessageCallResult { | ||
return new AvmMessageCallResult(false, output); | ||
} | ||
|
||
/** | ||
* Terminate a call as a revert | ||
* @param output - Return data ( revert message ) | ||
* @returns instance of AvmMessageCallResult | ||
*/ | ||
public static revert(output: Fr[]): AvmMessageCallResult { | ||
return new AvmMessageCallResult(true, output); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { BlockHeader } from '@aztec/circuits.js'; | ||
|
||
import { AvmJournal, HostStorage } from './journal/index.js'; | ||
|
||
/** | ||
* The Avm State Manager is the interpreter's interface to the node's state | ||
* It creates revertible views into the node state and manages the current call's journal | ||
*/ | ||
export class AvmStateManager { | ||
/** - */ | ||
public readonly blockHeader: BlockHeader; | ||
|
||
/** | ||
* Journal keeps track of pending state changes | ||
*/ | ||
public readonly journal: AvmJournal; | ||
|
||
constructor(blockHeader: BlockHeader, journal: AvmJournal) { | ||
this.blockHeader = blockHeader; | ||
this.journal = journal; | ||
} | ||
|
||
/** | ||
* Create a base state root manager | ||
* - this should be created by the highest level item where the state | ||
* can be reverted | ||
* @param blockHeader - | ||
* @param hostStorage - An immutable view into the node db | ||
* @returns Avm State Manager | ||
*/ | ||
public static rootStateManager(blockHeader: BlockHeader, hostStorage: HostStorage): AvmStateManager { | ||
const journal = new AvmJournal(hostStorage); | ||
return new AvmStateManager(blockHeader, journal); | ||
} | ||
|
||
/** | ||
* Avm State | ||
* @param parent - Avm state manager with a forked journal | ||
* @returns | ||
*/ | ||
public static forkStateManager(parent: AvmStateManager): AvmStateManager { | ||
return new AvmStateManager(parent.blockHeader, parent.journal); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
// Place large AVM text fixtures in here |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './avm_machine_state.js'; | ||
export * from './avm_context.js'; | ||
export * from './avm_state_manager.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './interpreter.js'; |
37 changes: 37 additions & 0 deletions
37
yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
import { mock } from 'jest-mock-extended'; | ||
|
||
import { AvmMachineState } from '../avm_machine_state.js'; | ||
import { AvmStateManager } from '../avm_state_manager.js'; | ||
import { Add } from '../opcodes/arithmetic.js'; | ||
import { Return } from '../opcodes/control_flow.js'; | ||
import { Instruction } from '../opcodes/instruction.js'; | ||
import { CallDataCopy } from '../opcodes/memory.js'; | ||
import { AvmInterpreter } from './interpreter.js'; | ||
|
||
describe('interpreter', () => { | ||
it('Should execute a series of instructions', () => { | ||
const calldata: Fr[] = [new Fr(1), new Fr(2)]; | ||
const stateManager = mock<AvmStateManager>(); | ||
|
||
const instructions: Instruction[] = [ | ||
// Copy the first two elements of the calldata to memory regions 0 and 1 | ||
new CallDataCopy(0, 2, 0), | ||
// Add the two together and store the result in memory region 2 | ||
new Add(0, 1, 2), // 1 + 2 | ||
// Return the result | ||
new Return(2, 1), // [3] | ||
]; | ||
|
||
const context = new AvmMachineState(calldata); | ||
const interpreter = new AvmInterpreter(context, stateManager, instructions); | ||
const avmReturnData = interpreter.run(); | ||
|
||
expect(avmReturnData.reverted).toBe(false); | ||
|
||
const returnData = avmReturnData.output; | ||
expect(returnData.length).toBe(1); | ||
expect(returnData).toEqual([new Fr(3)]); | ||
}); | ||
}); |
54 changes: 54 additions & 0 deletions
54
yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// import { AvmContext } from "../avm_machineState.js"; | ||
import { Fr } from '@aztec/foundation/fields'; | ||
|
||
import { AvmMachineState } from '../avm_machine_state.js'; | ||
import { AvmMessageCallResult } from '../avm_message_call_result.js'; | ||
import { AvmStateManager } from '../avm_state_manager.js'; | ||
import { Instruction } from '../opcodes/index.js'; | ||
|
||
/** | ||
* Avm Interpreter | ||
* | ||
* Executes an Avm context | ||
*/ | ||
export class AvmInterpreter { | ||
private instructions: Instruction[] = []; | ||
private machineState: AvmMachineState; | ||
private stateManager: AvmStateManager; | ||
|
||
constructor(machineState: AvmMachineState, stateManager: AvmStateManager, bytecode: Instruction[]) { | ||
this.machineState = machineState; | ||
this.stateManager = stateManager; | ||
this.instructions = bytecode; | ||
} | ||
|
||
/** | ||
* Run the avm | ||
* @returns bool - successful execution will return true | ||
* - reverted execution will return false | ||
* - any other panic will throw | ||
*/ | ||
run(): AvmMessageCallResult { | ||
try { | ||
for (const instruction of this.instructions) { | ||
instruction.execute(this.machineState, this.stateManager); | ||
} | ||
|
||
const returnData = this.machineState.getReturnData(); | ||
return AvmMessageCallResult.success(returnData); | ||
} catch (e) { | ||
// TODO: This should only accept AVM defined errors, anything else SHOULD be thrown upstream | ||
const revertData = this.machineState.getReturnData(); | ||
return AvmMessageCallResult.revert(revertData); | ||
} | ||
} | ||
|
||
/** | ||
* Get the return data from avm execution | ||
* TODO: this should fail if the code has not been executed | ||
* - maybe move the return in run into a variable and track it | ||
*/ | ||
returnData(): Fr[] { | ||
return this.machineState.getReturnData(); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
yarn-project/acir-simulator/src/avm/journal/host_storage.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; | ||
|
||
/** - */ | ||
export class HostStorage { | ||
/** - */ | ||
public readonly stateDb: PublicStateDB; | ||
/** - */ | ||
public readonly contractsDb: PublicContractsDB; | ||
|
||
/** - */ | ||
public readonly commitmentsDb: CommitmentsDB; | ||
|
||
constructor(stateDb: PublicStateDB, contractsDb: PublicContractsDB, commitmentsDb: CommitmentsDB) { | ||
this.stateDb = stateDb; | ||
this.contractsDb = contractsDb; | ||
this.commitmentsDb = commitmentsDb; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './host_storage.js'; | ||
export * from './journal.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
describe('journal', () => { | ||
it('Should write to storage', () => {}); | ||
|
||
it('Should read from storage', () => {}); | ||
|
||
it('Should merge two journals together', () => {}); | ||
}); |
Oops, something went wrong.