@aztec/txe 0.0.0-test.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/bin/index.d.ts +3 -0
- package/dest/bin/index.d.ts.map +1 -0
- package/dest/bin/index.js +30 -0
- package/dest/index.d.ts +8 -0
- package/dest/index.d.ts.map +1 -0
- package/dest/index.js +156 -0
- package/dest/node/txe_node.d.ts +358 -0
- package/dest/node/txe_node.d.ts.map +1 -0
- package/dest/node/txe_node.js +504 -0
- package/dest/oracle/txe_oracle.d.ts +152 -0
- package/dest/oracle/txe_oracle.d.ts.map +1 -0
- package/dest/oracle/txe_oracle.js +833 -0
- package/dest/txe_service/txe_service.d.ts +212 -0
- package/dest/txe_service/txe_service.d.ts.map +1 -0
- package/dest/txe_service/txe_service.js +572 -0
- package/dest/util/encoding.d.ts +103 -0
- package/dest/util/encoding.d.ts.map +1 -0
- package/dest/util/encoding.js +76 -0
- package/dest/util/expected_failure_error.d.ts +4 -0
- package/dest/util/expected_failure_error.d.ts.map +1 -0
- package/dest/util/expected_failure_error.js +5 -0
- package/dest/util/txe_account_data_provider.d.ts +10 -0
- package/dest/util/txe_account_data_provider.d.ts.map +1 -0
- package/dest/util/txe_account_data_provider.js +17 -0
- package/dest/util/txe_public_contract_data_source.d.ts +20 -0
- package/dest/util/txe_public_contract_data_source.d.ts.map +1 -0
- package/dest/util/txe_public_contract_data_source.js +88 -0
- package/dest/util/txe_world_state_db.d.ts +14 -0
- package/dest/util/txe_world_state_db.d.ts.map +1 -0
- package/dest/util/txe_world_state_db.js +27 -0
- package/package.json +93 -0
- package/src/bin/index.ts +39 -0
- package/src/index.ts +213 -0
- package/src/node/txe_node.ts +725 -0
- package/src/oracle/txe_oracle.ts +1241 -0
- package/src/txe_service/txe_service.ts +749 -0
- package/src/util/encoding.ts +92 -0
- package/src/util/expected_failure_error.ts +5 -0
- package/src/util/txe_account_data_provider.ts +23 -0
- package/src/util/txe_public_contract_data_source.ts +101 -0
- package/src/util/txe_world_state_db.ts +38 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import { hexToBuffer } from '@aztec/foundation/string';
|
|
3
|
+
import { ContractArtifactSchema } from '@aztec/stdlib/abi';
|
|
4
|
+
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
5
|
+
import { ContractInstanceWithAddressSchema } from '@aztec/stdlib/contract';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
export function fromSingle(obj) {
|
|
8
|
+
return Fr.fromBuffer(Buffer.from(obj, 'hex'));
|
|
9
|
+
}
|
|
10
|
+
export function addressFromSingle(obj) {
|
|
11
|
+
return new AztecAddress(fromSingle(obj));
|
|
12
|
+
}
|
|
13
|
+
export function fromArray(obj) {
|
|
14
|
+
return obj.map((str)=>Fr.fromBuffer(hexToBuffer(str)));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Converts an array of Noir unsigned integers to a single tightly-packed buffer.
|
|
18
|
+
* @param uintBitSize If it's an array of Noir u8's, put `8`, etc.
|
|
19
|
+
* @returns
|
|
20
|
+
*/ export function fromUintArray(obj, uintBitSize) {
|
|
21
|
+
if (uintBitSize % 8 !== 0) {
|
|
22
|
+
throw new Error(`u${uintBitSize} is not a supported type in Noir`);
|
|
23
|
+
}
|
|
24
|
+
const uintByteSize = uintBitSize / 8;
|
|
25
|
+
return Buffer.concat(obj.map((str)=>hexToBuffer(str).slice(-uintByteSize)));
|
|
26
|
+
}
|
|
27
|
+
export function toSingle(obj) {
|
|
28
|
+
return obj.toString().slice(2);
|
|
29
|
+
}
|
|
30
|
+
export function toArray(objs) {
|
|
31
|
+
return objs.map((obj)=>obj.toString());
|
|
32
|
+
}
|
|
33
|
+
export function bufferToU8Array(buffer) {
|
|
34
|
+
return toArray(Array.from(buffer).map((byte)=>new Fr(byte)));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Converts a ForeignCallArray into a tuple which represents a nr BoundedVec.
|
|
38
|
+
* If the input array is shorter than the maxLen, it pads the result with zeros,
|
|
39
|
+
* so that nr can correctly coerce this result into a BoundedVec.
|
|
40
|
+
* @param array
|
|
41
|
+
* @param maxLen - the max length of the BoundedVec.
|
|
42
|
+
* @returns a tuple representing a BoundedVec.
|
|
43
|
+
*/ export function arrayToBoundedVec(array, maxLen) {
|
|
44
|
+
if (array.length > maxLen) {
|
|
45
|
+
throw new Error(`Array of length ${array.length} larger than maxLen ${maxLen}`);
|
|
46
|
+
}
|
|
47
|
+
const lengthDiff = maxLen - array.length;
|
|
48
|
+
// We pad the array to the maxLen of the BoundedVec.
|
|
49
|
+
const zeroPaddingArray = toArray(Array(lengthDiff).fill(new Fr(0)));
|
|
50
|
+
// These variable names match with the BoundedVec members in nr:
|
|
51
|
+
const storage = array.concat(zeroPaddingArray);
|
|
52
|
+
const len = toSingle(new Fr(array.length));
|
|
53
|
+
return [
|
|
54
|
+
storage,
|
|
55
|
+
len
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
export function toForeignCallResult(obj) {
|
|
59
|
+
return {
|
|
60
|
+
values: obj
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export const ForeignCallSingleSchema = z.string();
|
|
64
|
+
export const ForeignCallArraySchema = z.array(z.string());
|
|
65
|
+
export const ForeignCallArgsSchema = z.array(z.union([
|
|
66
|
+
ForeignCallSingleSchema,
|
|
67
|
+
ForeignCallArraySchema,
|
|
68
|
+
ContractArtifactSchema,
|
|
69
|
+
ContractInstanceWithAddressSchema
|
|
70
|
+
]));
|
|
71
|
+
export const ForeignCallResultSchema = z.object({
|
|
72
|
+
values: z.array(z.union([
|
|
73
|
+
ForeignCallSingleSchema,
|
|
74
|
+
ForeignCallArraySchema
|
|
75
|
+
]))
|
|
76
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expected_failure_error.d.ts","sourceRoot":"","sources":["../../src/util/expected_failure_error.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAG5B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
2
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
|
+
import { CompleteAddress } from '@aztec/stdlib/contract';
|
|
4
|
+
export declare class TXEAccountDataProvider {
|
|
5
|
+
#private;
|
|
6
|
+
constructor(store: AztecAsyncKVStore);
|
|
7
|
+
getAccount(key: AztecAddress): Promise<CompleteAddress>;
|
|
8
|
+
setAccount(key: AztecAddress, value: CompleteAddress): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=txe_account_data_provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"txe_account_data_provider.d.ts","sourceRoot":"","sources":["../../src/util/txe_account_data_provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,iBAAiB,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,qBAAa,sBAAsB;;gBAGrB,KAAK,EAAE,iBAAiB;IAI9B,UAAU,CAAC,GAAG,EAAE,YAAY;IAQ5B,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe;CAG3D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CompleteAddress } from '@aztec/stdlib/contract';
|
|
2
|
+
export class TXEAccountDataProvider {
|
|
3
|
+
#accounts;
|
|
4
|
+
constructor(store){
|
|
5
|
+
this.#accounts = store.openMap('accounts');
|
|
6
|
+
}
|
|
7
|
+
async getAccount(key) {
|
|
8
|
+
const completeAddress = await this.#accounts.getAsync(key.toString());
|
|
9
|
+
if (!completeAddress) {
|
|
10
|
+
throw new Error(`Account not found: ${key.toString()}`);
|
|
11
|
+
}
|
|
12
|
+
return CompleteAddress.fromBuffer(completeAddress);
|
|
13
|
+
}
|
|
14
|
+
async setAccount(key, value) {
|
|
15
|
+
await this.#accounts.set(key.toString(), value.toBuffer());
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import { type ContractArtifact, FunctionSelector } from '@aztec/stdlib/abi';
|
|
3
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
|
+
import { type ContractClassPublic, type ContractDataSource, type ContractInstanceWithAddress, type PublicFunction } from '@aztec/stdlib/contract';
|
|
5
|
+
import type { TXE } from '../oracle/txe_oracle.js';
|
|
6
|
+
export declare class TXEPublicContractDataSource implements ContractDataSource {
|
|
7
|
+
private txeOracle;
|
|
8
|
+
constructor(txeOracle: TXE);
|
|
9
|
+
getPublicFunction(address: AztecAddress, selector: FunctionSelector): Promise<PublicFunction | undefined>;
|
|
10
|
+
getBlockNumber(): Promise<number>;
|
|
11
|
+
getContractClass(id: Fr): Promise<ContractClassPublic | undefined>;
|
|
12
|
+
getBytecodeCommitment(id: Fr): Promise<Fr | undefined>;
|
|
13
|
+
getContract(address: AztecAddress): Promise<ContractInstanceWithAddress | undefined>;
|
|
14
|
+
getContractClassIds(): Promise<Fr[]>;
|
|
15
|
+
getContractArtifact(address: AztecAddress): Promise<ContractArtifact | undefined>;
|
|
16
|
+
getContractFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined>;
|
|
17
|
+
registerContractFunctionSignatures(_address: AztecAddress, _signatures: []): Promise<void>;
|
|
18
|
+
addContractClass(_contractClass: ContractClassPublic): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=txe_public_contract_data_source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"txe_public_contract_data_source.d.ts","sourceRoot":"","sources":["../../src/util/txe_public_contract_data_source.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAE9C,OAAO,EAAE,KAAK,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAChC,KAAK,cAAc,EAEpB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAEnD,qBAAa,2BAA4B,YAAW,kBAAkB;IACxD,OAAO,CAAC,SAAS;gBAAT,SAAS,EAAE,GAAG;IAE5B,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAQ/G,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAI3B,gBAAgB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IA0BlE,qBAAqB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC;IAKtD,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,2BAA2B,GAAG,SAAS,CAAC;IAK1F,mBAAmB,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;IAI9B,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;IAKjF,uBAAuB,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAgB7G,kCAAkC,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAK1F,gBAAgB,CAAC,cAAc,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;CAIrE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { PUBLIC_DISPATCH_SELECTOR } from '@aztec/constants';
|
|
2
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
3
|
+
import { PrivateFunctionsTree } from '@aztec/pxe/server';
|
|
4
|
+
import { FunctionSelector } from '@aztec/stdlib/abi';
|
|
5
|
+
import { computePublicBytecodeCommitment } from '@aztec/stdlib/contract';
|
|
6
|
+
export class TXEPublicContractDataSource {
|
|
7
|
+
txeOracle;
|
|
8
|
+
constructor(txeOracle){
|
|
9
|
+
this.txeOracle = txeOracle;
|
|
10
|
+
}
|
|
11
|
+
async getPublicFunction(address, selector) {
|
|
12
|
+
const bytecode = await this.txeOracle.getContractDataProvider().getBytecode(address, selector);
|
|
13
|
+
if (!bytecode) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
bytecode,
|
|
18
|
+
selector
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
getBlockNumber() {
|
|
22
|
+
return this.txeOracle.getBlockNumber();
|
|
23
|
+
}
|
|
24
|
+
async getContractClass(id) {
|
|
25
|
+
const contractClass = await this.txeOracle.getContractDataProvider().getContractClass(id);
|
|
26
|
+
const artifact = await this.txeOracle.getContractDataProvider().getContractArtifact(id);
|
|
27
|
+
const tree = await PrivateFunctionsTree.create(artifact);
|
|
28
|
+
const privateFunctionsRoot = await tree.getFunctionTreeRoot();
|
|
29
|
+
const publicFunctions = [];
|
|
30
|
+
if (contractClass.packedBytecode.length > 0) {
|
|
31
|
+
publicFunctions.push({
|
|
32
|
+
selector: FunctionSelector.fromField(new Fr(PUBLIC_DISPATCH_SELECTOR)),
|
|
33
|
+
bytecode: contractClass.packedBytecode
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
id,
|
|
38
|
+
artifactHash: contractClass.artifactHash,
|
|
39
|
+
packedBytecode: contractClass.packedBytecode,
|
|
40
|
+
publicFunctions: publicFunctions,
|
|
41
|
+
privateFunctionsRoot: new Fr(privateFunctionsRoot.root),
|
|
42
|
+
version: contractClass.version,
|
|
43
|
+
privateFunctions: [],
|
|
44
|
+
unconstrainedFunctions: []
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async getBytecodeCommitment(id) {
|
|
48
|
+
const contractClass = await this.txeOracle.getContractDataProvider().getContractClass(id);
|
|
49
|
+
return computePublicBytecodeCommitment(contractClass.packedBytecode);
|
|
50
|
+
}
|
|
51
|
+
async getContract(address) {
|
|
52
|
+
const instance = await this.txeOracle.getContractDataProvider().getContractInstance(address);
|
|
53
|
+
return {
|
|
54
|
+
...instance,
|
|
55
|
+
address
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
getContractClassIds() {
|
|
59
|
+
throw new Error('Method not implemented.');
|
|
60
|
+
}
|
|
61
|
+
async getContractArtifact(address) {
|
|
62
|
+
const instance = await this.txeOracle.getContractDataProvider().getContractInstance(address);
|
|
63
|
+
return this.txeOracle.getContractDataProvider().getContractArtifact(instance.currentContractClassId);
|
|
64
|
+
}
|
|
65
|
+
async getContractFunctionName(address, selector) {
|
|
66
|
+
const artifact = await this.getContractArtifact(address);
|
|
67
|
+
if (!artifact) {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
const functionSelectorsAndNames = await Promise.all(artifact.functions.map(async (f)=>({
|
|
71
|
+
name: f.name,
|
|
72
|
+
selector: await FunctionSelector.fromNameAndParameters({
|
|
73
|
+
name: f.name,
|
|
74
|
+
parameters: f.parameters
|
|
75
|
+
})
|
|
76
|
+
})));
|
|
77
|
+
const func = functionSelectorsAndNames.find((f)=>f.selector.equals(selector));
|
|
78
|
+
return Promise.resolve(func?.name);
|
|
79
|
+
}
|
|
80
|
+
registerContractFunctionSignatures(_address, _signatures) {
|
|
81
|
+
return Promise.resolve();
|
|
82
|
+
}
|
|
83
|
+
// TODO(#10007): Remove this method.
|
|
84
|
+
addContractClass(_contractClass) {
|
|
85
|
+
// We don't really need to do anything for the txe here
|
|
86
|
+
return Promise.resolve();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import { WorldStateDB } from '@aztec/simulator/server';
|
|
3
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
|
+
import type { ContractDataSource } from '@aztec/stdlib/contract';
|
|
5
|
+
import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
|
|
6
|
+
import type { TXE } from '../oracle/txe_oracle.js';
|
|
7
|
+
export declare class TXEWorldStateDB extends WorldStateDB {
|
|
8
|
+
private merkleDb;
|
|
9
|
+
private txe;
|
|
10
|
+
constructor(merkleDb: MerkleTreeWriteOperations, dataSource: ContractDataSource, txe: TXE);
|
|
11
|
+
storageRead(contract: AztecAddress, slot: Fr): Promise<Fr>;
|
|
12
|
+
storageWrite(contract: AztecAddress, slot: Fr, newValue: Fr): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=txe_world_state_db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"txe_world_state_db.d.ts","sourceRoot":"","sources":["../../src/util/txe_world_state_db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAGjF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAEnD,qBAAa,eAAgB,SAAQ,YAAY;IACnC,OAAO,CAAC,QAAQ;IAA6D,OAAO,CAAC,GAAG;gBAAhF,QAAQ,EAAE,yBAAyB,EAAE,UAAU,EAAE,kBAAkB,EAAU,GAAG,EAAE,GAAG;IAI1F,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;IAgB1D,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAK3F"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
2
|
+
import { WorldStateDB } from '@aztec/simulator/server';
|
|
3
|
+
import { PublicDataWrite } from '@aztec/stdlib/avm';
|
|
4
|
+
import { computePublicDataTreeLeafSlot } from '@aztec/stdlib/hash';
|
|
5
|
+
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
6
|
+
export class TXEWorldStateDB extends WorldStateDB {
|
|
7
|
+
merkleDb;
|
|
8
|
+
txe;
|
|
9
|
+
constructor(merkleDb, dataSource, txe){
|
|
10
|
+
super(merkleDb, dataSource), this.merkleDb = merkleDb, this.txe = txe;
|
|
11
|
+
}
|
|
12
|
+
async storageRead(contract, slot) {
|
|
13
|
+
const leafSlot = (await computePublicDataTreeLeafSlot(contract, slot)).toBigInt();
|
|
14
|
+
const lowLeafResult = await this.merkleDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
|
|
15
|
+
let value = Fr.ZERO;
|
|
16
|
+
if (lowLeafResult && lowLeafResult.alreadyPresent) {
|
|
17
|
+
const preimage = await this.merkleDb.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
|
|
18
|
+
value = preimage.value;
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
async storageWrite(contract, slot, newValue) {
|
|
23
|
+
await this.txe.addPublicDataWrites([
|
|
24
|
+
new PublicDataWrite(await computePublicDataTreeLeafSlot(contract, slot), newValue)
|
|
25
|
+
]);
|
|
26
|
+
}
|
|
27
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aztec/txe",
|
|
3
|
+
"version": "0.0.0-test.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": "./dest/index.js",
|
|
6
|
+
"bin": "./dest/bin/index.js",
|
|
7
|
+
"typedocOptions": {
|
|
8
|
+
"entryPoints": [
|
|
9
|
+
"./src/index.ts"
|
|
10
|
+
],
|
|
11
|
+
"name": "TXE",
|
|
12
|
+
"tsconfig": "./tsconfig.json"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "yarn clean && tsc -b",
|
|
16
|
+
"build:dev": "tsc -b --watch",
|
|
17
|
+
"clean": "rm -rf ./dest .tsbuildinfo",
|
|
18
|
+
"formatting": "run -T prettier --check ./src && run -T eslint ./src",
|
|
19
|
+
"formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src",
|
|
20
|
+
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests --maxWorkers=${JEST_MAX_WORKERS:-8}",
|
|
21
|
+
"dev": "LOG_LEVEL=debug node ./dest/bin/index.js",
|
|
22
|
+
"start": "node --no-warnings ./dest/bin/index.js"
|
|
23
|
+
},
|
|
24
|
+
"inherits": [
|
|
25
|
+
"../package.common.json"
|
|
26
|
+
],
|
|
27
|
+
"jest": {
|
|
28
|
+
"moduleNameMapper": {
|
|
29
|
+
"^(\\.{1,2}/.*)\\.[cm]?js$": "$1"
|
|
30
|
+
},
|
|
31
|
+
"testRegex": "./src/.*\\.test\\.(js|mjs|ts)$",
|
|
32
|
+
"rootDir": "./src",
|
|
33
|
+
"workerThreads": true,
|
|
34
|
+
"transform": {
|
|
35
|
+
"^.+\\.tsx?$": [
|
|
36
|
+
"@swc/jest",
|
|
37
|
+
{
|
|
38
|
+
"jsc": {
|
|
39
|
+
"parser": {
|
|
40
|
+
"syntax": "typescript",
|
|
41
|
+
"decorators": true
|
|
42
|
+
},
|
|
43
|
+
"transform": {
|
|
44
|
+
"decoratorVersion": "2022-03"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"extensionsToTreatAsEsm": [
|
|
51
|
+
".ts"
|
|
52
|
+
],
|
|
53
|
+
"reporters": [
|
|
54
|
+
"default"
|
|
55
|
+
],
|
|
56
|
+
"testTimeout": 120000,
|
|
57
|
+
"setupFiles": [
|
|
58
|
+
"../../foundation/src/jest/setup.mjs"
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@aztec/accounts": "0.0.0-test.0",
|
|
63
|
+
"@aztec/aztec.js": "0.0.0-test.0",
|
|
64
|
+
"@aztec/constants": "0.0.0-test.0",
|
|
65
|
+
"@aztec/foundation": "0.0.0-test.0",
|
|
66
|
+
"@aztec/key-store": "0.0.0-test.0",
|
|
67
|
+
"@aztec/kv-store": "0.0.0-test.0",
|
|
68
|
+
"@aztec/protocol-contracts": "0.0.0-test.0",
|
|
69
|
+
"@aztec/pxe": "0.0.0-test.0",
|
|
70
|
+
"@aztec/simulator": "0.0.0-test.0",
|
|
71
|
+
"@aztec/stdlib": "0.0.0-test.0",
|
|
72
|
+
"@aztec/world-state": "0.0.0-test.0",
|
|
73
|
+
"zod": "^3.23.8"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@jest/globals": "^29.5.0",
|
|
77
|
+
"@types/jest": "^29.5.0",
|
|
78
|
+
"@types/node": "^18.7.23",
|
|
79
|
+
"jest": "^29.5.0",
|
|
80
|
+
"jest-mock-extended": "^3.0.3",
|
|
81
|
+
"ts-node": "^10.9.1",
|
|
82
|
+
"typescript": "^5.0.4"
|
|
83
|
+
},
|
|
84
|
+
"files": [
|
|
85
|
+
"dest",
|
|
86
|
+
"src",
|
|
87
|
+
"!*.test.*"
|
|
88
|
+
],
|
|
89
|
+
"types": "./dest/index.d.ts",
|
|
90
|
+
"engines": {
|
|
91
|
+
"node": ">=18"
|
|
92
|
+
}
|
|
93
|
+
}
|
package/src/bin/index.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings
|
|
2
|
+
import { createLogger } from '@aztec/aztec.js';
|
|
3
|
+
import { startHttpRpcServer } from '@aztec/foundation/json-rpc/server';
|
|
4
|
+
|
|
5
|
+
import { createTXERpcServer } from '../index.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create and start a new TXE HTTP Server
|
|
9
|
+
*/
|
|
10
|
+
async function main() {
|
|
11
|
+
const { TXE_PORT = 8080 } = process.env;
|
|
12
|
+
|
|
13
|
+
process.on('SIGTERM', () => {
|
|
14
|
+
logger.info('Received SIGTERM.');
|
|
15
|
+
process.exit(0);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
process.on('SIGINT', () => {
|
|
19
|
+
logger.info('Received SIGTERM.');
|
|
20
|
+
process.exit(0);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const logger = createLogger('txe:service');
|
|
24
|
+
logger.info(`Setting up TXE...`);
|
|
25
|
+
|
|
26
|
+
const txeServer = createTXERpcServer(logger);
|
|
27
|
+
const { port } = await startHttpRpcServer(txeServer, {
|
|
28
|
+
port: TXE_PORT,
|
|
29
|
+
timeoutMs: 1e3 * 60 * 5,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
logger.info(`TXE listening on port ${port}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
main().catch(err => {
|
|
36
|
+
// eslint-disable-next-line no-console
|
|
37
|
+
console.error(err);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { SchnorrAccountContractArtifact } from '@aztec/accounts/schnorr';
|
|
2
|
+
import {
|
|
3
|
+
AztecAddress,
|
|
4
|
+
type ContractArtifact,
|
|
5
|
+
type ContractInstanceWithAddress,
|
|
6
|
+
Fr,
|
|
7
|
+
PublicKeys,
|
|
8
|
+
deriveKeys,
|
|
9
|
+
getContractInstanceFromDeployParams,
|
|
10
|
+
loadContractArtifact,
|
|
11
|
+
} from '@aztec/aztec.js';
|
|
12
|
+
import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
|
|
13
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
14
|
+
import { type ProtocolContract, protocolContractNames } from '@aztec/protocol-contracts';
|
|
15
|
+
import { BundledProtocolContractsProvider } from '@aztec/protocol-contracts/providers/bundle';
|
|
16
|
+
import type { ApiSchemaFor, ZodFor } from '@aztec/stdlib/schemas';
|
|
17
|
+
|
|
18
|
+
import { readFile, readdir } from 'fs/promises';
|
|
19
|
+
import { join } from 'path';
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
|
|
22
|
+
import { TXEService } from './txe_service/txe_service.js';
|
|
23
|
+
import {
|
|
24
|
+
type ForeignCallArgs,
|
|
25
|
+
ForeignCallArgsSchema,
|
|
26
|
+
type ForeignCallArray,
|
|
27
|
+
type ForeignCallResult,
|
|
28
|
+
ForeignCallResultSchema,
|
|
29
|
+
type ForeignCallSingle,
|
|
30
|
+
fromArray,
|
|
31
|
+
fromSingle,
|
|
32
|
+
toForeignCallResult,
|
|
33
|
+
toSingle,
|
|
34
|
+
} from './util/encoding.js';
|
|
35
|
+
|
|
36
|
+
const TXESessions = new Map<number, TXEService>();
|
|
37
|
+
|
|
38
|
+
const TXEArtifactsCache = new Map<string, { artifact: ContractArtifact; instance: ContractInstanceWithAddress }>();
|
|
39
|
+
|
|
40
|
+
type MethodNames<T> = {
|
|
41
|
+
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
|
|
42
|
+
}[keyof T];
|
|
43
|
+
|
|
44
|
+
type TXEForeignCallInput = {
|
|
45
|
+
session_id: number;
|
|
46
|
+
function: MethodNames<TXEService> | 'reset';
|
|
47
|
+
root_path: string;
|
|
48
|
+
package_name: string;
|
|
49
|
+
inputs: ForeignCallArgs;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const TXEForeignCallInputSchema = z.object({
|
|
53
|
+
// eslint-disable-next-line camelcase
|
|
54
|
+
session_id: z.number().int().nonnegative(),
|
|
55
|
+
function: z.string() as ZodFor<MethodNames<TXEService> | 'reset'>,
|
|
56
|
+
// eslint-disable-next-line camelcase
|
|
57
|
+
root_path: z.string(),
|
|
58
|
+
// eslint-disable-next-line camelcase
|
|
59
|
+
package_name: z.string(),
|
|
60
|
+
inputs: ForeignCallArgsSchema,
|
|
61
|
+
}) satisfies ZodFor<TXEForeignCallInput>;
|
|
62
|
+
|
|
63
|
+
class TXEDispatcher {
|
|
64
|
+
private protocolContracts!: ProtocolContract[];
|
|
65
|
+
|
|
66
|
+
constructor(private logger: Logger) {}
|
|
67
|
+
|
|
68
|
+
async #processDeployInputs({ inputs, root_path: rootPath, package_name: packageName }: TXEForeignCallInput) {
|
|
69
|
+
const [pathStr, contractName, initializer] = inputs.slice(0, 3).map(input =>
|
|
70
|
+
fromArray(input as ForeignCallArray)
|
|
71
|
+
.map(char => String.fromCharCode(char.toNumber()))
|
|
72
|
+
.join(''),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const decodedArgs = fromArray(inputs[4] as ForeignCallArray);
|
|
76
|
+
const secret = fromSingle(inputs[5] as ForeignCallSingle);
|
|
77
|
+
const publicKeys = secret.equals(Fr.ZERO) ? PublicKeys.default() : (await deriveKeys(secret)).publicKeys;
|
|
78
|
+
const publicKeysHash = await publicKeys.hash();
|
|
79
|
+
|
|
80
|
+
const cacheKey = `${pathStr}-${contractName}-${initializer}-${decodedArgs
|
|
81
|
+
.map(arg => arg.toString())
|
|
82
|
+
.join('-')}-${publicKeysHash.toString()}`;
|
|
83
|
+
|
|
84
|
+
let artifact;
|
|
85
|
+
let instance;
|
|
86
|
+
|
|
87
|
+
if (TXEArtifactsCache.has(cacheKey)) {
|
|
88
|
+
this.logger.debug(`Using cached artifact for ${cacheKey}`);
|
|
89
|
+
({ artifact, instance } = TXEArtifactsCache.get(cacheKey)!);
|
|
90
|
+
} else {
|
|
91
|
+
let artifactPath = '';
|
|
92
|
+
// We're deploying the contract under test
|
|
93
|
+
// env.deploy_self("contractName")
|
|
94
|
+
if (!pathStr) {
|
|
95
|
+
artifactPath = join(rootPath, './target', `${packageName}-${contractName}.json`);
|
|
96
|
+
} else {
|
|
97
|
+
// We're deploying a contract that belongs in a workspace
|
|
98
|
+
// env.deploy("../path/to/workspace/root@packageName", "contractName")
|
|
99
|
+
if (pathStr.includes('@')) {
|
|
100
|
+
const [workspace, pkg] = pathStr.split('@');
|
|
101
|
+
const targetPath = join(rootPath, workspace, './target');
|
|
102
|
+
this.logger.debug(`Looking for compiled artifact in workspace ${targetPath}`);
|
|
103
|
+
artifactPath = join(targetPath, `${pkg}-${contractName}.json`);
|
|
104
|
+
} else {
|
|
105
|
+
// We're deploying a standalone contract
|
|
106
|
+
// env.deploy("../path/to/contract/root", "contractName")
|
|
107
|
+
const targetPath = join(rootPath, pathStr, './target');
|
|
108
|
+
this.logger.debug(`Looking for compiled artifact in ${targetPath}`);
|
|
109
|
+
[artifactPath] = (await readdir(targetPath)).filter(file => file.endsWith(`-${contractName}.json`));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
this.logger.debug(`Loading compiled artifact ${artifactPath}`);
|
|
113
|
+
artifact = loadContractArtifact(JSON.parse(await readFile(artifactPath, 'utf-8')));
|
|
114
|
+
this.logger.debug(
|
|
115
|
+
`Deploy ${
|
|
116
|
+
artifact.name
|
|
117
|
+
} with initializer ${initializer}(${decodedArgs}) and public keys hash ${publicKeysHash.toString()}`,
|
|
118
|
+
);
|
|
119
|
+
instance = await getContractInstanceFromDeployParams(artifact, {
|
|
120
|
+
constructorArgs: decodedArgs,
|
|
121
|
+
skipArgsDecoding: true,
|
|
122
|
+
salt: Fr.ONE,
|
|
123
|
+
publicKeys,
|
|
124
|
+
constructorArtifact: initializer ? initializer : undefined,
|
|
125
|
+
deployer: AztecAddress.ZERO,
|
|
126
|
+
});
|
|
127
|
+
TXEArtifactsCache.set(cacheKey, { artifact, instance });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
inputs.splice(0, 2, artifact, instance, toSingle(secret));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async #processAddAccountInputs({ inputs }: TXEForeignCallInput) {
|
|
134
|
+
const secret = fromSingle(inputs[0] as ForeignCallSingle);
|
|
135
|
+
|
|
136
|
+
const cacheKey = `SchnorrAccountContract-${secret}`;
|
|
137
|
+
|
|
138
|
+
let artifact;
|
|
139
|
+
let instance;
|
|
140
|
+
|
|
141
|
+
if (TXEArtifactsCache.has(cacheKey)) {
|
|
142
|
+
this.logger.debug(`Using cached artifact for ${cacheKey}`);
|
|
143
|
+
({ artifact, instance } = TXEArtifactsCache.get(cacheKey)!);
|
|
144
|
+
} else {
|
|
145
|
+
const keys = await deriveKeys(secret);
|
|
146
|
+
const args = [keys.publicKeys.masterIncomingViewingPublicKey.x, keys.publicKeys.masterIncomingViewingPublicKey.y];
|
|
147
|
+
artifact = SchnorrAccountContractArtifact;
|
|
148
|
+
instance = await getContractInstanceFromDeployParams(artifact, {
|
|
149
|
+
constructorArgs: args,
|
|
150
|
+
skipArgsDecoding: true,
|
|
151
|
+
salt: Fr.ONE,
|
|
152
|
+
publicKeys: keys.publicKeys,
|
|
153
|
+
constructorArtifact: 'constructor',
|
|
154
|
+
deployer: AztecAddress.ZERO,
|
|
155
|
+
});
|
|
156
|
+
TXEArtifactsCache.set(cacheKey, { artifact, instance });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
inputs.splice(0, 0, artifact, instance);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// eslint-disable-next-line camelcase
|
|
163
|
+
async resolve_foreign_call(callData: TXEForeignCallInput): Promise<ForeignCallResult> {
|
|
164
|
+
const { session_id: sessionId, function: functionName, inputs } = callData;
|
|
165
|
+
this.logger.debug(`Calling ${functionName} on session ${sessionId}`);
|
|
166
|
+
|
|
167
|
+
if (!TXESessions.has(sessionId) && functionName != 'reset') {
|
|
168
|
+
this.logger.debug(`Creating new session ${sessionId}`);
|
|
169
|
+
if (!this.protocolContracts) {
|
|
170
|
+
this.protocolContracts = await Promise.all(
|
|
171
|
+
protocolContractNames.map(name => new BundledProtocolContractsProvider().getProtocolContractArtifact(name)),
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
TXESessions.set(sessionId, await TXEService.init(this.logger, this.protocolContracts));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
switch (functionName) {
|
|
178
|
+
case 'reset': {
|
|
179
|
+
TXESessions.delete(sessionId) &&
|
|
180
|
+
this.logger.debug(`Called reset on session ${sessionId}, yeeting it out of existence`);
|
|
181
|
+
return toForeignCallResult([]);
|
|
182
|
+
}
|
|
183
|
+
case 'deploy': {
|
|
184
|
+
await this.#processDeployInputs(callData);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case 'addAccount': {
|
|
188
|
+
await this.#processAddAccountInputs(callData);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const txeService = TXESessions.get(sessionId);
|
|
194
|
+
const response = await (txeService as any)[functionName](...inputs);
|
|
195
|
+
return response;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const TXEDispatcherApiSchema: ApiSchemaFor<TXEDispatcher> = {
|
|
200
|
+
// eslint-disable-next-line camelcase
|
|
201
|
+
resolve_foreign_call: z.function().args(TXEForeignCallInputSchema).returns(ForeignCallResultSchema),
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Creates an RPC server that forwards calls to the TXE.
|
|
206
|
+
* @param logger - Logger to output to
|
|
207
|
+
* @returns A TXE RPC server.
|
|
208
|
+
*/
|
|
209
|
+
export function createTXERpcServer(logger: Logger) {
|
|
210
|
+
return createSafeJsonRpcServer(new TXEDispatcher(logger), TXEDispatcherApiSchema, {
|
|
211
|
+
http200OnError: true,
|
|
212
|
+
});
|
|
213
|
+
}
|