From a4b2c12e77b0d86b2428413aafe1bbe621803217 Mon Sep 17 00:00:00 2001 From: ptrus Date: Mon, 27 Jan 2025 14:06:11 +0100 Subject: [PATCH] storage: split consensus event related accounts into separate table --- .changelog/809.feature.2.md | 1 + analyzer/consensus/consensus.go | 71 +++++++++++++++--- analyzer/consensus/data_fetch.go | 16 ++++ analyzer/queries/queries.go | 6 +- storage/client/queries/queries.go | 28 +++++-- storage/migrations/00_consensus.up.sql | 5 +- storage/migrations/01_runtimes.up.sql | 12 +-- .../14_events_related_accounts.up.sql | 75 +++++++++++++++++++ storage/oasis/nodeapi/api.go | 7 +- storage/oasis/nodeapi/cobalt/convert.go | 24 +++--- storage/oasis/nodeapi/cobalt/node.go | 8 +- storage/oasis/nodeapi/damask/convert.go | 24 +++--- storage/oasis/nodeapi/damask/node.go | 8 +- storage/oasis/nodeapi/eden/convert.go | 24 +++--- storage/oasis/nodeapi/eden/node.go | 8 +- tests/e2e_regression/common_test_cases.sh | 2 +- .../damask/expected/events.body | 8 +- 17 files changed, 249 insertions(+), 78 deletions(-) create mode 100644 .changelog/809.feature.2.md create mode 100644 storage/migrations/14_events_related_accounts.up.sql diff --git a/.changelog/809.feature.2.md b/.changelog/809.feature.2.md new file mode 100644 index 000000000..e0d36954d --- /dev/null +++ b/.changelog/809.feature.2.md @@ -0,0 +1 @@ +storage: split consensus event related accounts into a separate table diff --git a/analyzer/consensus/consensus.go b/analyzer/consensus/consensus.go index ecbc52ccb..59cb4e509 100644 --- a/analyzer/consensus/consensus.go +++ b/analyzer/consensus/consensus.go @@ -43,6 +43,7 @@ const ( type EventType = apiTypes.ConsensusEventType // alias for brevity type parsedEvent struct { + eventIdx int ty EventType rawBody json.RawMessage roothashRuntimeID *coreCommon.Namespace @@ -253,12 +254,14 @@ func (m *processor) queueDbUpdates(batch *storage.QueryBatch, data allData) erro m.queueBlockInserts, m.queueEpochInserts, m.queueTransactionInserts, - m.queueTxEventInserts, } { if err := f(batch, data.BlockData); err != nil { return err } } + if err := m.queueTxEventInserts(batch, &data); err != nil { + return err + } for _, f := range []func(*storage.QueryBatch, *registryData) error{ m.queueEntityEvents, @@ -586,8 +589,8 @@ func (m *processor) queueTransactionInserts(batch *storage.QueryBatch, data *con } // Enqueue DB statements to store events that were generated as the result of a TX execution. -func (m *processor) queueTxEventInserts(batch *storage.QueryBatch, data *consensusBlockData) error { - for i, txr := range data.TransactionsWithResults { +func (m *processor) queueTxEventInserts(batch *storage.QueryBatch, data *allData) error { + for i, txr := range data.BlockData.TransactionsWithResults { txAccounts := []staking.Address{ // Always insert sender as a related address, some transactions (e.g. failed ones) might not have // any events associated. @@ -595,7 +598,36 @@ func (m *processor) queueTxEventInserts(batch *storage.QueryBatch, data *consens // much transaction parsing, where we could extract it for each transaction type. staking.NewAddress(txr.Transaction.Signature.PublicKey), } - for _, event := range txr.Result.Events { + + // Find all events associated with transaction. + // We don't use txr.Result.Events, because those do not have the event index unique within the block. + txEvents := make([]nodeapi.Event, 0, len(txr.Result.Events)) + for _, event := range data.GovernanceData.Events { + if event.TxHash == txr.Transaction.Hash() { + txEvents = append(txEvents, event) + } + } + for _, event := range data.RegistryData.Events { + if event.TxHash == txr.Transaction.Hash() { + txEvents = append(txEvents, event) + } + } + for _, event := range data.RootHashData.Events { + if event.TxHash == txr.Transaction.Hash() { + txEvents = append(txEvents, event) + } + } + for _, event := range data.StakingData.Events { + if event.TxHash == txr.Transaction.Hash() { + txEvents = append(txEvents, event) + } + } + // Sanity check that the number of event matches. + if len(txEvents) != len(txr.Result.Events) { + return fmt.Errorf("transaction %s has %d events, but only %d were found", txr.Transaction.Hash().Hex(), len(txr.Result.Events), len(txEvents)) + } + + for _, event := range txEvents { eventData := m.extractEventData(event) txAccounts = append(txAccounts, eventData.relatedAddresses...) accounts := extractUniqueAddresses(eventData.relatedAddresses) @@ -605,22 +637,29 @@ func (m *processor) queueTxEventInserts(batch *storage.QueryBatch, data *consens } batch.Queue(queries.ConsensusEventInsert, + data.BlockData.Height, string(eventData.ty), + eventData.eventIdx, string(body), - data.Height, txr.Transaction.Hash().Hex(), i, - accounts, common.StringOrNil(eventData.roothashRuntimeID), eventData.roothashRuntime, eventData.roothashRuntimeRound, ) + batch.Queue(queries.ConsensusEventRelatedAccountsInsert, + data.BlockData.Height, + string(eventData.ty), + eventData.eventIdx, + i, + accounts, + ) } uniqueTxAccounts := extractUniqueAddresses(txAccounts) for _, addr := range uniqueTxAccounts { batch.Queue(queries.ConsensusAccountRelatedTransactionInsert, addr, - data.Height, + data.BlockData.Height, i, ) @@ -630,7 +669,7 @@ func (m *processor) queueTxEventInserts(batch *storage.QueryBatch, data *consens batch.Queue( queries.ConsensusAccountFirstActivityUpsert, addr, - data.BlockHeader.Time.UTC(), + data.BlockData.BlockHeader.Time.UTC(), ) } } @@ -1376,16 +1415,23 @@ func (m *processor) queueSingleEventInserts(batch *storage.QueryBatch, eventData } batch.Queue(queries.ConsensusEventInsert, + height, string(eventData.ty), + eventData.eventIdx, string(body), - height, nil, nil, - accounts, common.StringOrNil(eventData.roothashRuntimeID), eventData.roothashRuntime, eventData.roothashRuntimeRound, ) + batch.Queue(queries.ConsensusEventRelatedAccountsInsert, + height, + string(eventData.ty), + eventData.eventIdx, + nil, + accounts, + ) return nil } @@ -1408,8 +1454,9 @@ func extractUniqueAddresses(accounts []staking.Address) []string { // extractEventData extracts the type, the body (JSON-serialized), and the related accounts of an event. func (m *processor) extractEventData(event nodeapi.Event) parsedEvent { eventData := parsedEvent{ - ty: event.Type, - rawBody: event.RawBody, + eventIdx: event.EventIdx, + ty: event.Type, + rawBody: event.RawBody, } // Fill in related accounts. diff --git a/analyzer/consensus/data_fetch.go b/analyzer/consensus/data_fetch.go index ca014be3f..b211f202e 100644 --- a/analyzer/consensus/data_fetch.go +++ b/analyzer/consensus/data_fetch.go @@ -160,6 +160,10 @@ func fetchRegistryData(ctx context.Context, cc nodeapi.ConsensusApiLite, height if err != nil { return nil, err } + // XXX: We do this here, so that we don't need to invalidate the caches. + for i := range events { + events[i].EventIdx = i + } var runtimeStartedEvents []nodeapi.RuntimeStartedEvent var runtimeSuspendedEvents []nodeapi.RuntimeSuspendedEvent @@ -199,6 +203,10 @@ func fetchStakingData(ctx context.Context, cc nodeapi.ConsensusApiLite, height i if err != nil { return nil, err } + // XXX: We do this here, so that we don't need to invalidate the caches. + for i := range events { + events[i].EventIdx = i + } epoch, err := cc.GetEpoch(ctx, height) if err != nil { @@ -281,6 +289,10 @@ func fetchGovernanceData(ctx context.Context, cc nodeapi.ConsensusApiLite, heigh if err != nil { return nil, err } + // XXX: We do this here, so that we don't need to invalidate the caches. + for i := range events { + events[i].EventIdx = i + } var submissions []nodeapi.Proposal var executions []nodeapi.ProposalExecutedEvent @@ -324,6 +336,10 @@ func fetchRootHashData(ctx context.Context, cc nodeapi.ConsensusApiLite, network if err != nil { return nil, err } + // XXX: We do this here, so that we don't need to invalidate the caches. + for i := range events { + events[i].EventIdx = i + } lastRoundResults := make(map[coreCommon.Namespace]*roothash.RoundResults, len(network.ParaTimes.All)) diff --git a/analyzer/queries/queries.go b/analyzer/queries/queries.go index bf17fab12..313c3ee2f 100644 --- a/analyzer/queries/queries.go +++ b/analyzer/queries/queries.go @@ -269,9 +269,13 @@ var ( schedule = excluded.schedule` ConsensusEventInsert = ` - INSERT INTO chain.events (type, body, tx_block, tx_hash, tx_index, related_accounts, roothash_runtime_id, roothash_runtime, roothash_runtime_round) + INSERT INTO chain.events (tx_block, type, event_index, body, tx_hash, tx_index, roothash_runtime_id, roothash_runtime, roothash_runtime_round) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)` + ConsensusEventRelatedAccountsInsert = ` + INSERT INTO chain.events_related_accounts (tx_block, type, event_index, tx_index, account_address) + SELECT $1, $2, $3, $4, unnest($5::text[])` + ConsensusEscrowEventInsert = ` INSERT INTO history.escrow_events (tx_block, epoch, type, delegatee, delegator, shares, amount, debonding_amount) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)` diff --git a/storage/client/queries/queries.go b/storage/client/queries/queries.go index a2232ac95..f31e3bb56 100644 --- a/storage/client/queries/queries.go +++ b/storage/client/queries/queries.go @@ -101,15 +101,29 @@ const ( OFFSET $9::bigint` Events = ` - SELECT tx_block, tx_index, tx_hash, roothash_runtime_id, roothash_runtime, roothash_runtime_round, type, body, b.time + SELECT + chain.events.tx_block, + chain.events.tx_index, + chain.events.tx_hash, + chain.events.roothash_runtime_id, + chain.events.roothash_runtime, + chain.events.roothash_runtime_round, + chain.events.type, + chain.events.body, + b.time FROM chain.events LEFT JOIN chain.blocks b ON tx_block = b.height - WHERE ($1::bigint IS NULL OR tx_block = $1::bigint) AND - ($2::integer IS NULL OR tx_index = $2::integer) AND - ($3::text IS NULL OR tx_hash = $3::text) AND - ($4::text IS NULL OR type = $4::text) AND - ($5::text IS NULL OR ARRAY[$5::text] <@ related_accounts) - ORDER BY tx_block DESC, tx_index + LEFT JOIN chain.events_related_accounts rel ON + chain.events.tx_block = rel.tx_block AND + chain.events.event_index = rel.event_index AND + -- When related_address ($5) is NULL and hence we do no filtering on it, avoid the join altogether. + ($5::text IS NOT NULL) + WHERE ($1::bigint IS NULL OR chain.events.tx_block = $1::bigint) AND + ($2::integer IS NULL OR chain.events.tx_index = $2::integer) AND + ($3::text IS NULL OR chain.events.tx_hash = $3::text) AND + ($4::text IS NULL OR chain.events.type = $4::text) AND + ($5::text IS NULL OR rel.account_address = $5::text) + ORDER BY chain.events.tx_block DESC, chain.events.tx_index LIMIT $6::bigint OFFSET $7::bigint` diff --git a/storage/migrations/00_consensus.up.sql b/storage/migrations/00_consensus.up.sql index 18bfc61c8..169f7281b 100644 --- a/storage/migrations/00_consensus.up.sql +++ b/storage/migrations/00_consensus.up.sql @@ -88,12 +88,13 @@ CREATE INDEX ix_transactions_method_block_tx_index ON chain.transactions (method CREATE TABLE chain.events ( tx_block UINT63 NOT NULL, + -- event_index UINT31 NOT NULL, -- Added in 14_events_related_accounts.up.sql tx_index UINT31, type TEXT NOT NULL, -- Enum with many values, see ConsensusEventType in api/spec/v1.yaml. body JSONB, tx_hash HEX64, -- could be fetched from `transactions` table; denormalized for efficiency - related_accounts TEXT[], + related_accounts TEXT[], -- Removed in 14_events_related_accounts.up.sql -- There's some mismatch between oasis-core's style in Go and nexus's -- style in SQL and JSON. oasis-core likes structures filled with nilable -- pointers, where one pointer is non-nil. nexus likes a type string plus @@ -112,7 +113,7 @@ CREATE TABLE chain.events FOREIGN KEY (tx_block, tx_index) REFERENCES chain.transactions(block, tx_index) DEFERRABLE INITIALLY DEFERRED ); -CREATE INDEX ix_events_related_accounts ON chain.events USING gin(related_accounts); +CREATE INDEX ix_events_related_accounts ON chain.events USING gin(related_accounts); -- Removed in 14_events_related_accounts.up.sql CREATE INDEX ix_events_tx_block ON chain.events (tx_block); -- for fetching events without filters CREATE INDEX ix_events_tx_hash ON chain.events (tx_hash); CREATE INDEX ix_events_type ON chain.events (type, tx_block); -- tx_block is for sorting the events of a given type by recency diff --git a/storage/migrations/01_runtimes.up.sql b/storage/migrations/01_runtimes.up.sql index d3384f2fa..570e92f60 100644 --- a/storage/migrations/01_runtimes.up.sql +++ b/storage/migrations/01_runtimes.up.sql @@ -155,8 +155,8 @@ CREATE TABLE chain.runtime_events timestamp TIMESTAMP WITH TIME ZONE NOT NULL, - -- The raw event, as returned by the oasis-sdk runtime client. type TEXT NOT NULL, + -- The raw event, as returned by the oasis-sdk runtime client. body JSONB NOT NULL, related_accounts TEXT[], -- Removed in 13_runtime_events_related_accounts.up.sql. @@ -196,14 +196,14 @@ CREATE INDEX ix_runtime_events_nft_transfers ON chain.runtime_events (runtime, ( -- ( -- runtime runtime NOT NULL, -- round UINT63 NOT NULL, --- tx_index UINT31 NOT NULL, --- type TEXT NOT NULL, --- type_index UINT31 NOT NULL, +-- event_index UINT31 NOT NULL, +-- tx_index UINT31, +-- type TEXT NOT NULL, -- account_address oasis_addr NOT NULL, --- FOREIGN KEY (runtime, round, tx_index, type, type_index) REFERENCES chain.runtime_events(runtime, round, tx_index, type, type_index) DEFERRABLE INITIALLY DEFERRED +-- FOREIGN KEY (runtime, round, event_index) REFERENCES chain.runtime_events(runtime, round, event_index) DEFERRABLE INITIALLY DEFERRED -- ); --- CREATE INDEX ix_runtime_events_related_accounts_related_account_round ON chain.runtime_events_related_accounts(runtime, account_address, round); +-- CREATE INDEX ix_runtime_events_related_accounts_account_address_round ON chain.runtime_events_related_accounts(runtime, account_address, round, tx_index); -- Roothash messages are small structures that a runtime can send to -- communicate with the consensus layer. They are agreed upon for each runtime diff --git a/storage/migrations/14_events_related_accounts.up.sql b/storage/migrations/14_events_related_accounts.up.sql new file mode 100644 index 000000000..e8e3d3606 --- /dev/null +++ b/storage/migrations/14_events_related_accounts.up.sql @@ -0,0 +1,75 @@ +BEGIN; + +ALTER TABLE chain.events ADD COLUMN event_index UINT31; + +-- Populate the event_index column with sequential values for each tx_block to ensure uniqueness. +DO $$ +DECLARE + cur_block UINT63; + cur_type TEXT; +BEGIN + -- Iterate over each unique (tx_block, type) pair. + FOR cur_block, cur_type IN + SELECT tx_block, type + FROM chain.events + GROUP BY tx_block, type + LOOP + -- Assign event_index within the group. + WITH ranked_events AS ( + SELECT ctid, + row_number() OVER (ORDER BY timestamp ASC) - 1 AS event_idx + FROM chain.events + WHERE tx_block = cur_block AND type = cur_type + ) + UPDATE chain.events e + SET event_index = ranked_events.event_idx + FROM ranked_events + WHERE e.ctid = ranked_events.ctid; + END LOOP; +END $$; + +ALTER TABLE chain.events + ALTER COLUMN event_index SET NOT NULL; + +-- Primary key for runtime events. +ALTER TABLE chain.events + ADD CONSTRAINT pk_events PRIMARY KEY (tx_block, type, event_index); + + +-- Create events related accounts table. +CREATE TABLE chain.events_related_accounts +( + tx_block UINT63 NOT NULL, + type TEXT NOT NULL, + event_index UINT31 NOT NULL, + + tx_index UINT31, + account_address oasis_addr NOT NULL, + + FOREIGN KEY (tx_block, type, event_index) REFERENCES chain.events(tx_block, type, event_index) DEFERRABLE INITIALLY DEFERRED +); + +-- Populate the events_related_accounts table. +INSERT INTO + chain.events_related_accounts (tx_block, type, event_index, tx_index, account_address) +SELECT + tx_block, type, event_index, tx_index, unnest(related_accounts) AS account_address +FROM + chain.events +WHERE + related_accounts IS NOT NULL + AND array_length(related_accounts, 1) > 0; + + +-- Used for fetching all events related to an account (sorted by round). +CREATE INDEX ix_events_related_accounts_account_address_block ON chain.events_related_accounts(account_address, tx_block DESC, tx_index); -- TODO: maybe also event index? + +DROP INDEX chain.ix_events_related_accounts; +ALTER TABLE chain.events DROP COLUMN related_accounts; + +-- Grant others read-only use. +-- (We granted already in 00_consensus.up.sql, but the grant does not apply to new tables.) +GRANT SELECT ON ALL TABLES IN SCHEMA chain TO PUBLIC; +GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA chain TO PUBLIC; + +COMMIT; diff --git a/storage/oasis/nodeapi/api.go b/storage/oasis/nodeapi/api.go index 49f72da77..d0b5f8bb3 100644 --- a/storage/oasis/nodeapi/api.go +++ b/storage/oasis/nodeapi/api.go @@ -119,6 +119,10 @@ type Event struct { Height int64 TxHash hash.Hash + // Called "Kind" in oasis-core but "Type" in Nexus APIs and DBs. + Type apiTypes.ConsensusEventType + EventIdx int // Index of the event within the same block, same transaction and event type. + // The body of the Event struct as it was received from oasis-core. For most // event types, a summary of the event (containing only nexus-relevant fields) // will be present in one of the fields below (StakingTransfer, StakingBurn, etc.). @@ -128,9 +132,6 @@ type Event struct { // oasis-core types (which vary between versions) from Nexus. RawBody json.RawMessage - // Called "Kind" in oasis-core but "Type" in Nexus APIs and DBs. - Type apiTypes.ConsensusEventType - StakingTransfer *TransferEvent StakingBurn *BurnEvent StakingAddEscrow *AddEscrowEvent diff --git a/storage/oasis/nodeapi/cobalt/convert.go b/storage/oasis/nodeapi/cobalt/convert.go index a6a12dd10..20423a106 100644 --- a/storage/oasis/nodeapi/cobalt/convert.go +++ b/storage/oasis/nodeapi/cobalt/convert.go @@ -184,7 +184,7 @@ func ConvertGenesis(d genesisCobalt.Document) *nodeapi.GenesisDocument { } } -func convertStakingEvent(e stakingCobalt.Event) nodeapi.Event { +func convertStakingEvent(e stakingCobalt.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.Transfer != nil: @@ -251,10 +251,11 @@ func convertStakingEvent(e stakingCobalt.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertRegistryEvent(e registryCobalt.Event) nodeapi.Event { +func convertRegistryEvent(e registryCobalt.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.RuntimeEvent != nil && e.RuntimeEvent.Runtime != nil: @@ -326,10 +327,11 @@ func convertRegistryEvent(e registryCobalt.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertRoothashEvent(e roothashCobalt.Event) nodeapi.Event { +func convertRoothashEvent(e roothashCobalt.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.ExecutorCommitted != nil: @@ -392,10 +394,11 @@ func convertRoothashEvent(e roothashCobalt.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertGovernanceEvent(e governanceCobalt.Event) nodeapi.Event { +func convertGovernanceEvent(e governanceCobalt.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.ProposalSubmitted != nil: @@ -433,19 +436,20 @@ func convertGovernanceEvent(e governanceCobalt.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertEvent(e txResultsCobalt.Event) nodeapi.Event { +func convertEvent(e txResultsCobalt.Event, eventIdx int) nodeapi.Event { switch { case e.Staking != nil: - return convertStakingEvent(*e.Staking) + return convertStakingEvent(*e.Staking, eventIdx) case e.Registry != nil: - return convertRegistryEvent(*e.Registry) + return convertRegistryEvent(*e.Registry, eventIdx) case e.RootHash != nil: - return convertRoothashEvent(*e.RootHash) + return convertRoothashEvent(*e.RootHash, eventIdx) case e.Governance != nil: - return convertGovernanceEvent(*e.Governance) + return convertGovernanceEvent(*e.Governance, eventIdx) default: return nodeapi.Event{} } @@ -454,7 +458,7 @@ func convertEvent(e txResultsCobalt.Event) nodeapi.Event { func convertTxResult(r txResultsCobalt.Result) nodeapi.TxResult { events := make([]nodeapi.Event, len(r.Events)) for i, e := range r.Events { - events[i] = convertEvent(*e) + events[i] = convertEvent(*e, i) } return nodeapi.TxResult{ diff --git a/storage/oasis/nodeapi/cobalt/node.go b/storage/oasis/nodeapi/cobalt/node.go index 2f3519df0..30b6fad58 100644 --- a/storage/oasis/nodeapi/cobalt/node.go +++ b/storage/oasis/nodeapi/cobalt/node.go @@ -132,7 +132,7 @@ func (c *ConsensusApiLite) RegistryEvents(ctx context.Context, height int64) ([] } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsCobalt.Event{Registry: e}) + events[i] = convertEvent(txResultsCobalt.Event{Registry: e}, i) } return events, nil } @@ -144,7 +144,7 @@ func (c *ConsensusApiLite) StakingEvents(ctx context.Context, height int64) ([]n } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsCobalt.Event{Staking: e}) + events[i] = convertEvent(txResultsCobalt.Event{Staking: e}, i) } return events, nil } @@ -156,7 +156,7 @@ func (c *ConsensusApiLite) GovernanceEvents(ctx context.Context, height int64) ( } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsCobalt.Event{Governance: e}) + events[i] = convertEvent(txResultsCobalt.Event{Governance: e}, i) } return events, nil } @@ -168,7 +168,7 @@ func (c *ConsensusApiLite) RoothashEvents(ctx context.Context, height int64) ([] } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsCobalt.Event{RootHash: e}) + events[i] = convertEvent(txResultsCobalt.Event{RootHash: e}, i) } return events, nil } diff --git a/storage/oasis/nodeapi/damask/convert.go b/storage/oasis/nodeapi/damask/convert.go index 93c24e7e3..399f8cfb9 100644 --- a/storage/oasis/nodeapi/damask/convert.go +++ b/storage/oasis/nodeapi/damask/convert.go @@ -60,7 +60,7 @@ func convertProposal(p *governanceDamask.Proposal) *governance.Proposal { } } -func convertStakingEvent(e stakingDamask.Event) nodeapi.Event { +func convertStakingEvent(e stakingDamask.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.Transfer != nil: @@ -115,10 +115,11 @@ func convertStakingEvent(e stakingDamask.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertRegistryEvent(e registryDamask.Event) nodeapi.Event { +func convertRegistryEvent(e registryDamask.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.RuntimeEvent != nil && e.RuntimeEvent.Runtime != nil: @@ -190,10 +191,11 @@ func convertRegistryEvent(e registryDamask.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertRoothashEvent(e roothashDamask.Event) nodeapi.Event { +func convertRoothashEvent(e roothashDamask.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.ExecutorCommitted != nil: @@ -236,10 +238,11 @@ func convertRoothashEvent(e roothashDamask.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertGovernanceEvent(e governanceDamask.Event) nodeapi.Event { +func convertGovernanceEvent(e governanceDamask.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.ProposalSubmitted != nil: @@ -277,19 +280,20 @@ func convertGovernanceEvent(e governanceDamask.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertEvent(e txResultsDamask.Event) nodeapi.Event { +func convertEvent(e txResultsDamask.Event, eventIdx int) nodeapi.Event { switch { case e.Staking != nil: - return convertStakingEvent(*e.Staking) + return convertStakingEvent(*e.Staking, eventIdx) case e.Registry != nil: - return convertRegistryEvent(*e.Registry) + return convertRegistryEvent(*e.Registry, eventIdx) case e.RootHash != nil: - return convertRoothashEvent(*e.RootHash) + return convertRoothashEvent(*e.RootHash, eventIdx) case e.Governance != nil: - return convertGovernanceEvent(*e.Governance) + return convertGovernanceEvent(*e.Governance, eventIdx) default: return nodeapi.Event{} } @@ -298,7 +302,7 @@ func convertEvent(e txResultsDamask.Event) nodeapi.Event { func convertTxResult(r txResultsDamask.Result) nodeapi.TxResult { events := make([]nodeapi.Event, len(r.Events)) for i, e := range r.Events { - events[i] = convertEvent(*e) + events[i] = convertEvent(*e, i) } return nodeapi.TxResult{ diff --git a/storage/oasis/nodeapi/damask/node.go b/storage/oasis/nodeapi/damask/node.go index 9304f2390..9cae2c6a0 100644 --- a/storage/oasis/nodeapi/damask/node.go +++ b/storage/oasis/nodeapi/damask/node.go @@ -126,7 +126,7 @@ func (c *ConsensusApiLite) RegistryEvents(ctx context.Context, height int64) ([] } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsDamask.Event{Registry: e}) + events[i] = convertEvent(txResultsDamask.Event{Registry: e}, i) } return events, nil } @@ -138,7 +138,7 @@ func (c *ConsensusApiLite) StakingEvents(ctx context.Context, height int64) ([]n } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsDamask.Event{Staking: e}) + events[i] = convertEvent(txResultsDamask.Event{Staking: e}, i) } return events, nil } @@ -150,7 +150,7 @@ func (c *ConsensusApiLite) GovernanceEvents(ctx context.Context, height int64) ( } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsDamask.Event{Governance: e}) + events[i] = convertEvent(txResultsDamask.Event{Governance: e}, i) } return events, nil } @@ -162,7 +162,7 @@ func (c *ConsensusApiLite) RoothashEvents(ctx context.Context, height int64) ([] } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsDamask.Event{RootHash: e}) + events[i] = convertEvent(txResultsDamask.Event{RootHash: e}, i) } return events, nil } diff --git a/storage/oasis/nodeapi/eden/convert.go b/storage/oasis/nodeapi/eden/convert.go index f9aeeb740..c865af8c7 100644 --- a/storage/oasis/nodeapi/eden/convert.go +++ b/storage/oasis/nodeapi/eden/convert.go @@ -214,7 +214,7 @@ func ConvertGenesis(d genesisEden.Document) (*nodeapi.GenesisDocument, error) { }, nil } -func convertStakingEvent(e stakingEden.Event) nodeapi.Event { +func convertStakingEvent(e stakingEden.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.Transfer != nil: @@ -281,10 +281,11 @@ func convertStakingEvent(e stakingEden.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertRegistryEvent(e registryEden.Event) nodeapi.Event { +func convertRegistryEvent(e registryEden.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.RuntimeStartedEvent != nil: @@ -358,10 +359,11 @@ func convertRegistryEvent(e registryEden.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertRoothashEvent(e roothashEden.Event) nodeapi.Event { +func convertRoothashEvent(e roothashEden.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.ExecutorCommitted != nil: @@ -416,10 +418,11 @@ func convertRoothashEvent(e roothashEden.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertGovernanceEvent(e governanceEden.Event) nodeapi.Event { +func convertGovernanceEvent(e governanceEden.Event, eventIdx int) nodeapi.Event { ret := nodeapi.Event{} switch { case e.ProposalSubmitted != nil: @@ -453,19 +456,20 @@ func convertGovernanceEvent(e governanceEden.Event) nodeapi.Event { } ret.Height = e.Height ret.TxHash = e.TxHash + ret.EventIdx = eventIdx return ret } -func convertEvent(e txResultsEden.Event) nodeapi.Event { +func convertEvent(e txResultsEden.Event, eventIdx int) nodeapi.Event { switch { case e.Staking != nil: - return convertStakingEvent(*e.Staking) + return convertStakingEvent(*e.Staking, eventIdx) case e.Registry != nil: - return convertRegistryEvent(*e.Registry) + return convertRegistryEvent(*e.Registry, eventIdx) case e.RootHash != nil: - return convertRoothashEvent(*e.RootHash) + return convertRoothashEvent(*e.RootHash, eventIdx) case e.Governance != nil: - return convertGovernanceEvent(*e.Governance) + return convertGovernanceEvent(*e.Governance, eventIdx) default: return nodeapi.Event{} } @@ -474,7 +478,7 @@ func convertEvent(e txResultsEden.Event) nodeapi.Event { func convertTxResult(r txResultsEden.Result) nodeapi.TxResult { events := make([]nodeapi.Event, len(r.Events)) for i, e := range r.Events { - events[i] = convertEvent(*e) + events[i] = convertEvent(*e, i) } return nodeapi.TxResult{ diff --git a/storage/oasis/nodeapi/eden/node.go b/storage/oasis/nodeapi/eden/node.go index 28c59130f..6ef305827 100644 --- a/storage/oasis/nodeapi/eden/node.go +++ b/storage/oasis/nodeapi/eden/node.go @@ -131,7 +131,7 @@ func (c *ConsensusApiLite) RegistryEvents(ctx context.Context, height int64) ([] } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsEden.Event{Registry: e}) + events[i] = convertEvent(txResultsEden.Event{Registry: e}, i) } return events, nil } @@ -143,7 +143,7 @@ func (c *ConsensusApiLite) StakingEvents(ctx context.Context, height int64) ([]n } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsEden.Event{Staking: e}) + events[i] = convertEvent(txResultsEden.Event{Staking: e}, i) } return events, nil } @@ -155,7 +155,7 @@ func (c *ConsensusApiLite) GovernanceEvents(ctx context.Context, height int64) ( } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsEden.Event{Governance: e}) + events[i] = convertEvent(txResultsEden.Event{Governance: e}, i) } return events, nil } @@ -167,7 +167,7 @@ func (c *ConsensusApiLite) RoothashEvents(ctx context.Context, height int64) ([] } events := make([]nodeapi.Event, len(rsp)) for i, e := range rsp { - events[i] = convertEvent(txResultsEden.Event{RootHash: e}) + events[i] = convertEvent(txResultsEden.Event{RootHash: e}, i) } return events, nil } diff --git a/tests/e2e_regression/common_test_cases.sh b/tests/e2e_regression/common_test_cases.sh index e766fd43c..3a7ddc8d1 100644 --- a/tests/e2e_regression/common_test_cases.sh +++ b/tests/e2e_regression/common_test_cases.sh @@ -13,7 +13,7 @@ commonTestCases=( 'db__delegations select * from chain.delegations where shares != 0 order by delegatee, delegator' 'db__epochs select id, start_height, end_height, ARRAY(SELECT unnest(validators) ORDER BY 1) AS sorted_validators from chain.epochs order by id' 'db__entities select * from chain.entities order by id' - 'db__events select tx_block, tx_index, tx_hash, type, ARRAY(SELECT unnest(related_accounts) ORDER BY 1) AS sorted_related_accounts, body::text from chain.events order by tx_block, tx_index, type, body::text' + 'db__events select tx_block, tx_index, tx_hash, type, ARRAY(SELECT account_address FROM chain.events_related_accounts ra WHERE ra.tx_block = e.tx_block AND ra.type = e.type AND ra.event_index = e.event_index ORDER BY 1) AS sorted_related_accounts, body::text from chain.events e order by tx_block, tx_index, type, body::text' 'db__nodes select id, entity_id, roles, expiration, voting_power from chain.nodes order by id' 'db__runtime_nodes select rn.*, n.roles FROM chain.runtime_nodes rn LEFT JOIN chain.nodes n ON (rn.node_id = n.id) ORDER BY runtime_id, node_id' 'db__validator_staking_history select * from history.validators order by epoch, id' diff --git a/tests/e2e_regression/damask/expected/events.body b/tests/e2e_regression/damask/expected/events.body index 87a95d034..868ae4eec 100644 --- a/tests/e2e_regression/damask/expected/events.body +++ b/tests/e2e_regression/damask/expected/events.body @@ -13,9 +13,9 @@ { "block": 8049946, "body": { - "amount": "100", + "amount": "10000000", "from": "oasis1qrqnh093w0pv8asfmc37pyal6yn2h4cnwvdqtzm0", - "to": "oasis1qqnv3peudzvekhulf8v3ht29z4cthkhy7gkxmph5" + "to": "oasis1qz068qtggv6kdstymnvqm46rpv6p6tk6pueffdqu" }, "timestamp": "2022-04-11T12:44:08Z", "tx_hash": "4defe2afa3abbd4668958e360e184c73381e8b99ebb8082b911f6b28c811da97", @@ -25,9 +25,9 @@ { "block": 8049946, "body": { - "amount": "10000000", + "amount": "100", "from": "oasis1qrqnh093w0pv8asfmc37pyal6yn2h4cnwvdqtzm0", - "to": "oasis1qz068qtggv6kdstymnvqm46rpv6p6tk6pueffdqu" + "to": "oasis1qqnv3peudzvekhulf8v3ht29z4cthkhy7gkxmph5" }, "timestamp": "2022-04-11T12:44:08Z", "tx_hash": "4defe2afa3abbd4668958e360e184c73381e8b99ebb8082b911f6b28c811da97",