@aztec/archiver 0.0.0-test.1 → 0.0.1-commit.5476d83
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/README.md +27 -6
- package/dest/archiver/archiver.d.ts +147 -57
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +841 -333
- package/dest/archiver/archiver_store.d.ts +85 -50
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +708 -213
- package/dest/archiver/config.d.ts +5 -21
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +21 -12
- package/dest/archiver/data_retrieval.d.ts +32 -27
- package/dest/archiver/data_retrieval.d.ts.map +1 -1
- package/dest/archiver/data_retrieval.js +197 -94
- package/dest/archiver/errors.d.ts +9 -1
- package/dest/archiver/errors.d.ts.map +1 -1
- package/dest/archiver/errors.js +12 -0
- package/dest/archiver/index.d.ts +3 -4
- package/dest/archiver/index.d.ts.map +1 -1
- package/dest/archiver/index.js +1 -2
- package/dest/archiver/instrumentation.d.ts +12 -6
- package/dest/archiver/instrumentation.d.ts.map +1 -1
- package/dest/archiver/instrumentation.js +58 -17
- package/dest/archiver/kv_archiver_store/block_store.d.ts +48 -11
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +216 -63
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +3 -3
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.js +12 -18
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +11 -8
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.js +30 -16
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +50 -35
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +88 -46
- package/dest/archiver/kv_archiver_store/log_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +18 -46
- package/dest/archiver/kv_archiver_store/message_store.d.ts +23 -17
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.js +150 -48
- package/dest/archiver/structs/data_retrieval.d.ts +1 -1
- package/dest/archiver/structs/inbox_message.d.ts +15 -0
- package/dest/archiver/structs/inbox_message.d.ts.map +1 -0
- package/dest/archiver/structs/inbox_message.js +38 -0
- package/dest/archiver/structs/published.d.ts +3 -11
- package/dest/archiver/structs/published.d.ts.map +1 -1
- package/dest/archiver/structs/published.js +1 -1
- package/dest/archiver/validation.d.ts +17 -0
- package/dest/archiver/validation.d.ts.map +1 -0
- package/dest/archiver/validation.js +98 -0
- package/dest/factory.d.ts +8 -13
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +18 -49
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/rpc/index.d.ts +2 -3
- package/dest/rpc/index.d.ts.map +1 -1
- package/dest/rpc/index.js +1 -4
- package/dest/test/index.d.ts +1 -1
- package/dest/test/mock_archiver.d.ts +2 -2
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.d.ts +5 -3
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +14 -1
- package/dest/test/mock_l2_block_source.d.ts +38 -10
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +119 -8
- package/dest/test/mock_structs.d.ts +9 -0
- package/dest/test/mock_structs.d.ts.map +1 -0
- package/dest/test/mock_structs.js +37 -0
- package/package.json +28 -30
- package/src/archiver/archiver.ts +1087 -410
- package/src/archiver/archiver_store.ts +97 -55
- package/src/archiver/archiver_store_test_suite.ts +664 -210
- package/src/archiver/config.ts +28 -41
- package/src/archiver/data_retrieval.ts +279 -125
- package/src/archiver/errors.ts +21 -0
- package/src/archiver/index.ts +2 -3
- package/src/archiver/instrumentation.ts +77 -22
- package/src/archiver/kv_archiver_store/block_store.ts +270 -72
- package/src/archiver/kv_archiver_store/contract_class_store.ts +13 -23
- package/src/archiver/kv_archiver_store/contract_instance_store.ts +35 -27
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +127 -63
- package/src/archiver/kv_archiver_store/log_store.ts +24 -62
- package/src/archiver/kv_archiver_store/message_store.ts +209 -53
- package/src/archiver/structs/inbox_message.ts +41 -0
- package/src/archiver/structs/published.ts +2 -11
- package/src/archiver/validation.ts +124 -0
- package/src/factory.ts +24 -66
- package/src/index.ts +1 -1
- package/src/rpc/index.ts +1 -5
- package/src/test/mock_archiver.ts +1 -1
- package/src/test/mock_l1_to_l2_message_source.ts +14 -3
- package/src/test/mock_l2_block_source.ts +158 -13
- package/src/test/mock_structs.ts +49 -0
- package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +0 -12
- package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/nullifier_store.js +0 -73
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +0 -23
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +0 -1
- package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +0 -49
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +0 -175
- package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +0 -1
- package/dest/archiver/memory_archiver_store/memory_archiver_store.js +0 -636
- package/src/archiver/kv_archiver_store/nullifier_store.ts +0 -97
- package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +0 -61
- package/src/archiver/memory_archiver_store/memory_archiver_store.ts +0 -801
|
@@ -7,71 +7,75 @@ import {
|
|
|
7
7
|
SerializableContractInstance,
|
|
8
8
|
SerializableContractInstanceUpdate,
|
|
9
9
|
} from '@aztec/stdlib/contract';
|
|
10
|
+
import type { UInt64 } from '@aztec/stdlib/types';
|
|
10
11
|
|
|
11
|
-
type ContractInstanceUpdateKey = [string,
|
|
12
|
+
type ContractInstanceUpdateKey = [string, string] | [string, string, number];
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* LMDB implementation of the ArchiverDataStore interface.
|
|
15
16
|
*/
|
|
16
17
|
export class ContractInstanceStore {
|
|
17
18
|
#contractInstances: AztecAsyncMap<string, Buffer>;
|
|
19
|
+
#contractInstancePublishedAt: AztecAsyncMap<string, number>;
|
|
18
20
|
#contractInstanceUpdates: AztecAsyncMap<ContractInstanceUpdateKey, Buffer>;
|
|
19
21
|
|
|
20
|
-
constructor(db: AztecAsyncKVStore) {
|
|
22
|
+
constructor(private db: AztecAsyncKVStore) {
|
|
21
23
|
this.#contractInstances = db.openMap('archiver_contract_instances');
|
|
24
|
+
this.#contractInstancePublishedAt = db.openMap('archiver_contract_instances_publication_block_number');
|
|
22
25
|
this.#contractInstanceUpdates = db.openMap('archiver_contract_instance_updates');
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
addContractInstance(contractInstance: ContractInstanceWithAddress): Promise<void> {
|
|
26
|
-
return this
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
addContractInstance(contractInstance: ContractInstanceWithAddress, blockNumber: number): Promise<void> {
|
|
29
|
+
return this.db.transactionAsync(async () => {
|
|
30
|
+
await this.#contractInstances.set(
|
|
31
|
+
contractInstance.address.toString(),
|
|
32
|
+
new SerializableContractInstance(contractInstance).toBuffer(),
|
|
33
|
+
);
|
|
34
|
+
await this.#contractInstancePublishedAt.set(contractInstance.address.toString(), blockNumber);
|
|
35
|
+
});
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
deleteContractInstance(contractInstance: ContractInstanceWithAddress): Promise<void> {
|
|
33
|
-
return this
|
|
39
|
+
return this.db.transactionAsync(async () => {
|
|
40
|
+
await this.#contractInstances.delete(contractInstance.address.toString());
|
|
41
|
+
await this.#contractInstancePublishedAt.delete(contractInstance.address.toString());
|
|
42
|
+
});
|
|
34
43
|
}
|
|
35
44
|
|
|
36
|
-
getUpdateKey(contractAddress: AztecAddress,
|
|
45
|
+
getUpdateKey(contractAddress: AztecAddress, timestamp: UInt64, logIndex?: number): ContractInstanceUpdateKey {
|
|
37
46
|
if (logIndex === undefined) {
|
|
38
|
-
return [contractAddress.toString(),
|
|
47
|
+
return [contractAddress.toString(), timestamp.toString()];
|
|
39
48
|
} else {
|
|
40
|
-
return [contractAddress.toString(),
|
|
49
|
+
return [contractAddress.toString(), timestamp.toString(), logIndex];
|
|
41
50
|
}
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
addContractInstanceUpdate(
|
|
45
54
|
contractInstanceUpdate: ContractInstanceUpdateWithAddress,
|
|
46
|
-
|
|
55
|
+
timestamp: UInt64,
|
|
47
56
|
logIndex: number,
|
|
48
57
|
): Promise<void> {
|
|
49
58
|
return this.#contractInstanceUpdates.set(
|
|
50
|
-
this.getUpdateKey(contractInstanceUpdate.address,
|
|
59
|
+
this.getUpdateKey(contractInstanceUpdate.address, timestamp, logIndex),
|
|
51
60
|
new SerializableContractInstanceUpdate(contractInstanceUpdate).toBuffer(),
|
|
52
61
|
);
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
deleteContractInstanceUpdate(
|
|
56
65
|
contractInstanceUpdate: ContractInstanceUpdateWithAddress,
|
|
57
|
-
|
|
66
|
+
timestamp: UInt64,
|
|
58
67
|
logIndex: number,
|
|
59
68
|
): Promise<void> {
|
|
60
|
-
return this.#contractInstanceUpdates.delete(
|
|
61
|
-
this.getUpdateKey(contractInstanceUpdate.address, blockNumber, logIndex),
|
|
62
|
-
);
|
|
69
|
+
return this.#contractInstanceUpdates.delete(this.getUpdateKey(contractInstanceUpdate.address, timestamp, logIndex));
|
|
63
70
|
}
|
|
64
71
|
|
|
65
|
-
async getCurrentContractInstanceClassId(
|
|
66
|
-
|
|
67
|
-
blockNumber: number,
|
|
68
|
-
originalClassId: Fr,
|
|
69
|
-
): Promise<Fr> {
|
|
70
|
-
// We need to find the last update before the given block number
|
|
72
|
+
async getCurrentContractInstanceClassId(address: AztecAddress, timestamp: UInt64, originalClassId: Fr): Promise<Fr> {
|
|
73
|
+
// We need to find the last update before the given timestamp
|
|
71
74
|
const queryResult = await this.#contractInstanceUpdates
|
|
72
75
|
.valuesAsync({
|
|
73
76
|
reverse: true,
|
|
74
|
-
|
|
77
|
+
start: this.getUpdateKey(address, 0n), // Make sure we only look at updates for this contract
|
|
78
|
+
end: this.getUpdateKey(address, timestamp + 1n), // No update can match this key since it doesn't have a log index. We want the highest key <= timestamp
|
|
75
79
|
limit: 1,
|
|
76
80
|
})
|
|
77
81
|
.next();
|
|
@@ -81,7 +85,7 @@ export class ContractInstanceStore {
|
|
|
81
85
|
|
|
82
86
|
const serializedUpdate = queryResult.value;
|
|
83
87
|
const update = SerializableContractInstanceUpdate.fromBuffer(serializedUpdate);
|
|
84
|
-
if (
|
|
88
|
+
if (timestamp < update.timestampOfChange) {
|
|
85
89
|
return update.prevContractClassId.isZero() ? originalClassId : update.prevContractClassId;
|
|
86
90
|
}
|
|
87
91
|
return update.newContractClassId;
|
|
@@ -89,7 +93,7 @@ export class ContractInstanceStore {
|
|
|
89
93
|
|
|
90
94
|
async getContractInstance(
|
|
91
95
|
address: AztecAddress,
|
|
92
|
-
|
|
96
|
+
timestamp: UInt64,
|
|
93
97
|
): Promise<ContractInstanceWithAddress | undefined> {
|
|
94
98
|
const contractInstance = await this.#contractInstances.getAsync(address.toString());
|
|
95
99
|
if (!contractInstance) {
|
|
@@ -99,9 +103,13 @@ export class ContractInstanceStore {
|
|
|
99
103
|
const instance = SerializableContractInstance.fromBuffer(contractInstance).withAddress(address);
|
|
100
104
|
instance.currentContractClassId = await this.getCurrentContractInstanceClassId(
|
|
101
105
|
address,
|
|
102
|
-
|
|
106
|
+
timestamp,
|
|
103
107
|
instance.originalContractClassId,
|
|
104
108
|
);
|
|
105
109
|
return instance;
|
|
106
110
|
}
|
|
111
|
+
|
|
112
|
+
getContractInstanceDeploymentBlockNumber(address: AztecAddress): Promise<number | undefined> {
|
|
113
|
+
return this.#contractInstancePublishedAt.getAsync(address.toString());
|
|
114
|
+
}
|
|
107
115
|
}
|
|
@@ -1,69 +1,104 @@
|
|
|
1
|
+
import type { L1BlockId } from '@aztec/ethereum';
|
|
1
2
|
import type { Fr } from '@aztec/foundation/fields';
|
|
2
3
|
import { toArray } from '@aztec/foundation/iterable';
|
|
3
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import type { AztecAsyncKVStore, StoreSize } from '@aztec/kv-store';
|
|
5
|
+
import type { AztecAsyncKVStore, CustomRange, StoreSize } from '@aztec/kv-store';
|
|
5
6
|
import { FunctionSelector } from '@aztec/stdlib/abi';
|
|
6
7
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
7
|
-
import type
|
|
8
|
+
import { type L2Block, L2BlockHash, type ValidateBlockResult } from '@aztec/stdlib/block';
|
|
8
9
|
import type {
|
|
9
10
|
ContractClassPublic,
|
|
11
|
+
ContractDataSource,
|
|
10
12
|
ContractInstanceUpdateWithAddress,
|
|
11
13
|
ContractInstanceWithAddress,
|
|
12
14
|
ExecutablePrivateFunctionWithMembershipProof,
|
|
13
|
-
|
|
15
|
+
UtilityFunctionWithMembershipProof,
|
|
14
16
|
} from '@aztec/stdlib/contract';
|
|
15
17
|
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
|
|
16
18
|
import { type LogFilter, PrivateLog, type TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
17
|
-
import type { InboxLeaf } from '@aztec/stdlib/messaging';
|
|
18
19
|
import type { BlockHeader, TxHash, TxReceipt } from '@aztec/stdlib/tx';
|
|
20
|
+
import type { UInt64 } from '@aztec/stdlib/types';
|
|
21
|
+
|
|
22
|
+
import { join } from 'path';
|
|
19
23
|
|
|
20
24
|
import type { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js';
|
|
21
|
-
import type {
|
|
22
|
-
import type {
|
|
25
|
+
import type { InboxMessage } from '../structs/inbox_message.js';
|
|
26
|
+
import type { PublishedL2Block } from '../structs/published.js';
|
|
23
27
|
import { BlockStore } from './block_store.js';
|
|
24
28
|
import { ContractClassStore } from './contract_class_store.js';
|
|
25
29
|
import { ContractInstanceStore } from './contract_instance_store.js';
|
|
26
30
|
import { LogStore } from './log_store.js';
|
|
27
31
|
import { MessageStore } from './message_store.js';
|
|
28
|
-
|
|
32
|
+
|
|
33
|
+
export const ARCHIVER_DB_VERSION = 3;
|
|
34
|
+
export const MAX_FUNCTION_SIGNATURES = 1000;
|
|
35
|
+
export const MAX_FUNCTION_NAME_LEN = 256;
|
|
29
36
|
|
|
30
37
|
/**
|
|
31
38
|
* LMDB implementation of the ArchiverDataStore interface.
|
|
32
39
|
*/
|
|
33
|
-
export class KVArchiverDataStore implements ArchiverDataStore {
|
|
34
|
-
public static readonly SCHEMA_VERSION =
|
|
40
|
+
export class KVArchiverDataStore implements ArchiverDataStore, ContractDataSource {
|
|
41
|
+
public static readonly SCHEMA_VERSION = ARCHIVER_DB_VERSION;
|
|
35
42
|
|
|
36
43
|
#blockStore: BlockStore;
|
|
37
44
|
#logStore: LogStore;
|
|
38
|
-
#nullifierStore: NullifierStore;
|
|
39
45
|
#messageStore: MessageStore;
|
|
40
46
|
#contractClassStore: ContractClassStore;
|
|
41
47
|
#contractInstanceStore: ContractInstanceStore;
|
|
48
|
+
|
|
42
49
|
private functionNames = new Map<string, string>();
|
|
43
50
|
|
|
44
51
|
#log = createLogger('archiver:data-store');
|
|
45
52
|
|
|
46
|
-
constructor(
|
|
53
|
+
constructor(
|
|
54
|
+
private db: AztecAsyncKVStore,
|
|
55
|
+
logsMaxPageSize: number = 1000,
|
|
56
|
+
) {
|
|
47
57
|
this.#blockStore = new BlockStore(db);
|
|
48
58
|
this.#logStore = new LogStore(db, this.#blockStore, logsMaxPageSize);
|
|
49
59
|
this.#messageStore = new MessageStore(db);
|
|
50
60
|
this.#contractClassStore = new ContractClassStore(db);
|
|
51
61
|
this.#contractInstanceStore = new ContractInstanceStore(db);
|
|
52
|
-
this.#nullifierStore = new NullifierStore(db);
|
|
53
62
|
}
|
|
54
63
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
public transactionAsync<T>(callback: () => Promise<T>): Promise<T> {
|
|
65
|
+
return this.db.transactionAsync(callback);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public getBlockNumber(): Promise<number> {
|
|
69
|
+
return this.getSynchedL2BlockNumber();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public async getContract(
|
|
73
|
+
address: AztecAddress,
|
|
74
|
+
maybeTimestamp?: UInt64,
|
|
75
|
+
): Promise<ContractInstanceWithAddress | undefined> {
|
|
76
|
+
const [header] = await this.getBlockHeaders(await this.getBlockNumber(), 1);
|
|
77
|
+
const timestamp = maybeTimestamp ?? header!.globalVariables.timestamp;
|
|
78
|
+
return this.getContractInstance(address, timestamp);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public async backupTo(path: string, compress = true): Promise<string> {
|
|
82
|
+
await this.db.backupTo(path, compress);
|
|
83
|
+
return join(path, 'data.mdb');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public close() {
|
|
87
|
+
return this.db.close();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
getDebugFunctionName(_address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
|
|
59
91
|
return Promise.resolve(this.functionNames.get(selector.toString()));
|
|
60
92
|
}
|
|
61
93
|
|
|
62
|
-
async registerContractFunctionSignatures(
|
|
94
|
+
async registerContractFunctionSignatures(signatures: string[]): Promise<void> {
|
|
63
95
|
for (const sig of signatures) {
|
|
96
|
+
if (this.functionNames.size > MAX_FUNCTION_SIGNATURES) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
64
99
|
try {
|
|
65
100
|
const selector = await FunctionSelector.fromSignature(sig);
|
|
66
|
-
this.functionNames.set(selector.toString(), sig.slice(0, sig.indexOf('(')));
|
|
101
|
+
this.functionNames.set(selector.toString(), sig.slice(0, sig.indexOf('(')).slice(0, MAX_FUNCTION_NAME_LEN));
|
|
67
102
|
} catch {
|
|
68
103
|
this.#log.warn(`Failed to parse signature: ${sig}. Ignoring`);
|
|
69
104
|
}
|
|
@@ -78,9 +113,12 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
78
113
|
return this.#contractClassStore.getContractClassIds();
|
|
79
114
|
}
|
|
80
115
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
116
|
+
getContractInstance(address: AztecAddress, timestamp: UInt64): Promise<ContractInstanceWithAddress | undefined> {
|
|
117
|
+
return this.#contractInstanceStore.getContractInstance(address, timestamp);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
getContractInstanceDeploymentBlockNumber(address: AztecAddress): Promise<number | undefined> {
|
|
121
|
+
return this.#contractInstanceStore.getContractInstanceDeploymentBlockNumber(address);
|
|
84
122
|
}
|
|
85
123
|
|
|
86
124
|
async addContractClasses(
|
|
@@ -108,36 +146,35 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
108
146
|
addFunctions(
|
|
109
147
|
contractClassId: Fr,
|
|
110
148
|
privateFunctions: ExecutablePrivateFunctionWithMembershipProof[],
|
|
111
|
-
|
|
149
|
+
utilityFunctions: UtilityFunctionWithMembershipProof[],
|
|
112
150
|
): Promise<boolean> {
|
|
113
|
-
return this.#contractClassStore.addFunctions(contractClassId, privateFunctions,
|
|
151
|
+
return this.#contractClassStore.addFunctions(contractClassId, privateFunctions, utilityFunctions);
|
|
114
152
|
}
|
|
115
153
|
|
|
116
|
-
async addContractInstances(data: ContractInstanceWithAddress[],
|
|
117
|
-
return (await Promise.all(data.map(c => this.#contractInstanceStore.addContractInstance(c)))).every(
|
|
154
|
+
async addContractInstances(data: ContractInstanceWithAddress[], blockNumber: number): Promise<boolean> {
|
|
155
|
+
return (await Promise.all(data.map(c => this.#contractInstanceStore.addContractInstance(c, blockNumber)))).every(
|
|
156
|
+
Boolean,
|
|
157
|
+
);
|
|
118
158
|
}
|
|
119
159
|
|
|
120
160
|
async deleteContractInstances(data: ContractInstanceWithAddress[], _blockNumber: number): Promise<boolean> {
|
|
121
161
|
return (await Promise.all(data.map(c => this.#contractInstanceStore.deleteContractInstance(c)))).every(Boolean);
|
|
122
162
|
}
|
|
123
163
|
|
|
124
|
-
async addContractInstanceUpdates(data: ContractInstanceUpdateWithAddress[],
|
|
164
|
+
async addContractInstanceUpdates(data: ContractInstanceUpdateWithAddress[], timestamp: UInt64): Promise<boolean> {
|
|
125
165
|
return (
|
|
126
166
|
await Promise.all(
|
|
127
167
|
data.map((update, logIndex) =>
|
|
128
|
-
this.#contractInstanceStore.addContractInstanceUpdate(update,
|
|
168
|
+
this.#contractInstanceStore.addContractInstanceUpdate(update, timestamp, logIndex),
|
|
129
169
|
),
|
|
130
170
|
)
|
|
131
171
|
).every(Boolean);
|
|
132
172
|
}
|
|
133
|
-
async deleteContractInstanceUpdates(
|
|
134
|
-
data: ContractInstanceUpdateWithAddress[],
|
|
135
|
-
blockNumber: number,
|
|
136
|
-
): Promise<boolean> {
|
|
173
|
+
async deleteContractInstanceUpdates(data: ContractInstanceUpdateWithAddress[], timestamp: UInt64): Promise<boolean> {
|
|
137
174
|
return (
|
|
138
175
|
await Promise.all(
|
|
139
176
|
data.map((update, logIndex) =>
|
|
140
|
-
this.#contractInstanceStore.deleteContractInstanceUpdate(update,
|
|
177
|
+
this.#contractInstanceStore.deleteContractInstanceUpdate(update, timestamp, logIndex),
|
|
141
178
|
),
|
|
142
179
|
)
|
|
143
180
|
).every(Boolean);
|
|
@@ -148,8 +185,8 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
148
185
|
* @param blocks - The L2 blocks to be added to the store and the last processed L1 block.
|
|
149
186
|
* @returns True if the operation is successful.
|
|
150
187
|
*/
|
|
151
|
-
addBlocks(blocks:
|
|
152
|
-
return this.#blockStore.addBlocks(blocks);
|
|
188
|
+
addBlocks(blocks: PublishedL2Block[], opts: { force?: boolean } = {}): Promise<boolean> {
|
|
189
|
+
return this.#blockStore.addBlocks(blocks, opts);
|
|
153
190
|
}
|
|
154
191
|
|
|
155
192
|
/**
|
|
@@ -163,6 +200,18 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
163
200
|
return this.#blockStore.unwindBlocks(from, blocksToUnwind);
|
|
164
201
|
}
|
|
165
202
|
|
|
203
|
+
getPublishedBlock(number: number): Promise<PublishedL2Block | undefined> {
|
|
204
|
+
return this.#blockStore.getBlock(number);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
getPublishedBlockByHash(blockHash: Fr): Promise<PublishedL2Block | undefined> {
|
|
208
|
+
return this.#blockStore.getBlockByHash(L2BlockHash.fromField(blockHash));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
getPublishedBlockByArchive(archive: Fr): Promise<PublishedL2Block | undefined> {
|
|
212
|
+
return this.#blockStore.getBlockByArchive(archive);
|
|
213
|
+
}
|
|
214
|
+
|
|
166
215
|
/**
|
|
167
216
|
* Gets up to `limit` amount of L2 blocks starting from `from`.
|
|
168
217
|
*
|
|
@@ -170,7 +219,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
170
219
|
* @param limit - The number of blocks to return.
|
|
171
220
|
* @returns The requested L2 blocks
|
|
172
221
|
*/
|
|
173
|
-
|
|
222
|
+
getPublishedBlocks(start: number, limit: number): Promise<PublishedL2Block[]> {
|
|
174
223
|
return toArray(this.#blockStore.getBlocks(start, limit));
|
|
175
224
|
}
|
|
176
225
|
|
|
@@ -185,10 +234,18 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
185
234
|
return toArray(this.#blockStore.getBlockHeaders(start, limit));
|
|
186
235
|
}
|
|
187
236
|
|
|
237
|
+
getBlockHeaderByHash(blockHash: Fr): Promise<BlockHeader | undefined> {
|
|
238
|
+
return this.#blockStore.getBlockHeaderByHash(L2BlockHash.fromField(blockHash));
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
|
|
242
|
+
return this.#blockStore.getBlockHeaderByArchive(archive);
|
|
243
|
+
}
|
|
244
|
+
|
|
188
245
|
/**
|
|
189
246
|
* Gets a tx effect.
|
|
190
|
-
* @param txHash - The
|
|
191
|
-
* @returns The requested tx effect (or undefined if not found).
|
|
247
|
+
* @param txHash - The hash of the tx corresponding to the tx effect.
|
|
248
|
+
* @returns The requested tx effect with block info (or undefined if not found).
|
|
192
249
|
*/
|
|
193
250
|
getTxEffect(txHash: TxHash) {
|
|
194
251
|
return this.#blockStore.getTxEffect(txHash);
|
|
@@ -216,33 +273,19 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
216
273
|
return this.#logStore.deleteLogs(blocks);
|
|
217
274
|
}
|
|
218
275
|
|
|
219
|
-
/**
|
|
220
|
-
* Append new nullifiers to the store's list.
|
|
221
|
-
* @param blocks - The blocks for which to add the nullifiers.
|
|
222
|
-
* @returns True if the operation is successful.
|
|
223
|
-
*/
|
|
224
|
-
addNullifiers(blocks: L2Block[]): Promise<boolean> {
|
|
225
|
-
return this.#nullifierStore.addNullifiers(blocks);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
deleteNullifiers(blocks: L2Block[]): Promise<boolean> {
|
|
229
|
-
return this.#nullifierStore.deleteNullifiers(blocks);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
findNullifiersIndexesWithBlock(blockNumber: number, nullifiers: Fr[]): Promise<(InBlock<bigint> | undefined)[]> {
|
|
233
|
-
return this.#nullifierStore.findNullifiersIndexesWithBlock(blockNumber, nullifiers);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
276
|
getTotalL1ToL2MessageCount(): Promise<bigint> {
|
|
237
277
|
return this.#messageStore.getTotalL1ToL2MessageCount();
|
|
238
278
|
}
|
|
239
279
|
|
|
280
|
+
getLastL1ToL2Message(): Promise<InboxMessage | undefined> {
|
|
281
|
+
return this.#messageStore.getLastMessage();
|
|
282
|
+
}
|
|
283
|
+
|
|
240
284
|
/**
|
|
241
285
|
* Append L1 to L2 messages to the store.
|
|
242
|
-
* @param messages - The L1 to L2 messages to be added to the store
|
|
243
|
-
* @returns True if the operation is successful.
|
|
286
|
+
* @param messages - The L1 to L2 messages to be added to the store.
|
|
244
287
|
*/
|
|
245
|
-
addL1ToL2Messages(messages:
|
|
288
|
+
addL1ToL2Messages(messages: InboxMessage[]): Promise<void> {
|
|
246
289
|
return this.#messageStore.addL1ToL2Messages(messages);
|
|
247
290
|
}
|
|
248
291
|
|
|
@@ -260,7 +303,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
260
303
|
* @param blockNumber - L2 block number to get messages for.
|
|
261
304
|
* @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found).
|
|
262
305
|
*/
|
|
263
|
-
getL1ToL2Messages(blockNumber:
|
|
306
|
+
getL1ToL2Messages(blockNumber: number): Promise<Fr[]> {
|
|
264
307
|
return this.#messageStore.getL1ToL2Messages(blockNumber);
|
|
265
308
|
}
|
|
266
309
|
|
|
@@ -277,12 +320,13 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
277
320
|
/**
|
|
278
321
|
* Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
|
|
279
322
|
* @param tags - The tags to filter the logs by.
|
|
323
|
+
* @param logsPerTag - How many logs to return per tag. Default returns everything
|
|
280
324
|
* @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
|
|
281
325
|
* that tag.
|
|
282
326
|
*/
|
|
283
|
-
getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
|
|
327
|
+
getLogsByTags(tags: Fr[], logsPerTag?: number): Promise<TxScopedL2Log[][]> {
|
|
284
328
|
try {
|
|
285
|
-
return this.#logStore.getLogsByTags(tags);
|
|
329
|
+
return this.#logStore.getLogsByTags(tags, logsPerTag);
|
|
286
330
|
} catch (err) {
|
|
287
331
|
return Promise.reject(err);
|
|
288
332
|
}
|
|
@@ -334,8 +378,8 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
334
378
|
await this.#blockStore.setSynchedL1BlockNumber(l1BlockNumber);
|
|
335
379
|
}
|
|
336
380
|
|
|
337
|
-
async
|
|
338
|
-
await this.#messageStore.
|
|
381
|
+
async setMessageSynchedL1Block(l1Block: L1BlockId) {
|
|
382
|
+
await this.#messageStore.setSynchedL1Block(l1Block);
|
|
339
383
|
}
|
|
340
384
|
|
|
341
385
|
/**
|
|
@@ -344,7 +388,7 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
344
388
|
async getSynchPoint(): Promise<ArchiverL1SynchPoint> {
|
|
345
389
|
const [blocksSynchedTo, messagesSynchedTo] = await Promise.all([
|
|
346
390
|
this.#blockStore.getSynchedL1BlockNumber(),
|
|
347
|
-
this.#messageStore.
|
|
391
|
+
this.#messageStore.getSynchedL1Block(),
|
|
348
392
|
]);
|
|
349
393
|
return {
|
|
350
394
|
blocksSynchedTo,
|
|
@@ -355,4 +399,24 @@ export class KVArchiverDataStore implements ArchiverDataStore {
|
|
|
355
399
|
public estimateSize(): Promise<StoreSize> {
|
|
356
400
|
return this.db.estimateSize();
|
|
357
401
|
}
|
|
402
|
+
|
|
403
|
+
public rollbackL1ToL2MessagesToL2Block(targetBlockNumber: number): Promise<void> {
|
|
404
|
+
return this.#messageStore.rollbackL1ToL2MessagesToL2Block(targetBlockNumber);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
public iterateL1ToL2Messages(range: CustomRange<bigint> = {}): AsyncIterableIterator<InboxMessage> {
|
|
408
|
+
return this.#messageStore.iterateL1ToL2Messages(range);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
public removeL1ToL2Messages(startIndex: bigint): Promise<void> {
|
|
412
|
+
return this.#messageStore.removeL1ToL2Messages(startIndex);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
public getPendingChainValidationStatus(): Promise<ValidateBlockResult | undefined> {
|
|
416
|
+
return this.#blockStore.getPendingChainValidationStatus();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
public setPendingChainValidationStatus(status: ValidateBlockResult | undefined): Promise<void> {
|
|
420
|
+
return this.#blockStore.setPendingChainValidationStatus(status);
|
|
421
|
+
}
|
|
358
422
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX
|
|
1
|
+
import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX } from '@aztec/constants';
|
|
2
2
|
import type { Fr } from '@aztec/foundation/fields';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
|
|
@@ -30,7 +30,11 @@ export class LogStore {
|
|
|
30
30
|
#logsMaxPageSize: number;
|
|
31
31
|
#log = createLogger('archiver:log_store');
|
|
32
32
|
|
|
33
|
-
constructor(
|
|
33
|
+
constructor(
|
|
34
|
+
private db: AztecAsyncKVStore,
|
|
35
|
+
private blockStore: BlockStore,
|
|
36
|
+
logsMaxPageSize: number = 1000,
|
|
37
|
+
) {
|
|
34
38
|
this.#logsByTag = db.openMap('archiver_tagged_logs_by_tag');
|
|
35
39
|
this.#logTagsByBlock = db.openMap('archiver_log_tags_by_block');
|
|
36
40
|
this.#privateLogsByBlock = db.openMap('archiver_private_logs_by_block');
|
|
@@ -40,7 +44,7 @@ export class LogStore {
|
|
|
40
44
|
this.#logsMaxPageSize = logsMaxPageSize;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
|
-
#
|
|
47
|
+
#extractTaggedLogs(block: L2Block) {
|
|
44
48
|
const taggedLogs = new Map<string, Buffer[]>();
|
|
45
49
|
const dataStartIndexForBlock =
|
|
46
50
|
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
@@ -48,68 +52,22 @@ export class LogStore {
|
|
|
48
52
|
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
49
53
|
const txHash = txEffect.txHash;
|
|
50
54
|
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
51
|
-
|
|
55
|
+
|
|
56
|
+
txEffect.privateLogs.forEach((log, logIndex) => {
|
|
52
57
|
const tag = log.fields[0];
|
|
58
|
+
this.#log.debug(`Found private log with tag ${tag.toString()} in block ${block.number}`);
|
|
59
|
+
|
|
53
60
|
const currentLogs = taggedLogs.get(tag.toString()) ?? [];
|
|
54
|
-
currentLogs.push(
|
|
55
|
-
new TxScopedL2Log(
|
|
56
|
-
txHash,
|
|
57
|
-
dataStartIndexForTx,
|
|
58
|
-
block.number,
|
|
59
|
-
/* isFromPublic */ false,
|
|
60
|
-
log.toBuffer(),
|
|
61
|
-
).toBuffer(),
|
|
62
|
-
);
|
|
61
|
+
currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, logIndex, block.number, log).toBuffer());
|
|
63
62
|
taggedLogs.set(tag.toString(), currentLogs);
|
|
64
63
|
});
|
|
65
|
-
});
|
|
66
|
-
return taggedLogs;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
#extractTaggedLogsFromPublic(block: L2Block) {
|
|
70
|
-
const taggedLogs = new Map<string, Buffer[]>();
|
|
71
|
-
const dataStartIndexForBlock =
|
|
72
|
-
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
73
|
-
block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
|
|
74
|
-
block.body.txEffects.forEach((txEffect, txIndex) => {
|
|
75
|
-
const txHash = txEffect.txHash;
|
|
76
|
-
const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
|
|
77
|
-
txEffect.publicLogs.forEach(log => {
|
|
78
|
-
// Check that each log stores 2 lengths in its first field. If not, it's not a tagged log:
|
|
79
|
-
const firstFieldBuf = log.log[0].toBuffer();
|
|
80
|
-
// See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
|
|
81
|
-
// Search the codebase for "disgusting encoding" to see other hardcoded instances of this encoding, that you might need to change if you ever find yourself here.
|
|
82
|
-
if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
|
|
83
|
-
// See parseLogFromPublic - the first field of a tagged log is 5 bytes structured:
|
|
84
|
-
// [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
|
|
85
|
-
this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
// Check that the length values line up with the log contents
|
|
89
|
-
const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
|
|
90
|
-
const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
|
|
91
|
-
// Add 1 for the first field holding lengths
|
|
92
|
-
const totalLogLength = 1 + publicValuesLength + privateValuesLength;
|
|
93
|
-
// Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
|
|
94
|
-
if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
|
|
95
|
-
this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
64
|
|
|
99
|
-
|
|
100
|
-
const tag = log.
|
|
65
|
+
txEffect.publicLogs.forEach((log, logIndex) => {
|
|
66
|
+
const tag = log.fields[0];
|
|
67
|
+
this.#log.debug(`Found public log with tag ${tag.toString()} in block ${block.number}`);
|
|
101
68
|
|
|
102
|
-
this.#log.debug(`Found tagged public log with tag ${tag.toString()} in block ${block.number}`);
|
|
103
69
|
const currentLogs = taggedLogs.get(tag.toString()) ?? [];
|
|
104
|
-
currentLogs.push(
|
|
105
|
-
new TxScopedL2Log(
|
|
106
|
-
txHash,
|
|
107
|
-
dataStartIndexForTx,
|
|
108
|
-
block.number,
|
|
109
|
-
/* isFromPublic */ true,
|
|
110
|
-
log.toBuffer(),
|
|
111
|
-
).toBuffer(),
|
|
112
|
-
);
|
|
70
|
+
currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, logIndex, block.number, log).toBuffer());
|
|
113
71
|
taggedLogs.set(tag.toString(), currentLogs);
|
|
114
72
|
});
|
|
115
73
|
});
|
|
@@ -123,14 +81,14 @@ export class LogStore {
|
|
|
123
81
|
*/
|
|
124
82
|
addLogs(blocks: L2Block[]): Promise<boolean> {
|
|
125
83
|
const taggedLogsToAdd = blocks
|
|
126
|
-
.
|
|
84
|
+
.map(block => this.#extractTaggedLogs(block))
|
|
127
85
|
.reduce((acc, val) => {
|
|
128
86
|
for (const [tag, logs] of val.entries()) {
|
|
129
87
|
const currentLogs = acc.get(tag) ?? [];
|
|
130
88
|
acc.set(tag, currentLogs.concat(logs));
|
|
131
89
|
}
|
|
132
90
|
return acc;
|
|
133
|
-
});
|
|
91
|
+
}, new Map());
|
|
134
92
|
const tagsToUpdate = Array.from(taggedLogsToAdd.keys());
|
|
135
93
|
|
|
136
94
|
return this.db.transactionAsync(async () => {
|
|
@@ -204,6 +162,7 @@ export class LogStore {
|
|
|
204
162
|
this.#privateLogsByBlock.delete(block.number),
|
|
205
163
|
this.#publicLogsByBlock.delete(block.number),
|
|
206
164
|
this.#logTagsByBlock.delete(block.number),
|
|
165
|
+
this.#contractClassLogsByBlock.delete(block.number),
|
|
207
166
|
]),
|
|
208
167
|
),
|
|
209
168
|
);
|
|
@@ -236,10 +195,13 @@ export class LogStore {
|
|
|
236
195
|
* @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
|
|
237
196
|
* that tag.
|
|
238
197
|
*/
|
|
239
|
-
async getLogsByTags(tags: Fr[]): Promise<TxScopedL2Log[][]> {
|
|
198
|
+
async getLogsByTags(tags: Fr[], limitPerTag?: number): Promise<TxScopedL2Log[][]> {
|
|
199
|
+
if (limitPerTag !== undefined && limitPerTag <= 0) {
|
|
200
|
+
throw new TypeError('limitPerTag needs to be greater than 0');
|
|
201
|
+
}
|
|
240
202
|
const logs = await Promise.all(tags.map(tag => this.#logsByTag.getAsync(tag.toString())));
|
|
241
203
|
return logs.map(
|
|
242
|
-
|
|
204
|
+
logBuffers => logBuffers?.slice(0, limitPerTag).map(logBuffer => TxScopedL2Log.fromBuffer(logBuffer)) ?? [],
|
|
243
205
|
);
|
|
244
206
|
}
|
|
245
207
|
|