Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add endActionState and fromActionState to fetchActions #828

Merged
merged 7 commits into from
Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- The internal event type now includes event data and transaction information as separate objects, allowing for more accurate information about each event and its associated transaction.
- Removed multiple best tip blocks when fetching action data https://github.com/o1-labs/snarkyjs/pull/817
- Implemented a temporary fix that filters out multiple best tip blocks, if they exist, while fetching actions. This fix will be removed once the related issue in the Archive-Node-API repository (https://github.com/o1-labs/Archive-Node-API/issues/7) is resolved.
- New `fromActionHash` and `endActionHash` parameters for fetchActions function in SnarkyJS https://github.com/o1-labs/snarkyjs/pull/828
MartinMinkov marked this conversation as resolved.
Show resolved Hide resolved
- Allows fetching only necessary actions to compute the latest actions hash
- Eliminates the need to retrieve the entire actions history of a zkApp
- Utilizes `actionStateTwo` field returned by Archive Node API as a safe starting point for deriving the most recent action hash

## [0.9.5](https://github.com/o1-labs/snarkyjs/compare/21de489...4573252d)

Expand Down
69 changes: 50 additions & 19 deletions src/lib/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { SequenceEvents, TokenId } from './account_update.js';
import { PublicKey } from './signature.js';
import { NetworkValue } from './precondition.js';
import { Types } from '../provable/types.js';
import { ActionHashes } from './mina.js';
import * as Encoding from './encoding.js';
import {
Account,
Expand Down Expand Up @@ -173,7 +174,12 @@ let accountsToFetch = {} as Record<
let networksToFetch = {} as Record<string, { graphqlEndpoint: string }>;
let actionsToFetch = {} as Record<
string,
{ publicKey: string; tokenId: string; graphqlEndpoint: string }
{
publicKey: string;
tokenId: string;
actionHashes: { fromActionHash?: string; endActionHash?: string };
graphqlEndpoint: string;
}
>;

function markAccountToBeFetched(
Expand All @@ -194,14 +200,27 @@ function markNetworkToBeFetched(graphqlEndpoint: string) {
}
function markActionsToBeFetched(
publicKey: PublicKey,
actionHashes: ActionHashes,
tokenId: Field,
graphqlEndpoint: string
) {
let publicKeyBase58 = publicKey.toBase58();
let tokenBase58 = TokenId.toBase58(tokenId);
let { fromActionHash, endActionHash } = actionHashes;
let fromActionHashBase58 = fromActionHash
? fromActionHash.toString()
: undefined;
let endActionHashBase58 = endActionHash
? endActionHash.toString()
: undefined;

actionsToFetch[`${publicKeyBase58};${tokenBase58};${graphqlEndpoint}`] = {
publicKey: publicKeyBase58,
tokenId: tokenBase58,
actionHashes: {
fromActionHash: fromActionHashBase58,
endActionHash: endActionHashBase58,
},
graphqlEndpoint,
};
}
Expand All @@ -220,9 +239,9 @@ async function fetchMissingData(
}
);
let actionPromises = Object.entries(actionsToFetch).map(
async ([key, { publicKey, tokenId }]) => {
async ([key, { publicKey, actionHashes, tokenId }]) => {
let response = await fetchActions(
{ publicKey, tokenId },
{ publicKey, actionHashes, tokenId },
archiveEndpoint
);
if (!('error' in response) || response.error === undefined)
Expand Down Expand Up @@ -558,7 +577,10 @@ type FetchedActions = {
blockInfo: {
distanceFromMaxBlockHeight: number;
};
actionState: string;
actionState: {
actionStateOne: string;
actionStateTwo: string;
};
actionData: {
accountUpdateId: string;
data: string[];
Expand Down Expand Up @@ -606,23 +628,27 @@ const getEventsQuery = (
};
const getActionsQuery = (
publicKey: string,
actionHashes: { fromActionHash?: string; endActionHash?: string },
tokenId: string,
filterOptions?: EventActionFilterOptions
_filterOptions?: EventActionFilterOptions
) => {
const { to, from } = filterOptions ?? {};
const { fromActionHash, endActionHash } = actionHashes ?? {};
let input = `address: "${publicKey}", tokenId: "${tokenId}"`;
if (to !== undefined) {
input += `, to: ${to}`;
if (fromActionHash !== undefined) {
input += `, fromActionHash: "${fromActionHash}"`;
}
if (from !== undefined) {
input += `, from: ${from}`;
if (endActionHash !== undefined) {
input += `, endActionHash: "${endActionHash}"`;
}
return `{
actions(input: { ${input} }) {
blockInfo {
distanceFromMaxBlockHeight
}
actionState
actionState {
actionStateOne
actionStateTwo
}
actionData {
accountUpdateId
data
Expand Down Expand Up @@ -711,20 +737,23 @@ async function fetchEvents(
}

async function fetchActions(
accountInfo: { publicKey: string; tokenId?: string },
graphqlEndpoint = archiveGraphqlEndpoint,
filterOptions: EventActionFilterOptions = {}
accountInfo: {
publicKey: string;
actionHashes: { fromActionHash?: string; endActionHash?: string };
tokenId?: string;
},
graphqlEndpoint = archiveGraphqlEndpoint
) {
if (!graphqlEndpoint)
throw new Error(
'fetchEvents: Specified GraphQL endpoint is undefined. Please specify a valid endpoint.'
);
const { publicKey, tokenId } = accountInfo;
const { publicKey, actionHashes, tokenId } = accountInfo;
let [response, error] = await makeGraphqlRequest(
getActionsQuery(
publicKey,
tokenId ?? TokenId.toBase58(TokenId.default),
filterOptions
actionHashes,
tokenId ?? TokenId.toBase58(TokenId.default)
),
graphqlEndpoint
);
Expand Down Expand Up @@ -771,10 +800,12 @@ async function fetchActions(
// Archive Node API returns actions in the latest order, so we reverse the array to get the actions in chronological order.
fetchedActions.reverse();
let actionsList: { actions: string[][]; hash: string }[] = [];
let latestActionsHash = SequenceEvents.emptySequenceState();

fetchedActions.forEach((fetchedAction) => {
const { actionState, actionData } = fetchedAction;
const { actionData } = fetchedAction;
let latestActionsHash = Field(fetchedAction.actionState.actionStateTwo);
let actionState = Field(fetchedAction.actionState.actionStateOne);

if (actionData.length === 0)
throw new Error(
`No action data was found for the account ${publicKey} with the latest action state ${actionState}`
Expand Down
37 changes: 31 additions & 6 deletions src/lib/mina.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export {
fetchEvents,
getActions,
FeePayerSpec,
ActionHashes,
faucet,
waitForFunding,
getProofsEnabled,
Expand Down Expand Up @@ -148,6 +149,11 @@ type DeprecatedFeePayerSpec =
})
| undefined;

type ActionHashes = {
MartinMinkov marked this conversation as resolved.
Show resolved Hide resolved
fromActionHash?: Field;
endActionHash?: Field;
};

function reportGetAccountError(publicKey: string, tokenId: string) {
if (tokenId === TokenId.toBase58(TokenId.default)) {
return `getAccount: Could not find account for public key ${publicKey}`;
Expand Down Expand Up @@ -340,6 +346,7 @@ interface Mina {
) => ReturnType<typeof Fetch.fetchEvents>;
getActions: (
publicKey: PublicKey,
actionHashes: ActionHashes,
MartinMinkov marked this conversation as resolved.
Show resolved Hide resolved
tokenId?: Field
) => { hash: string; actions: string[][] }[];
proofsEnabled: boolean;
Expand Down Expand Up @@ -581,6 +588,7 @@ function LocalBlockchain({
},
getActions(
publicKey: PublicKey,
_actionHashes: ActionHashes,
MartinMinkov marked this conversation as resolved.
Show resolved Hide resolved
tokenId: Field = TokenId.default
): { hash: string; actions: string[][] }[] {
return (
Expand Down Expand Up @@ -817,9 +825,18 @@ function Network(input: { mina: string; archive: string } | string): Mina {
filterOptions
);
},
getActions(publicKey: PublicKey, tokenId: Field = TokenId.default) {
getActions(
publicKey: PublicKey,
actionHashes: ActionHashes,
tokenId: Field = TokenId.default
) {
if (currentTransaction()?.fetchMode === 'test') {
Fetch.markActionsToBeFetched(publicKey, tokenId, archiveEndpoint);
Fetch.markActionsToBeFetched(
publicKey,
actionHashes,
tokenId,
archiveEndpoint
);
let actions = Fetch.getCachedActions(publicKey, tokenId);
return actions ?? [];
}
Expand Down Expand Up @@ -906,10 +923,14 @@ let activeInstance: Mina = {
async transaction(sender: DeprecatedFeePayerSpec, f: () => void) {
return createTransaction(sender, f, 0);
},
fetchEvents(publicKey: PublicKey, tokenId: Field = TokenId.default) {
fetchEvents(_publicKey: PublicKey, _tokenId: Field = TokenId.default) {
throw Error('must call Mina.setActiveInstance first');
},
getActions(publicKey: PublicKey, tokenId: Field = TokenId.default) {
getActions(
_publicKey: PublicKey,
_actionHashes: ActionHashes,
_tokenId: Field = TokenId.default
) {
throw Error('must call Mina.setActiveInstance first');
},
proofsEnabled: true,
Expand Down Expand Up @@ -1055,8 +1076,12 @@ async function fetchEvents(
/**
* @return A list of emitted sequencing actions associated to the given public key.
*/
function getActions(publicKey: PublicKey, tokenId?: Field) {
return activeInstance.getActions(publicKey, tokenId);
function getActions(
publicKey: PublicKey,
actionHashes: ActionHashes,
tokenId?: Field
) {
return activeInstance.getActions(publicKey, actionHashes, tokenId);
}

function getProofsEnabled() {
Expand Down
9 changes: 8 additions & 1 deletion src/lib/zkapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1414,7 +1414,14 @@ Use the optional \`maxTransactionsWithActions\` argument to increase this number
? Ledger.fieldToBase58(endActionHash)
: undefined;

let actions = Mina.getActions(contract.address, contract.self.tokenId);
let actions = Mina.getActions(
contract.address,
{
fromActionHash,
endActionHash,
},
contract.self.tokenId
);

// gets the start/end indices of our array slice
let startIndex = start
Expand Down