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

runtime: Support consensus event queries #4904

Merged
merged 8 commits into from
Sep 9, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .changelog/4694.feature.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
runtime: verify consensus state integrity for queries
runtime: Enable dispatcher to verify state integrity for queries
1 change: 0 additions & 1 deletion .changelog/4830.bugfix.md

This file was deleted.

1 change: 1 addition & 0 deletions .changelog/4830.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
runtime: Enable dispatcher to verify state integrity for queries
1 change: 1 addition & 0 deletions .changelog/4904.feature.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
runtime: Enable dispatcher to verify state integrity for queries
1 change: 1 addition & 0 deletions .changelog/4904.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
runtime: Support consensus event queries
2 changes: 1 addition & 1 deletion go/common/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ var (
// the runtime.
//
// NOTE: This version must be synced with runtime/src/common/version.rs.
RuntimeHostProtocol = Version{Major: 5, Minor: 0, Patch: 0}
RuntimeHostProtocol = Version{Major: 5, Minor: 1, Patch: 0}

// RuntimeCommitteeProtocol versions the P2P protocol used by the runtime
// committee members.
Expand Down
38 changes: 38 additions & 0 deletions go/consensus/api/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ var (

// methodGetLightBlock is the GetLightBlock method.
methodGetLightBlock = lightServiceName.NewMethod("GetLightBlock", int64(0))
// methodGetLightBlockForState is the GetLightBlockForState method.
methodGetLightBlockForState = lightServiceName.NewMethod("GetLightBlockForState", int64(0))
// methodGetParameters is the GetParameters method.
methodGetParameters = lightServiceName.NewMethod("GetParameters", int64(0))
// methodStateSyncGet is the StateSyncGet method.
Expand Down Expand Up @@ -139,6 +141,10 @@ var (
MethodName: methodGetLightBlock.ShortName(),
Handler: handlerGetLightBlock,
},
{
MethodName: methodGetLightBlockForState.ShortName(),
Handler: handlerGetLightBlockForState,
},
{
MethodName: methodGetParameters.ShortName(),
Handler: handlerGetParameters,
Expand Down Expand Up @@ -474,6 +480,29 @@ func handlerGetLightBlock(
return interceptor(ctx, height, info, handler)
}

func handlerGetLightBlockForState(
srv interface{},
ctx context.Context,
dec func(interface{}) error,
interceptor grpc.UnaryServerInterceptor,
) (interface{}, error) {
var height int64
if err := dec(&height); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(LightClientBackend).GetLightBlockForState(ctx, height)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodGetLightBlockForState.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(LightClientBackend).GetLightBlockForState(ctx, req.(int64))
}
return interceptor(ctx, height, info, handler)
}

func handlerGetParameters(
srv interface{},
ctx context.Context,
Expand Down Expand Up @@ -636,6 +665,15 @@ func (c *consensusLightClient) GetLightBlock(ctx context.Context, height int64)
return &rsp, nil
}

// Implements LightClientBackend.
func (c *consensusLightClient) GetLightBlockForState(ctx context.Context, height int64) (*LightBlock, error) {
var rsp LightBlock
if err := c.conn.Invoke(ctx, methodGetLightBlockForState.FullName(), height, &rsp); err != nil {
return nil, err
}
return &rsp, nil
}

// Implements LightClientBackend.
func (c *consensusLightClient) GetParameters(ctx context.Context, height int64) (*Parameters, error) {
var rsp Parameters
Expand Down
7 changes: 7 additions & 0 deletions go/consensus/api/light.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ type LightClientBackend interface {
// client verification.
GetLightBlock(ctx context.Context, height int64) (*LightBlock, error)

// GetLightBlockForState returns a light block for the state as of executing the consensus layer
// block at the specified height. Note that the height of the returned block may differ
// depending on consensus layer implementation details.
//
// In case light block for the given height is not yet available, it returns ErrVersionNotFound.
GetLightBlockForState(ctx context.Context, height int64) (*LightBlock, error)

// GetParameters returns the consensus parameters for a specific height.
GetParameters(ctx context.Context, height int64) (*Parameters, error)

Expand Down
34 changes: 31 additions & 3 deletions go/consensus/tendermint/full/light.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

tmcore "github.com/tendermint/tendermint/rpc/core"
tmstate "github.com/tendermint/tendermint/state"
tmtypes "github.com/tendermint/tendermint/types"

"github.com/oasisprotocol/oasis-core/go/common/cbor"
Expand All @@ -14,8 +15,7 @@ import (
"github.com/oasisprotocol/oasis-core/go/storage/mkvs/syncer"
)

// Implements LightClientBackend.
func (n *commonNode) GetLightBlock(ctx context.Context, height int64) (*consensusAPI.LightBlock, error) {
func (n *commonNode) getLightBlock(ctx context.Context, height int64, allowPending bool) (*consensusAPI.LightBlock, error) {
if err := n.ensureStarted(ctx); err != nil {
return nil, err
}
Expand All @@ -33,9 +33,27 @@ func (n *commonNode) GetLightBlock(ctx context.Context, height int64) (*consensu
return nil, consensusAPI.ErrVersionNotFound
}

if commit, cerr := tmcore.Commit(n.rpcCtx, &tmHeight); cerr == nil && commit.Header != nil {
commit, err := tmcore.Commit(n.rpcCtx, &tmHeight)
if err == nil && commit.Header != nil {
lb.SignedHeader = &commit.SignedHeader
tmHeight = commit.Header.Height
} else if allowPending {
// The specified height seems to be for the "next" block that has not yet been finalized. We
// construct a "pending" block instead (this block cannot be verified by a light client as
// it doesn't have any commits).
var state tmstate.State
state, err = n.stateStore.Load()
if err != nil {
return nil, fmt.Errorf("tendermint: failed to fetch latest blockchain state: %w", err)
}

commit := tmtypes.NewCommit(height, 0, tmtypes.BlockID{}, nil)
var proposerAddr [20]byte
blk, _ := state.MakeBlock(height, nil, commit, nil, proposerAddr[:])
lb.SignedHeader = &tmtypes.SignedHeader{
Header: &blk.Header,
Commit: commit,
}
}
protoLb, err := lb.ToProto()
if err != nil {
Expand All @@ -59,6 +77,16 @@ func (n *commonNode) GetLightBlock(ctx context.Context, height int64) (*consensu
}, nil
}

// Implements LightClientBackend.
func (n *commonNode) GetLightBlock(ctx context.Context, height int64) (*consensusAPI.LightBlock, error) {
return n.getLightBlock(ctx, height, false)
}

// Implements LightClientBackend.
func (n *commonNode) GetLightBlockForState(ctx context.Context, height int64) (*consensusAPI.LightBlock, error) {
return n.getLightBlock(ctx, height+1, true)
}

// Implements LightClientBackend.
func (n *commonNode) GetParameters(ctx context.Context, height int64) (*consensusAPI.Parameters, error) {
if err := n.ensureStarted(ctx); err != nil {
Expand Down
5 changes: 5 additions & 0 deletions go/consensus/tendermint/light/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ func (lc *lightClient) GetLightBlock(ctx context.Context, height int64) (*consen
return lc.getPrimary().GetLightBlock(ctx, height)
}

// Implements consensus.LightClientBackend.
func (lc *lightClient) GetLightBlockForState(ctx context.Context, height int64) (*consensus.LightBlock, error) {
return lc.getPrimary().GetLightBlockForState(ctx, height)
}

// Implements consensus.LightClientBackend.
func (lc *lightClient) GetParameters(ctx context.Context, height int64) (*consensus.Parameters, error) {
return lc.getPrimary().GetParameters(ctx, height)
Expand Down
5 changes: 5 additions & 0 deletions go/consensus/tendermint/seed/seed.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ func (srv *seedService) GetLightBlock(ctx context.Context, height int64) (*conse
return nil, consensus.ErrUnsupported
}

// Implements consensus.Backend.
func (srv *seedService) GetLightBlockForState(ctx context.Context, height int64) (*consensus.LightBlock, error) {
return nil, consensus.ErrUnsupported
}

// Implements consensus.Backend.
func (srv *seedService) GetParameters(ctx context.Context, height int64) (*consensus.Parameters, error) {
return nil, consensus.ErrUnsupported
Expand Down
55 changes: 41 additions & 14 deletions go/runtime/host/protocol/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/oasisprotocol/oasis-core/go/common/sgx/quote"
"github.com/oasisprotocol/oasis-core/go/common/version"
consensus "github.com/oasisprotocol/oasis-core/go/consensus/api"
consensusResults "github.com/oasisprotocol/oasis-core/go/consensus/api/transaction/results"
roothash "github.com/oasisprotocol/oasis-core/go/roothash/api"
"github.com/oasisprotocol/oasis-core/go/roothash/api/block"
"github.com/oasisprotocol/oasis-core/go/roothash/api/commitment"
Expand Down Expand Up @@ -95,20 +96,22 @@ type Body struct {
RuntimeConsensusSyncResponse *Empty `json:",omitempty"`

// Host interface.
HostRPCCallRequest *HostRPCCallRequest `json:",omitempty"`
HostRPCCallResponse *HostRPCCallResponse `json:",omitempty"`
HostStorageSyncRequest *HostStorageSyncRequest `json:",omitempty"`
HostStorageSyncResponse *HostStorageSyncResponse `json:",omitempty"`
HostLocalStorageGetRequest *HostLocalStorageGetRequest `json:",omitempty"`
HostLocalStorageGetResponse *HostLocalStorageGetResponse `json:",omitempty"`
HostLocalStorageSetRequest *HostLocalStorageSetRequest `json:",omitempty"`
HostLocalStorageSetResponse *Empty `json:",omitempty"`
HostFetchConsensusBlockRequest *HostFetchConsensusBlockRequest `json:",omitempty"`
HostFetchConsensusBlockResponse *HostFetchConsensusBlockResponse `json:",omitempty"`
HostFetchTxBatchRequest *HostFetchTxBatchRequest `json:",omitempty"`
HostFetchTxBatchResponse *HostFetchTxBatchResponse `json:",omitempty"`
HostFetchGenesisHeightRequest *HostFetchGenesisHeightRequest `json:",omitempty"`
HostFetchGenesisHeightResponse *HostFetchGenesisHeightResponse `json:",omitempty"`
HostRPCCallRequest *HostRPCCallRequest `json:",omitempty"`
HostRPCCallResponse *HostRPCCallResponse `json:",omitempty"`
HostStorageSyncRequest *HostStorageSyncRequest `json:",omitempty"`
HostStorageSyncResponse *HostStorageSyncResponse `json:",omitempty"`
HostLocalStorageGetRequest *HostLocalStorageGetRequest `json:",omitempty"`
HostLocalStorageGetResponse *HostLocalStorageGetResponse `json:",omitempty"`
HostLocalStorageSetRequest *HostLocalStorageSetRequest `json:",omitempty"`
HostLocalStorageSetResponse *Empty `json:",omitempty"`
HostFetchConsensusBlockRequest *HostFetchConsensusBlockRequest `json:",omitempty"`
HostFetchConsensusBlockResponse *HostFetchConsensusBlockResponse `json:",omitempty"`
HostFetchConsensusEventsRequest *HostFetchConsensusEventsRequest `json:",omitempty"`
HostFetchConsensusEventsResponse *HostFetchConsensusEventsResponse `json:",omitempty"`
HostFetchTxBatchRequest *HostFetchTxBatchRequest `json:",omitempty"`
HostFetchTxBatchResponse *HostFetchTxBatchResponse `json:",omitempty"`
HostFetchGenesisHeightRequest *HostFetchGenesisHeightRequest `json:",omitempty"`
HostFetchGenesisHeightResponse *HostFetchGenesisHeightResponse `json:",omitempty"`
}

// Type returns the message type by determining the name of the first non-nil member.
Expand Down Expand Up @@ -480,6 +483,30 @@ type HostFetchConsensusBlockResponse struct {
Block consensus.LightBlock `json:"block"`
}

// EventKind is the consensus event kind.
type EventKind uint8

// Supported consensus event kinds.
const (
EventKindStaking EventKind = 1
EventKindRegistry EventKind = 2
EventKindRootHash EventKind = 3
EventKindGovernance EventKind = 4
)

// HostFetchConsensusEventsRequest is a request to host to fetch the consensus events for the given
// height.
type HostFetchConsensusEventsRequest struct {
Height uint64 `json:"height"`
Kind EventKind `json:"kind"`
}

// HostFetchConsensusEventsResponse is a response from host fetching the consensus events for the
// given height.
type HostFetchConsensusEventsResponse struct {
Events []*consensusResults.Event `json:"events,omitempty"`
}

// HostFetchGenesisHeightRequest is a request to host to fetch the consensus genesis height.
type HostFetchGenesisHeightRequest struct{}

Expand Down
Loading