-
Notifications
You must be signed in to change notification settings - Fork 4
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
adjust query to support ordering #107
Conversation
045c9c8
to
ddd8b27
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to better understand the design of this API but my initial reaction is-
sequenceNumber
makes more sense undertransactionInfo
since it is a property of the transaction. Also it needs block-height (assuming the API returns canonical blocks only) to disambiguate transactions with same sequence numbers but are part of different blocks. So the client can order by block height and sequence number- Same with
zkappAccountUpdateIds
since it describes the order of the account updates within a transaction. Also, I think we'll want to expose the index of the account-id that this action corresponds to. A client can then order by block-height + sequence-number + account-update-sequence-number zkappEventElementIds
: Similar tozkappAccountUpdateIds
because events/actions are a list of field elements. The API returns an array of field elements for both actions and events but this array may not be in the same order as it was in the account update. So we might want to use the ordering inzkappEventElementIds
fromzke.element_ids
for actions and events respectively. Finally the order for actions/events for an account across a few different blocks will be based on block-height + transaction-sequence-number + account-sequence-number + event-sequence-number.
Yes, I will have to work on the format. Here's what I can produce on the current branch: {
"data": {
"actions": [
{
"blockInfo": {
"stateHash": "3NKZqA81s8iHMQc4vcJxrcx6epVB7C9vBD8oV7K3EpCZzvfebCtP",
"timestamp": "1729695587000",
"height": 69,
"parentHash": "3NLAneCAdNdj2u6DW5ycvUAvuJZP4mMain7eLWEU6QvL9ZTmZ53i",
"chainStatus": "canonical",
"distanceFromMaxBlockHeight": 36,
"globalSlotSinceGenesis": 132
},
"actionState": {
"actionStateOne": "25619375377485241455325506385026113155326956491463643967090964080969742671789",
"actionStateTwo": "25079927036070901246064867767436987657692091363973573142121686150614948079097",
"actionStateThree": "25079927036070901246064867767436987657692091363973573142121686150614948079097",
"actionStateFour": "25079927036070901246064867767436987657692091363973573142121686150614948079097",
"actionStateFive": "25079927036070901246064867767436987657692091363973573142121686150614948079097"
},
"actionData": [
{
"data": [
"24650",
"1",
"63073",
"4611450100234868895111341341933539196411650948711574062334330094836938200670",
"1"
],
"accountUpdateId": "27",
"transactionInfo": {
"status": "applied",
"hash": "5JvAynd7NAHEiMqCpgZD85WCzLniBv18eSEJyuvNVK8pQL8Fi5kx",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 2,
"zkappAccountUpdateIds": [
27,
28
],
"zkappEventElementIds": [
23
]
},
{
"data": [
"24651",
"1",
"63073",
"4611450100234868895111341341933539196411650948711574062334330094836938200670",
"1"
],
"accountUpdateId": "28",
"transactionInfo": {
"status": "applied",
"hash": "5JvAynd7NAHEiMqCpgZD85WCzLniBv18eSEJyuvNVK8pQL8Fi5kx",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 2,
"zkappAccountUpdateIds": [
27,
28
],
"zkappEventElementIds": [
24
]
},
{
"data": [
"73587",
"1",
"92297",
"8253926607854573680301530978054957179571865656842078211022112667228198387920",
"1"
],
"accountUpdateId": "25",
"transactionInfo": {
"status": "applied",
"hash": "5JumftuGBSY8x4yHpqvpg4gDWUnEpuZ8335Nxr5FgsXxmUsqmX8J",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 1,
"zkappAccountUpdateIds": [
25,
26
],
"zkappEventElementIds": [
21
]
},
{
"data": [
"73588",
"1",
"92297",
"8253926607854573680301530978054957179571865656842078211022112667228198387920",
"1"
],
"accountUpdateId": "26",
"transactionInfo": {
"status": "applied",
"hash": "5JumftuGBSY8x4yHpqvpg4gDWUnEpuZ8335Nxr5FgsXxmUsqmX8J",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 1,
"zkappAccountUpdateIds": [
25,
26
],
"zkappEventElementIds": [
22
]
},
{
"data": [
"55455",
"1",
"86171",
"476632679643188528985438056980162363837707337312210785567256027534077014652",
"0"
],
"accountUpdateId": "23",
"transactionInfo": {
"status": "applied",
"hash": "5Ju8GoXZWFqBKTAv3b1iMbc77yUhZEoVc5RwD5aj3VQw5eCkHwU9",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 0,
"zkappAccountUpdateIds": [
23,
24
],
"zkappEventElementIds": [
19
]
},
{
"data": [
"55456",
"1",
"86171",
"476632679643188528985438056980162363837707337312210785567256027534077014652",
"0"
],
"accountUpdateId": "24",
"transactionInfo": {
"status": "applied",
"hash": "5Ju8GoXZWFqBKTAv3b1iMbc77yUhZEoVc5RwD5aj3VQw5eCkHwU9",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 0,
"zkappAccountUpdateIds": [
23,
24
],
"zkappEventElementIds": [
20
]
}
]
},
{
"blockInfo": {
"stateHash": "3NLEZvkc7Z1mRdFkh1bSppnKo8aZrB6VGe83J7UdKpL4PuLjtjqB",
"timestamp": "1729695707000",
"height": 70,
"parentHash": "3NKZqA81s8iHMQc4vcJxrcx6epVB7C9vBD8oV7K3EpCZzvfebCtP",
"chainStatus": "canonical",
"distanceFromMaxBlockHeight": 35,
"globalSlotSinceGenesis": 138
},
"actionState": {
"actionStateOne": "7365288285578028013264727183932035337741887015276045401228215954698411077529",
"actionStateTwo": "25619375377485241455325506385026113155326956491463643967090964080969742671789",
"actionStateThree": "25079927036070901246064867767436987657692091363973573142121686150614948079097",
"actionStateFour": "25079927036070901246064867767436987657692091363973573142121686150614948079097",
"actionStateFive": "25079927036070901246064867767436987657692091363973573142121686150614948079097"
},
"actionData": [
{
"data": [
"73850",
"1",
"11895",
"8253926607854573680301530978054957179571865656842078211022112667228198387920",
"1"
],
"accountUpdateId": "33",
"transactionInfo": {
"status": "applied",
"hash": "5JuunjPt2xffChmddFDzdreN3TtTsADs1AiW4cgPXkYoFERyKPAi",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 3,
"zkappAccountUpdateIds": [
33,
34
],
"zkappEventElementIds": [
29
]
},
{
"data": [
"73851",
"1",
"11895",
"8253926607854573680301530978054957179571865656842078211022112667228198387920",
"1"
],
"accountUpdateId": "34",
"transactionInfo": {
"status": "applied",
"hash": "5JuunjPt2xffChmddFDzdreN3TtTsADs1AiW4cgPXkYoFERyKPAi",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 3,
"zkappAccountUpdateIds": [
33,
34
],
"zkappEventElementIds": [
30
]
},
{
"data": [
"73237",
"1",
"52294",
"476632679643188528985438056980162363837707337312210785567256027534077014652",
"0"
],
"accountUpdateId": "31",
"transactionInfo": {
"status": "applied",
"hash": "5JtuWFstMC6m3wgeoX8E5Nh1ZdwRdGXvhcrVbGB247Ph72KGpL23",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 1,
"zkappAccountUpdateIds": [
31,
32
],
"zkappEventElementIds": [
27
]
},
{
"data": [
"73238",
"1",
"52294",
"476632679643188528985438056980162363837707337312210785567256027534077014652",
"0"
],
"accountUpdateId": "32",
"transactionInfo": {
"status": "applied",
"hash": "5JtuWFstMC6m3wgeoX8E5Nh1ZdwRdGXvhcrVbGB247Ph72KGpL23",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 1,
"zkappAccountUpdateIds": [
31,
32
],
"zkappEventElementIds": [
28
]
},
{
"data": [
"35093",
"1",
"39852",
"4611450100234868895111341341933539196411650948711574062334330094836938200670",
"1"
],
"accountUpdateId": "29",
"transactionInfo": {
"status": "applied",
"hash": "5JtrkeMGmJFJQkVk27EtUsmzkLeiCinetkiwvVBfuHXrMqrwJvj2",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 0,
"zkappAccountUpdateIds": [
29,
30
],
"zkappEventElementIds": [
25
]
},
{
"data": [
"35094",
"1",
"39852",
"4611450100234868895111341341933539196411650948711574062334330094836938200670",
"1"
],
"accountUpdateId": "30",
"transactionInfo": {
"status": "applied",
"hash": "5JtrkeMGmJFJQkVk27EtUsmzkLeiCinetkiwvVBfuHXrMqrwJvj2",
"memo": "E4YM2vTHhWEg66xpj52JErHUBU4pZ1yageL4TVDDpTTSsv8mK6YaH"
},
"sequenceNumber": 0,
"zkappAccountUpdateIds": [
29,
30
],
"zkappEventElementIds": [
26
]
}
]
}
]
}
} |
It looks like all the data is there, but it can be better-organized. @deepthiskumar, do you know the relationship between events and actions? It seems like each transaction here has one event id, and 2 action ids. My test script does generate 2 actions per transaction, so I expected that, but I'm not sure why only one event would be sent. |
This is already available, as I could add a property, |
So we could have a response like
We have enough info here to tell us within the block that it's in, it belongs to transaction 2, and it is the second update in that sequence. That seems good enough to me, as long as that is the correct way to order things. |
For pending blocks, it looks like we follow the longest chain rule here:
We can probably handle filtering for canonical blocks in o1js. For reducing actions, I think we can ignore pending blocks by default, but for random exploratory queries, people might be interested to see pending data as well. |
d8f0b60
to
030c60f
Compare
tests/makeActionsRequest.ts
Outdated
@@ -0,0 +1,66 @@ | |||
import { createYoga, createSchema } from 'graphql-yoga'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole file may be better to remove. It's just a script to make a graphql request against the local API.
@@ -157,4 +157,26 @@ class ActionsService implements IActionsService { | |||
} | |||
return actions; | |||
} | |||
|
|||
sortActions(actions: Action[]): Action[] { | |||
return actions.sort((a, b) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since actions are returned grouped by block, this is focused on ordering the actions within a block.
I'm not sure the sort order is correct. Maybe it's reversed, but we should get it right, then we will have access to the unit test as a spec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@deepthiskumar it's worth noting that you and gregor both mentioned a sub-order to the account update in o1-labs/o1js#1872
It is your point 4, and Gregor said "It's extremely important that when reordering the actions here, the order within the same account update is maintained".
This sort only looks at sequence number and account update id. But with my JSON comment on this PR and this code, we should be able to get on the same page more easily. If there's a third sorting lever we need here, then I can add it, but it's not clear to me what it is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the third sorting lever is the element ID index from zkappEventElementIds
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So as linked in my other comment, I think we only need to sort to the event field array
level. Then all the fields from all the field arrays get put into data
in the correct order.
tests/resolvers.test.ts
Outdated
/* fundNewAccount = */ false | ||
); | ||
} catch (error) { | ||
console.error(error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This console was helpful in debugging. Errors were swallowed otherwise.
Those are two separate fields in the transaction. Events are more for recording information corresponding to an account update. They don't change any on-chain state. Actions on the other hand are committed to the account ( Can you generate at least two account updates (excluding the fee payer account update) each having two or more events and two or more actions? I think that should cover all the cases. |
Adding the index or a sequence field makes more sense to me than exposing account ID that is not consistent across DBs. If one were to run the API on two different DBs (or existing DB was updated during migration) then they could get different values for the same field. But with a sequence number or index they should be consistent across all archive DBs. Imo none of the database ID fields should be exposed to the client to ensure the client side application doesn't get tightly coupled to the database instance serving the API |
This fundamentally makes sense to me, but just to confirm, there is not literally an account update index value in the DB, it's something that needs to be calculated right? e.g. as I do here? The only thing I worry about is the added compute cost to calculate this every time. It seems quite cheap, but perhaps at scale it's not acceptable. If that's the right solution for the long term, it's also a possibility to do a quick fix now and a migration of the archive DB in the future to better serve this use case. |
@boray is going to advance this PR while I'm on PTO, so to do a quick summary of the changes I suggest based on your feedback:
Important Don't remove any values from the graphQL schema, because it should continue to work with older o1js versions which will make the old query. We can consider the db identifier fields deprecated though. |
Yes, the index needs to be computed given the current schema. It is an option to do in the archive processor and have a new table to store the sequence number and the corresponding element ID. It is not clear to me if it is a better option (another huge table to join vs looking up in arrays) |
src/blockchain/types.ts
Outdated
@@ -41,6 +41,9 @@ export type TransactionInfo = { | |||
hash: string; | |||
memo: string; | |||
authorizationKind: string; | |||
sequenceNumber: number; | |||
zkappAccountUpdateIds: number[]; | |||
zkappEventElementIds: number[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll want another similar field for Events (this is for Actions) to include as part of the Events data, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need that, assuming events will not be sorted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assuming events will not be sorted
Not sure what you mean by this. Events are recorded in the same order as actions i.e., sequence of blocks, sequence of transactions within a block, sequence of account updates within a transaction and sequence of events within an account update. The only difference is that the actions are accumulated on chain in action state and so one will always want to know the order of actions to validate against action states. For events it is more of a utility where an app might want to process events in the order they were confirmed/included in the chain. As an AP,I it seems like it should be providing that utility
There's actually another order that I didn't account for in my previous messages. I've updated now o1-labs/o1js#1872 (comment) |
Please note that the current branch has failing tests, but CI is green. I will try to resolve that in the next commit, but this is still WIP. |
4b3b73f
to
d453a59
Compare
Another one to reduce the complexity of reviewing #107 This PR: - exposes port 8282 on docker in CI, which is used by lightnet - improves the resolver tests - properly annotates the type of the graphQL response object - exits the process with code `1` on error instead of always exiting with code `0` - makes use of additional describe blocks to clarify the test cases - explicitly test response data for correctness, rather than metadata like length only Since there are no implementation changes here, we can be more confident about changes to the test file, then in the other PR where I do change the implementation, I will be able to leave existing tests as-is.
this.emitEvent('struct', struct); | ||
} | ||
|
||
@method async emitStructsEvent(structs: TestStructArray) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updating these methods give us more variance to test with - not just emitting the same thing over and over.
const x = this.x.getAndRequireEquals(); | ||
const y = this.y.getAndRequireEquals(); | ||
const z = this.z.getAndRequireEquals(); | ||
this.reducer.dispatch(new TestStruct({ x, y, z, address: this.address })); | ||
const struct = new TestStruct({ x, y, z, address: this.address }); | ||
this.reducer.dispatch({ structs: [struct, struct, struct] }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One contract may have many types of events, but only one type of action. To keep the tests slightly simple and fast, I updated this action type to the most complex: One action with multiple field arrays with multiple fields.
The alternative was writing a new contract where one has a simple action type and one has a complex action type, and we would need to await compile, deploy, etc... on both.
Ok, tests are green and this is ready for review! |
src/db/sql/events-actions/types.ts
Outdated
// List of `element_ids` that are used to construct the zkApp event. | ||
zkapp_event_element_ids: number[]; | ||
|
||
// List of `element_ids` that are used to construct the field array. | ||
zkapp_field_array_element_ids: number[]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The naming is confusing and it is making it a bit difficult to review the code for me. May I suggest the following-
account_update_events_id
: id of an array of events per account updateaccount_update_event_id
: id of a single event in an account update.account_update_events_id
(from 1) points to an array ofaccount_update_event_id
event_field_elements_id
: Id of an array of field elements. Each event (account_update_event_id
from 2) corresponds to an array of field elementsevent_field_element_id
: Id of a field element.event_field_elements_id
(from 3) points to an array ofevent_field_element_id
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This type is the ArchiveNodeDatabaseRow
, and I believe it should retain the column names of the query result (I'll take another pass and make sure it does, and see if the new columns I added can be named better).
But I will take this feedback and apply it to the user-facing types.
src/resolvers-types.ts
Outdated
status: Scalars['String']['output']; | ||
zkappAccountUpdateIds: Array<Maybe<Scalars['Int']['output']>>; | ||
zkappEventElementIds: Array<Maybe<Scalars['Int']['output']>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename zkappEventElementIds
to accountUpdateEventIds
and zkappFieldArrayElementIds
to eventFieldElementIds
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up just removing these. I don't think we need to expose them in graphQL after all
); | ||
|
||
return aAccountUpdateIndex - bAccountUpdateIndex; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this include action ids and field element ids also? The protocol supports multiple actions per account update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, are we not doing similar sorting for events?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this include action ids and field element ids also? The protocol supports multiple actions per account update
Within one account update, the actions are ordered within the data
property in the response, see: https://github.com/o1-labs/Archive-Node-API/pull/107/files#diff-ce4b532132cbf96cc52ea84724fbfa50698c62ca9c690844068dafbfc687d3a8R341
const structData = eventData.data;
assert.strictEqual(structData.length, 16);
assert.strictEqual(structData[0], '2');
assert.deepStrictEqual(
structData.slice(1, 6),
structToAction(expectedS1)
);
assert.deepStrictEqual(
structData.slice(6, 11),
structToAction(expectedS2)
);
assert.deepStrictEqual(
structData.slice(11, 16),
structToAction(expectedS3)
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't changed the intra-AU event order here, as it seems to be correct already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, are we not doing similar sorting for events?
I've always been told as a zkapp developer that event order is not guaranteed, so I don't think we need to. The only reason we need to sort actions is because an actions hash is committed to, and that hash uses a particular order that needs to be reproduced. There is no such events hash on chain, so no ordering should be necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The query here to fetch actions uses ANY
and so the ordering is not guaranteed. I'm guessing the ordering here just happens to be correct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I'll double check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@deepthiskumar we convert field arrays into data
here. It seems like we take the element_ids
for the correct order, and elementIdFieldValues
(key-value map) to access the correct values.
Maybe I can add a test to make sure this order is explicitly respected, but I think it happens to work correctly already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add such a test? I think that'll help a lot with order being preserved implicitly. Everything else looks good otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I will add a test in a fast-follow!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, responded to some of the naming issues at the database level. I will also improve the tying here and make sure to propagate the naming upstream as well, where relevant.
I will comment again when the PR is explicitly ready for review.
@@ -123,8 +123,8 @@ function removeRedundantEmittedFields( | |||
for (let i = 0; i < archiveNodeRow.length; i++) { | |||
const currentRow = archiveNodeRow[i]; | |||
const { | |||
zkapp_event_array_id, // The unique id for the event/action emitted | |||
zkapp_event_element_ids, // The list of field ids that make up the event/action | |||
event_field_elements_id, // The unique id for the field array in the current row |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the comments here weren't quite right. Following the comments explicitly led to test failures, so I found the intended inputs and updated the comments. Will double check the logic here.
@@ -106,8 +106,23 @@ function emittedZkAppCommandsCTE(db_client: postgres.Sql) { | |||
return db_client` | |||
emitted_zkapp_commands AS ( | |||
SELECT | |||
blocks_accessed.*, | |||
blocks_accessed.requesting_zkapp_account_identifier_id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expanding *
queries is optional, but I think it will be more clear for the next person who has to dig here. I struggled to make sense of these queries at first.
/** | ||
* A Field is the smallest unit of raw data in an Event | ||
*/ | ||
namespace Field { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Namespaces are also optional. It gives the ArchiveNodeDatabaseRow
columns some more clarity, since zkappEventElementFieldArrayElementValue
is not obvious!
*/ | ||
export type ArchiveNodeDatabaseRow = { | ||
// Unique block identifier. | ||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* List of `element_ids` that are used to construct the field array. | ||
* Each entry corresponds to a `Field.Id`, linking to a `Field`. | ||
*/ | ||
event_field_element_ids: EventFieldArray.FieldIds; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Example of how the namespace types are being used.
@@ -157,4 +157,26 @@ class ActionsService implements IActionsService { | |||
} | |||
return actions; | |||
} | |||
|
|||
sortActions(actions: Action[]): Action[] { | |||
return actions.sort((a, b) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So as linked in my other comment, I think we only need to sort to the event field array
level. Then all the fields from all the field arrays get put into data
in the correct order.
@@ -12,7 +12,7 @@ import { ArchiveNodeDatabaseRow } from '../src/db/sql/events-actions/types.js'; | |||
describe('utils', () => { | |||
describe('partitionBlocks', () => { | |||
test('should partition rows by block hash and transaction hash', () => { | |||
const rows: any[] = [ | |||
const rows: Partial<ArchiveNodeDatabaseRow>[] = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Partial<>
over any
so that invalid keys are flagged as an error
Hello there, please excuse me in advance if this off-track. I am not sure if this falls within #106 scope, but when doing the events query (or actions), it appears that there is no way to know what is the latest blockHeight currently in the database when the results set is empty. This information is present within the SQL queries ( It could be helpful to know what is the Would it be within the scope of this PR to add it ? Or should I open a different issue ? |
@Hebilicious great feedback! Please open a different issue for this, but it sounds pretty straightforward to me! |
Fixes: #106
This PR adds
sequenceNumber
, as well aszkappAccountUpdateIds
to the graphQL schema, which will expose enough information for clients to verify the order in which actions were processed by consensus. It also attempts to return actions in that order, and exposes the ordering spec in a unit test.We also overhaul the test contract and test suite to emit more random and different values so that sequential events and actions can be identified by their data.
I have tested this branch locally against the sibling branch in o1js.