Skip to content

Commit

Permalink
Merge pull request #588 from oasisprotocol/pro-wh/feature/roothash
Browse files Browse the repository at this point in the history
consensus roothash events specialization
  • Loading branch information
pro-wh authored Mar 1, 2024
2 parents b102297 + 0934827 commit bb32699
Show file tree
Hide file tree
Showing 38 changed files with 905 additions and 590 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
<api/spec/v1.yaml ./yq --output-format json | ./yq --output-format yaml --input-format json >api/spec/v1-normalized.yaml
- name: Validate OpenAPI definition
run: |
./vacuum lint --ruleset .vacuum.yaml --errors api/spec/v1-normalized.yaml
./vacuum lint --ruleset .vacuum.yaml --details --snippets --errors api/spec/v1-normalized.yaml
validate-migrations:
runs-on: ubuntu-20.04
Expand Down
36 changes: 30 additions & 6 deletions analyzer/consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import (
"os"
"strings"

coreCommon "github.com/oasisprotocol/oasis-core/go/common"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
sdkConfig "github.com/oasisprotocol/oasis-sdk/client-sdk/go/config"

"github.com/oasisprotocol/nexus/common"
"github.com/oasisprotocol/nexus/coreapi/v22.2.11/consensus/api/transaction"
genesis "github.com/oasisprotocol/nexus/coreapi/v22.2.11/genesis/api"
staking "github.com/oasisprotocol/nexus/coreapi/v22.2.11/staking/api"
Expand All @@ -37,9 +39,12 @@ const (
type EventType = apiTypes.ConsensusEventType // alias for brevity

type parsedEvent struct {
ty EventType
rawBody json.RawMessage
relatedAddresses []staking.Address
ty EventType
rawBody json.RawMessage
roothashRuntimeID *coreCommon.Namespace
roothashRuntime *common.Runtime
roothashRuntimeRound *uint64
relatedAddresses []staking.Address
}

// OpenSignedTxNoVerify decodes the Transaction inside a Signed transaction
Expand Down Expand Up @@ -479,6 +484,9 @@ func (m *processor) queueTxEventInserts(batch *storage.QueryBatch, data *consens
txr.Transaction.Hash().Hex(),
i,
accounts,
common.StringOrNil(eventData.roothashRuntimeID),
eventData.roothashRuntime,
eventData.roothashRuntimeRound,
)
}
uniqueTxAccounts := extractUniqueAddresses(txAccounts)
Expand Down Expand Up @@ -1035,6 +1043,9 @@ func (m *processor) queueSingleEventInserts(batch *storage.QueryBatch, eventData
nil,
nil,
accounts,
common.StringOrNil(eventData.roothashRuntimeID),
eventData.roothashRuntime,
eventData.roothashRuntimeRound,
)

return nil
Expand Down Expand Up @@ -1068,9 +1079,22 @@ func (m *processor) extractEventData(event nodeapi.Event) parsedEvent {
eventData.relatedAddresses = []staking.Address{event.GovernanceProposalSubmitted.Submitter}
case event.GovernanceVote != nil:
eventData.relatedAddresses = []staking.Address{event.GovernanceVote.Submitter}
case event.RoothashExecutorCommitted != nil && event.RoothashExecutorCommitted.NodeID != nil:
nodeAddr := staking.NewAddress(*event.RoothashExecutorCommitted.NodeID)
eventData.relatedAddresses = []staking.Address{nodeAddr}
case event.RoothashMisc != nil:
eventData.roothashRuntimeID = &event.RoothashMisc.RuntimeID
eventData.roothashRuntime = RuntimeFromID(event.RoothashMisc.RuntimeID, m.network)
eventData.roothashRuntimeRound = event.RoothashMisc.Round
case event.RoothashExecutorCommitted != nil:
eventData.roothashRuntimeID = &event.RoothashExecutorCommitted.RuntimeID
eventData.roothashRuntime = RuntimeFromID(event.RoothashExecutorCommitted.RuntimeID, m.network)
eventData.roothashRuntimeRound = &event.RoothashExecutorCommitted.Round
if event.RoothashExecutorCommitted.NodeID != nil {
// TODO: preimage?
nodeAddr := staking.NewAddress(*event.RoothashExecutorCommitted.NodeID)
eventData.relatedAddresses = []staking.Address{nodeAddr}
}
case event.RoothashMessage != nil:
eventData.roothashRuntimeID = &event.RoothashMessage.RuntimeID
eventData.roothashRuntime = RuntimeFromID(event.RoothashMessage.RuntimeID, m.network)
case event.RegistryEntity != nil:
addr := staking.NewAddress(event.RegistryEntity.Entity.ID)
accounts := []staking.Address{addr}
Expand Down
24 changes: 24 additions & 0 deletions analyzer/consensus/runtimes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package consensus

import (
"bytes"
"encoding/hex"

coreCommon "github.com/oasisprotocol/oasis-core/go/common"
sdkConfig "github.com/oasisprotocol/oasis-sdk/client-sdk/go/config"

"github.com/oasisprotocol/nexus/common"
)

func RuntimeFromID(rtid coreCommon.Namespace, network sdkConfig.Network) *common.Runtime {
for name, pt := range network.ParaTimes.All {
id, err := hex.DecodeString(pt.ID)
if err != nil {
return nil
}
if bytes.Equal(id, rtid[:]) {
return common.Ptr(common.Runtime(name))
}
}
return nil
}
4 changes: 2 additions & 2 deletions analyzer/queries/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,8 @@ var (
schedule = excluded.schedule`

ConsensusEventInsert = `
INSERT INTO chain.events (type, body, tx_block, tx_hash, tx_index, related_accounts)
VALUES ($1, $2, $3, $4, $5, $6)`
INSERT INTO chain.events (type, body, tx_block, tx_hash, tx_index, related_accounts, roothash_runtime_id, roothash_runtime, roothash_runtime_round)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`

ConsensusAccountRelatedTransactionInsert = `
INSERT INTO chain.accounts_related_transactions (account_address, tx_block, tx_index)
Expand Down
51 changes: 38 additions & 13 deletions api/spec/v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ paths:
- in: query
name: rel
schema:
$ref: '#/components/schemas/StakingAddress'
allOf: [$ref: '#/components/schemas/StakingAddress']
# TODO: Implement autodetection of Eth addresses, get rid of last sentence.
description: |
A filter on related accounts. Every returned transaction will refer to
Expand Down Expand Up @@ -1557,6 +1557,11 @@ components:
- roothash.execution_discrepancy
- roothash.executor_committed
- roothash.finalized
# Note: roothash.message is no longer used as an event since Damask.
# Message results are now in RoundResults.
# The MessageEvent structure remains and is used in RoundResults.
- roothash.message
- roothash.in_msg_processed
- staking.allowance_change
- staking.burn
- staking.escrow.add
Expand Down Expand Up @@ -1601,6 +1606,26 @@ components:
Hash of this event's originating transaction.
Absent if the event did not originate from a transaction.
example: *tx_hash_1
roothash_runtime_id:
type: string
description: |
The ID of the runtime to which the event relates, encoded in hex.
Present only for events of type `roothash.*`.
example: 000000000000000000000000000000000000000000000000e2eaa99fc008f87f
roothash_runtime:
allOf: [$ref: '#/components/schemas/Runtime']
description: |
The runtime to which the event relates.
Present only for events of type `roothash.*`.
example: emerald
roothash_runtime_round:
type: integer
format: int64
description: |
When applicable, the round in the runtime to which this event
relates.
Present only for events of type `roothash.*` except for
`roothash.execution_discrepancy` before Eden.
type:
allOf: [$ref: '#/components/schemas/ConsensusEventType']
description: The type of the event.
Expand Down Expand Up @@ -1730,7 +1755,7 @@ components:
type: boolean
description: Whether the entity has a node that is registered for being a validator, node is up to date, and has successfully registered itself. It may or may not be part of validator set.
media:
$ref: '#/components/schemas/ValidatorMedia'
allOf: [$ref: '#/components/schemas/ValidatorMedia']
current_rate:
type: integer
format: uint64
Expand Down Expand Up @@ -1899,7 +1924,7 @@ components:
type: string
description: The name of the token. Not guaranteed to be unique across distinct EVM tokens.
token_type:
$ref: "#/components/schemas/EvmTokenType"
allOf: [$ref: "#/components/schemas/EvmTokenType"]
token_decimals:
type: integer
description: The number of decimals of precision for this token.
Expand Down Expand Up @@ -2074,15 +2099,15 @@ components:
description: The staking address of the proposal submitter.
example: *staking_address_1
state:
$ref: '#/components/schemas/ProposalState'
allOf: [$ref: '#/components/schemas/ProposalState']
deposit:
allOf: [$ref: '#/components/schemas/TextBigInt']
description: The deposit attached to this proposal.
handler:
type: string
description: The name of the upgrade handler.
target:
$ref: '#/components/schemas/ProposalTarget'
allOf: [$ref: '#/components/schemas/ProposalTarget']
epoch:
type: integer
format: uint64
Expand Down Expand Up @@ -2315,7 +2340,7 @@ components:
type: object
properties:
type:
$ref: '#/components/schemas/EvmTokenType'
allOf: [$ref: '#/components/schemas/EvmTokenType']
symbol:
type: string
description: Symbol of the token, as provided by token contract's `symbol()` method.
Expand Down Expand Up @@ -2385,7 +2410,7 @@ components:
type: object
properties:
verification_level:
$ref: '#/components/schemas/VerificationLevel'
allOf: [$ref: '#/components/schemas/VerificationLevel']
compilation_metadata:
type: object
description: |
Expand Down Expand Up @@ -2610,7 +2635,7 @@ components:
description: The staking address for this account.
example: *staking_address_1
address_preimage:
$ref: '#/components/schemas/AddressPreimage'
allOf: [$ref: '#/components/schemas/AddressPreimage']
balances:
description: |
The balance(s) of this account in this runtime. Most runtimes use only one denomination, and thus
Expand All @@ -2619,7 +2644,7 @@ components:
this does not include ERC-20 tokens
type: array
items:
$ref: '#/components/schemas/RuntimeSdkBalance'
allOf: [$ref: '#/components/schemas/RuntimeSdkBalance']
evm_contract:
allOf: [$ref: '#/components/schemas/RuntimeEvmContract']
description: |
Expand All @@ -2631,9 +2656,9 @@ components:
NOTE: This field is limited to 1000 entries. If you need more, please let us know in a GitHub issue.
type: array
items:
$ref: '#/components/schemas/RuntimeEvmBalance'
allOf: [$ref: '#/components/schemas/RuntimeEvmBalance']
stats:
$ref: '#/components/schemas/AccountStats'
allOf: [$ref: '#/components/schemas/AccountStats']

RuntimeStatus:
type: object
Expand Down Expand Up @@ -2739,7 +2764,7 @@ components:
DEPRECATED: This field will be removed in the future in favor of verification_level
example: false
verification_level:
$ref: '#/components/schemas/VerificationLevel'
allOf: [$ref: '#/components/schemas/VerificationLevel']

EvmNftList:
allOf:
Expand All @@ -2761,7 +2786,7 @@ components:
- id
properties:
token:
$ref: '#/components/schemas/EvmToken'
allOf: [$ref: '#/components/schemas/EvmToken']
id:
allOf: [$ref: '#/components/schemas/TextBigInt']
description: The instance ID of this NFT within the collection represented by `token`.
Expand Down
2 changes: 2 additions & 0 deletions coreapi/v23.0/roothash/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ type ExecutorCommittedEvent struct {

// ExecutionDiscrepancyDetectedEvent is an execute discrepancy detected event.
type ExecutionDiscrepancyDetectedEvent struct {
// Round is the round in which the discrepancy was detected.
Round *uint64 `json:"round,omitempty"`
// Rank is the rank of the transaction scheduler.
Rank uint64 `json:"rank"`
// Timeout signals whether the discrepancy was due to a timeout.
Expand Down
13 changes: 13 additions & 0 deletions scripts/vendor-oasis-core/patches/v23.0/discrepancy_round.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/coreapi/v23.0/roothash/api/api.go b/coreapi/v23.0/roothash/api/api.go
index e7653d7d..e6a88db5 100644
--- a/coreapi/v23.0/roothash/api/api.go
+++ b/coreapi/v23.0/roothash/api/api.go
@@ -192,6 +192,8 @@ type ExecutorCommittedEvent struct {

// ExecutionDiscrepancyDetectedEvent is an execute discrepancy detected event.
type ExecutionDiscrepancyDetectedEvent struct {
+ // Round is the round in which the discrepancy was detected.
+ Round *uint64 `json:"round,omitempty"`
// Rank is the rank of the transaction scheduler.
Rank uint64 `json:"rank"`
// Timeout signals whether the discrepancy was due to a timeout.
11 changes: 10 additions & 1 deletion storage/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,16 @@ func (c *StorageClient) Events(ctx context.Context, p apiTypes.GetConsensusEvent

for res.rows.Next() {
var e Event
if err := res.rows.Scan(&e.Block, &e.TxIndex, &e.TxHash, &e.Type, &e.Body); err != nil {
if err := res.rows.Scan(
&e.Block,
&e.TxIndex,
&e.TxHash,
&e.RoothashRuntimeId,
&e.RoothashRuntime,
&e.RoothashRuntimeRound,
&e.Type,
&e.Body,
); err != nil {
return nil, wrapError(err)
}
es.Events = append(es.Events, e)
Expand Down
2 changes: 1 addition & 1 deletion storage/client/queries/queries.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const (
WHERE tx_hash = $1::text`

Events = `
SELECT tx_block, tx_index, tx_hash, type, body
SELECT tx_block, tx_index, tx_hash, roothash_runtime_id, roothash_runtime, roothash_runtime_round, type, body
FROM chain.events
WHERE ($1::bigint IS NULL OR tx_block = $1::bigint) AND
($2::integer IS NULL OR tx_index = $2::integer) AND
Expand Down
10 changes: 10 additions & 0 deletions storage/migrations/00_consensus.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,23 @@ CREATE TABLE chain.events
body JSONB,
tx_hash HEX64, -- could be fetched from `transactions` table; denormalized for efficiency
related_accounts TEXT[],
-- added in 10_roothash.up.sql
-- roothash_runtime_id HEX64,
-- roothash_runtime runtime,
-- roothash_runtime_round UINT63,

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_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
-- added in 10_roothash.up.sql
-- CREATE INDEX ix_events_roothash
-- ON chain.events (roothash_runtime, roothash_runtime_round)
-- WHERE
-- roothash_runtime IS NOT NULL AND
-- roothash_runtime_round IS NOT NULL;

-- Beacon Backend Data

Expand Down
32 changes: 32 additions & 0 deletions storage/migrations/10_roothash.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
BEGIN;

ALTER TABLE chain.events
-- 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
-- a "body" blob. In roothash events though, the roothash/api Event
-- structure additionally has a RuntimeID field, which nexus otherwise
-- loses when it extracts the one non-nil event next to it. In the nexus,
-- database, we're storing that runtime identifier in a column.
--
-- This is a runtime identifier, which is a binary "namespace," e.g.
-- `000000000000000000000000000000000000000000000000f80306c9858e7279` for
-- Sapphire on Mainnet. This is taken from the event from the node, and it
-- is set even for runtimes that nexus isn't configured to analyze.
ADD COLUMN roothash_runtime_id HEX64,
-- This is a nexus runtime name, for example `sapphire`. This is only set
-- for supported runtimes.
ADD COLUMN roothash_runtime runtime,
ADD COLUMN roothash_runtime_round UINT63;

-- ix_events_roothash is the link between runtime blocks and consensus blocks.
-- Given a runtime block (runtime, round), you can look up the roothash events
-- with this index and find the events when the block was proposed (first
-- executor commit), committed to, and finalized.
CREATE INDEX ix_events_roothash
ON chain.events (roothash_runtime, roothash_runtime_round)
WHERE
roothash_runtime IS NOT NULL AND
roothash_runtime_round IS NOT NULL;

COMMIT;
Loading

0 comments on commit bb32699

Please sign in to comment.