Skip to content

Commit

Permalink
runtime: Support consensus event queries
Browse files Browse the repository at this point in the history
  • Loading branch information
kostko committed Aug 26, 2022
1 parent 8b06511 commit b16e00d
Show file tree
Hide file tree
Showing 12 changed files with 705 additions and 29 deletions.
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
51 changes: 39 additions & 12 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,18 +96,20 @@ 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"`
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"`
}

// Type returns the message type by determining the name of the first non-nil member.
Expand Down Expand Up @@ -478,6 +481,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"`
}

// HostFetchTxBatchRequest is a request to host to fetch a further batch of transactions.
type HostFetchTxBatchRequest struct {
// Offset specifies the transaction hash that should serve as an offset when returning
Expand Down
48 changes: 48 additions & 0 deletions go/runtime/registry/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/oasisprotocol/oasis-core/go/common/logging"
"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"
keymanager "github.com/oasisprotocol/oasis-core/go/keymanager/api"
registry "github.com/oasisprotocol/oasis-core/go/registry/api"
"github.com/oasisprotocol/oasis-core/go/roothash/api/block"
Expand Down Expand Up @@ -242,6 +243,53 @@ func (h *runtimeHostHandler) Handle(ctx context.Context, body *protocol.Body) (*
Block: *lb,
}}, nil
}
// Consensus events.
if body.HostFetchConsensusEventsRequest != nil {
var evs []*consensusResults.Event
switch rq := body.HostFetchConsensusEventsRequest; rq.Kind {
case protocol.EventKindStaking:
sevs, err := h.consensus.Staking().GetEvents(ctx, int64(rq.Height))
if err != nil {
return nil, err
}
evs = make([]*consensusResults.Event, 0, len(sevs))
for _, sev := range sevs {
evs = append(evs, &consensusResults.Event{Staking: sev})
}
case protocol.EventKindRegistry:
revs, err := h.consensus.Registry().GetEvents(ctx, int64(rq.Height))
if err != nil {
return nil, err
}
evs = make([]*consensusResults.Event, 0, len(revs))
for _, rev := range revs {
evs = append(evs, &consensusResults.Event{Registry: rev})
}
case protocol.EventKindRootHash:
revs, err := h.consensus.RootHash().GetEvents(ctx, int64(rq.Height))
if err != nil {
return nil, err
}
evs = make([]*consensusResults.Event, 0, len(revs))
for _, rev := range revs {
evs = append(evs, &consensusResults.Event{RootHash: rev})
}
case protocol.EventKindGovernance:
gevs, err := h.consensus.Governance().GetEvents(ctx, int64(rq.Height))
if err != nil {
return nil, err
}
evs = make([]*consensusResults.Event, 0, len(gevs))
for _, gev := range gevs {
evs = append(evs, &consensusResults.Event{Governance: gev})
}
default:
return nil, errMethodNotSupported
}
return &protocol.Body{HostFetchConsensusEventsResponse: &protocol.HostFetchConsensusEventsResponse{
Events: evs,
}}, nil
}
// Transaction pool.
if rq := body.HostFetchTxBatchRequest; rq != nil {
txPool, err := h.env.GetTxPool(ctx)
Expand Down
149 changes: 149 additions & 0 deletions go/staking/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/oasisprotocol/oasis-core/go/beacon/api"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/crypto/hash"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
"github.com/oasisprotocol/oasis-core/go/common/quantity"
)
Expand Down Expand Up @@ -506,3 +507,151 @@ func TestReclaimEscrowResultsSerialization(t *testing.T) {
require.EqualValues(tc.rr, dec, "ReclaimEscrow serialization should round-trip")
}
}

func TestEventsSerialization(t *testing.T) {
require := require.New(t)

pk1 := signature.NewPublicKey("aaafffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
addr1 := NewAddress(pk1)
pk2 := signature.NewPublicKey("bbbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
addr2 := NewAddress(pk2)
var txHash hash.Hash
txHash.Empty()

// NOTE: These cases should be synced with tests in runtime/src/consensus/staking.rs.
for _, tc := range []struct {
ev Event
expectedBase64 string
}{
{Event{}, "oWd0eF9oYXNoWCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="},
{Event{Height: 42}, "omZoZWlnaHQYKmd0eF9oYXNoWCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="},
{Event{Height: 42, TxHash: txHash}, "omZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWeg=="},

// Transfer.
{
Event{
Height: 42,
TxHash: txHash,
Transfer: &TransferEvent{
From: addr1,
To: addr2,
Amount: mustInitQuantity(t, 100),
},
},
"o2ZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWemh0cmFuc2ZlcqNidG9VALkSOXiV5kcMUfq+zJ3cg/cK7YahZGZyb21VACByFDSJP2FsCYFI4s+fmePigm4TZmFtb3VudEFk",
},

// Burn.
{
Event{
Height: 42,
TxHash: txHash,
Burn: &BurnEvent{
Owner: addr1,
Amount: mustInitQuantity(t, 100),
},
},
"o2RidXJuomVvd25lclUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNmYW1vdW50QWRmaGVpZ2h0GCpndHhfaGFzaFggxnK40e9W7Sirh8NiLFEUBpvdOte4+XN0mNDAHs7wlno=",
},

// Escrow.
{
Event{
Height: 42,
TxHash: txHash,
Escrow: &EscrowEvent{
Add: &AddEscrowEvent{
Owner: addr1,
Escrow: addr2,
Amount: mustInitQuantity(t, 100),
NewShares: mustInitQuantity(t, 50),
},
},
},
"o2Zlc2Nyb3ehY2FkZKRlb3duZXJVACByFDSJP2FsCYFI4s+fmePigm4TZmFtb3VudEFkZmVzY3Jvd1UAuRI5eJXmRwxR+r7MndyD9wrthqFqbmV3X3NoYXJlc0EyZmhlaWdodBgqZ3R4X2hhc2hYIMZyuNHvVu0oq4fDYixRFAab3TrXuPlzdJjQwB7O8JZ6",
},
{
Event{
Height: 42,
TxHash: txHash,
Escrow: &EscrowEvent{
Take: &TakeEscrowEvent{
Owner: addr1,
Amount: mustInitQuantity(t, 100),
},
},
},
"o2Zlc2Nyb3ehZHRha2WiZW93bmVyVQAgchQ0iT9hbAmBSOLPn5nj4oJuE2ZhbW91bnRBZGZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWeg==",
},
{
Event{
Height: 42,
TxHash: txHash,
Escrow: &EscrowEvent{
DebondingStart: &DebondingStartEscrowEvent{
Owner: addr1,
Escrow: addr2,
Amount: mustInitQuantity(t, 100),
ActiveShares: mustInitQuantity(t, 50),
DebondingShares: mustInitQuantity(t, 25),
DebondEndTime: 42,
},
},
},
"o2Zlc2Nyb3ehb2RlYm9uZGluZ19zdGFydKZlb3duZXJVACByFDSJP2FsCYFI4s+fmePigm4TZmFtb3VudEFkZmVzY3Jvd1UAuRI5eJXmRwxR+r7MndyD9wrthqFtYWN0aXZlX3NoYXJlc0Eyb2RlYm9uZF9lbmRfdGltZRgqcGRlYm9uZGluZ19zaGFyZXNBGWZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWeg==",
},
{
Event{
Height: 42,
TxHash: txHash,
Escrow: &EscrowEvent{
Reclaim: &ReclaimEscrowEvent{
Owner: addr1,
Escrow: addr2,
Amount: mustInitQuantity(t, 100),
Shares: mustInitQuantity(t, 25),
},
},
},
"o2Zlc2Nyb3ehZ3JlY2xhaW2kZW93bmVyVQAgchQ0iT9hbAmBSOLPn5nj4oJuE2ZhbW91bnRBZGZlc2Nyb3dVALkSOXiV5kcMUfq+zJ3cg/cK7YahZnNoYXJlc0EZZmhlaWdodBgqZ3R4X2hhc2hYIMZyuNHvVu0oq4fDYixRFAab3TrXuPlzdJjQwB7O8JZ6",
},

// Allowance change.
{
Event{
Height: 42,
TxHash: txHash,
AllowanceChange: &AllowanceChangeEvent{
Owner: addr1,
Beneficiary: addr2,
Allowance: mustInitQuantity(t, 100),
Negative: false,
AmountChange: mustInitQuantity(t, 50),
},
},
"o2ZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWenBhbGxvd2FuY2VfY2hhbmdlpGVvd25lclUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNpYWxsb3dhbmNlQWRrYmVuZWZpY2lhcnlVALkSOXiV5kcMUfq+zJ3cg/cK7YahbWFtb3VudF9jaGFuZ2VBMg==",
},
{
Event{
Height: 42,
TxHash: txHash,
AllowanceChange: &AllowanceChangeEvent{
Owner: addr1,
Beneficiary: addr2,
Allowance: mustInitQuantity(t, 100),
Negative: true,
AmountChange: mustInitQuantity(t, 50),
},
},
"o2ZoZWlnaHQYKmd0eF9oYXNoWCDGcrjR71btKKuHw2IsURQGm90617j5c3SY0MAezvCWenBhbGxvd2FuY2VfY2hhbmdlpWVvd25lclUAIHIUNIk/YWwJgUjiz5+Z4+KCbhNobmVnYXRpdmX1aWFsbG93YW5jZUFka2JlbmVmaWNpYXJ5VQC5Ejl4leZHDFH6vsyd3IP3Cu2GoW1hbW91bnRfY2hhbmdlQTI=",
},
} {
enc := cbor.Marshal(tc.ev)
require.Equal(tc.expectedBase64, base64.StdEncoding.EncodeToString(enc), "serialization should match")

var dec Event
err := cbor.Unmarshal(enc, &dec)
require.NoError(err, "Unmarshal")
require.EqualValues(tc.ev, dec, "Event serialization should round-trip")
}
}
8 changes: 8 additions & 0 deletions runtime/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,11 @@ pub struct LightBlock {
pub height: u64,
pub meta: Vec<u8>,
}

/// An event emitted by the consensus layer.
#[derive(Clone, Debug, cbor::Encode, cbor::Decode)]
pub enum Event {
#[cbor(rename = "staking")]
Staking(staking::Event),
// TODO: Add support for other kind of events.
}
Loading

0 comments on commit b16e00d

Please sign in to comment.