/// <reference types="node" />
import { Either } from 'fp-ts/lib/Either.js';
import * as O from 'fp-ts/lib/Option.js';
import * as TE from 'fp-ts/lib/TaskEither.js';
import { TaskEither } from 'fp-ts/lib/TaskEither.js';
import fs from 'fs/promises';
import { Field, MerkleTree, PrivateKey } from 'o1js';
import z from 'zod';
import * as ZkProgram from './merklemembershipsprogram.js';
import { TreeRootStorageContract } from './treerootstoragecontract.js';
/**
 * An interface for o1js Merkle trees store holding sets of members.
 *
 * It uses fp-ts TaskEither to allow failible async actions executed
 * during the tree operations.
 */
export interface TreeStorage {
    /** Get the root of the Merkle tree. */
    getRoot: () => TaskEither<string, Field>;
    /** Get a witness for given leaf index */
    getWitness: (leafIndex: bigint) => TaskEither<string, O.Option<ZkProgram.TreeWitness>>;
    /** Check if there's a leaf under the given index */
    hasLeaf: (leafIndex: bigint) => TaskEither<string, boolean>;
    /** Set a Field value under the given index */
    setLeaf: (leafIndex: bigint, leaf: Field) => TaskEither<string, void>;
    /** Get the set of leaves as an array of optional Fields */
    getLeaves(): TaskEither<string, Array<O.Option<Field>>>;
}
/**
 * An implementation of the tree storage using in-memory data structures.
 */
export declare class InMemoryStorage implements TreeStorage {
    /** Set of indexes of occupied leaves */
    occupied: Set<bigint>;
    /** The underlying Merkle tree */
    merkleTree: MerkleTree;
    /** The Merkle tree root */
    getRoot(): TaskEither<string, Field>;
    /** Get a witness for given leaf index */
    getWitness(leafIndex: bigint): TE.TaskEither<never, O.None | O.Some<ZkProgram.TreeWitness>>;
    /** Check if there's a leaf under the given index */
    hasLeaf(leafIndex: bigint): TE.TaskEither<never, boolean>;
    /** Set a Field value under the given index */
    setLeaf(leafIndex: bigint, leaf: Field): TE.TaskEither<never, void>;
    /** Get the set of leaves as an array of optional Fields */
    getLeaves(): () => Promise<Either<string, Array<O.Option<Field>>>>;
}
/**
 * An implementation of the tree storage using a file system handle.
 */
export declare class PersistentInMemoryStorage extends InMemoryStorage {
    readonly file: fs.FileHandle;
    /**
     * Write current state of the storage to the file.
     */
    persist(): TaskEither<string, void>;
    private constructor();
    /**
     * Initialize the storage from a file.
     * If the file is empty, initialize the storage with the given leaves.
     */
    static initialize(path: string, initialLeaves?: Record<string, string>): TaskEither<string, PersistentInMemoryStorage>;
}
/**
 * A tree storage implementation with additional method `updateTreeRootOnChainIfNecessary`
 * that updates the root stored on chain if the off-chain root differs from the on-chain one.
 */
export declare class GenericMinaBlockchainTreeStorage<T extends TreeStorage> implements TreeStorage {
    private underlyingStorage;
    private contract;
    private mkTx;
    constructor(storage: T, contract: TreeRootStorageContract, mkTx: (txFn: () => void) => TaskEither<string, void>);
    private fetchOnChainRoot;
    /**
     * Fetch the root stored on chain, compare to the off-chain counterpart
     * and update the on-chain root if necessary.
     */
    updateTreeRootOnChainIfNecessary(): TaskEither<string, void>;
    /**
     * Get the off-chain Merkle tree root.
     */
    getRoot(): TE.TaskEither<string, import("o1js/dist/node/lib/field.js").Field>;
    /** Get a witness for given leaf index */
    getWitness(leafIdx: bigint): TE.TaskEither<string, O.Option<ZkProgram.TreeWitness>>;
    /** Check if there's a leaf under the given index */
    hasLeaf(leafIdx: bigint): TE.TaskEither<string, boolean>;
    /** Set a Field value under the given index
     *
     * NOTE. This function does not update the on-chain root.
     */
    setLeaf(leafIndex: bigint, leaf: Field): TE.TaskEither<string, void>;
    /** Get the set of leaves as an array of optional Fields */
    getLeaves(): TE.TaskEither<string, O.Option<import("o1js/dist/node/lib/field.js").Field>[]>;
}
/**
 * A Merkle tree storage that keeps the tree root on Mina blockchain
 * guarded by a contract controlled by a private key.
 * The tree itself is stored in the off-chain file storage.
 */
export declare class MinaBlockchainTreeStorage extends GenericMinaBlockchainTreeStorage<PersistentInMemoryStorage> {
    static initialize(path: string, contractPrivateKey: PrivateKey, feePayerPrivateKey: PrivateKey, initialLeaves?: Record<string, string>): TaskEither<string, MinaBlockchainTreeStorage>;
}
/**
 * An interface of an entity that provides access to a set of Merkle trees.
 */
export interface TreesProvider {
    getTree(treeRoot: Field): TaskEither<string, O.Option<TreeStorage>>;
    getTreeRoots(): TaskEither<string, Array<Field>>;
}
/**
 * Schema for the configuration of a Mina trees provider.
 * If for given tree `feePayerPrivateKey` and `contractPrivateKey`
 * are not simultanously present the tree root will NOT be commited to
 * the MINA blockchain.
 */
export declare const minaTreesProviderConfigurationSchema: z.ZodObject<{
    feePayerPrivateKey: z.ZodOptional<z.ZodString>;
    trees: z.ZodArray<z.ZodObject<{
        contractPrivateKey: z.ZodOptional<z.ZodString>;
        offchainStoragePath: z.ZodString;
        initialLeaves: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
    }, "strip", z.ZodTypeAny, {
        offchainStoragePath: string;
        contractPrivateKey?: string | undefined;
        initialLeaves?: Record<string, string> | undefined;
    }, {
        offchainStoragePath: string;
        contractPrivateKey?: string | undefined;
        initialLeaves?: Record<string, string> | undefined;
    }>, "many">;
}, "strip", z.ZodTypeAny, {
    trees: {
        offchainStoragePath: string;
        contractPrivateKey?: string | undefined;
        initialLeaves?: Record<string, string> | undefined;
    }[];
    feePayerPrivateKey?: string | undefined;
}, {
    trees: {
        offchainStoragePath: string;
        contractPrivateKey?: string | undefined;
        initialLeaves?: Record<string, string> | undefined;
    }[];
    feePayerPrivateKey?: string | undefined;
}>;
/**
 * Type of the configuration of the Mina trees provider.
 */
export type MinaTreesProviderConfiguration = z.infer<typeof minaTreesProviderConfigurationSchema>;
/**
 * Implements a trees provider that uses Mina blockchain to store the roots of the trees.
 * The trees are stored in the off-chain storage.
 */
export declare class MinaTreesProvider implements TreesProvider {
    readonly treeStorages: Array<TreeStorage>;
    getTree(treeRoot: Field): TaskEither<string, O.Option<TreeStorage>>;
    getTreeRoots(): TaskEither<string, Array<Field>>;
    constructor(treeStorages: TreeStorage[]);
    static initialize(cfg: MinaTreesProviderConfiguration): TaskEither<string, MinaTreesProvider>;
}
