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

Expose staking event hashes + add GetGenesisDocument to consensus client API #2889

Merged
merged 2 commits into from
May 6, 2020
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
5 changes: 5 additions & 0 deletions .changelog/2889.feature.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
go/staking: Add event hashes

Staking events now have a new `TxHash` field, which contains
the hash of the transaction that caused the event (or the empty
hash in case of block events).
4 changes: 4 additions & 0 deletions .changelog/2889.feature.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
go/consensus: Add GetGenesisDocument

The consensus client now has a new method to return the original
genesis document.
3 changes: 3 additions & 0 deletions go/consensus/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ type ClientBackend interface {
// WatchBlocks returns a channel that produces a stream of consensus
// blocks as they are being finalized.
WatchBlocks(ctx context.Context) (<-chan *Block, pubsub.ClosableSubscription, error)

// GetGenesisDocument returns the original genesis document.
GetGenesisDocument(ctx context.Context) (*genesis.Document, error)
}

// Block is a consensus block.
Expand Down
33 changes: 33 additions & 0 deletions go/consensus/api/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ var (
methodGetBlock = serviceName.NewMethod("GetBlock", int64(0))
// methodGetTransactions is the GetTransactions method.
methodGetTransactions = serviceName.NewMethod("GetTransactions", int64(0))
// methodGetGenesisDocument is the GetGenesisDocument method.
methodGetGenesisDocument = serviceName.NewMethod("GetGenesisDocument", nil)

// methodWatchBlocks is the WatchBlocks method.
methodWatchBlocks = serviceName.NewMethod("WatchBlocks", nil)
Expand Down Expand Up @@ -82,6 +84,10 @@ var (
MethodName: methodGetTransactions.ShortName(),
Handler: handlerGetTransactions,
},
{
MethodName: methodGetGenesisDocument.ShortName(),
Handler: handlerGetGenesisDocument,
},
},
Streams: []grpc.StreamDesc{
{
Expand Down Expand Up @@ -297,6 +303,25 @@ func handlerGetTransactions( // nolint: golint
return interceptor(ctx, height, info, handler)
}

func handlerGetGenesisDocument( // nolint: golint
srv interface{},
ctx context.Context,
dec func(interface{}) error,
interceptor grpc.UnaryServerInterceptor,
) (interface{}, error) {
if interceptor == nil {
return srv.(Backend).GetGenesisDocument(ctx)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodGetGenesisDocument.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(Backend).GetGenesisDocument(ctx)
}
return interceptor(ctx, nil, info, handler)
}

func handlerWatchBlocks(srv interface{}, stream grpc.ServerStream) error {
if err := stream.RecvMsg(nil); err != nil {
return err
Expand Down Expand Up @@ -498,6 +523,14 @@ func (c *consensusClient) GetTransactions(ctx context.Context, height int64) ([]
return rsp, nil
}

func (c *consensusClient) GetGenesisDocument(ctx context.Context) (*genesis.Document, error) {
var rsp genesis.Document
if err := c.conn.Invoke(ctx, methodGetGenesisDocument.FullName(), nil, &rsp); err != nil {
return nil, err
}
return &rsp, nil
}

func (c *consensusClient) WatchBlocks(ctx context.Context) (<-chan *Block, pubsub.ClosableSubscription, error) {
ctx, sub := pubsub.NewContextSubscription(ctx)

Expand Down
7 changes: 6 additions & 1 deletion go/consensus/tendermint/epochtime/epochtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,12 @@ func (t *tendermintBackend) updateCached(ctx context.Context, block *tmtypes.Blo
// New constructs a new tendermint backed epochtime Backend instance,
// with the specified epoch interval.
func New(ctx context.Context, service service.TendermintService, interval int64) (api.Backend, error) {
base := service.GetGenesis().EpochTime.Base
genDoc, err := service.GetGenesisDocument(ctx)
if err != nil {
return nil, err
}

base := genDoc.EpochTime.Base
r := &tendermintBackend{
logger: logging.GetLogger("epochtime/tendermint"),
service: service,
Expand Down
7 changes: 6 additions & 1 deletion go/consensus/tendermint/epochtime_mock/epochtime_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,12 @@ func New(ctx context.Context, service service.TendermintService) (api.SetableBac
}
})

if base := service.GetGenesis().EpochTime.Base; base != 0 {
genDoc, err := service.GetGenesisDocument(ctx)
if err != nil {
return nil, err
}

if base := genDoc.EpochTime.Base; base != 0 {
r.logger.Warn("ignoring non-zero base genesis epoch",
"base", base,
)
Expand Down
4 changes: 0 additions & 4 deletions go/consensus/tendermint/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/oasislabs/oasis-core/go/common/service"
consensus "github.com/oasislabs/oasis-core/go/consensus/api"
"github.com/oasislabs/oasis-core/go/consensus/tendermint/abci"
genesis "github.com/oasislabs/oasis-core/go/genesis/api"
)

// TendermintService provides Tendermint access to Oasis core backends.
Expand All @@ -33,9 +32,6 @@ type TendermintService interface {
// ABCI multiplexer.
SetTransactionAuthHandler(abci.TransactionAuthHandler) error

// GetGenesis will return the oasis genesis document.
GetGenesis() *genesis.Document

// GetHeight returns the Tendermint block height.
GetHeight(ctx context.Context) (int64, error)

Expand Down
84 changes: 72 additions & 12 deletions go/consensus/tendermint/staking/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
tmtypes "github.com/tendermint/tendermint/types"

"github.com/oasislabs/oasis-core/go/common/cbor"
"github.com/oasislabs/oasis-core/go/common/crypto/hash"
"github.com/oasislabs/oasis-core/go/common/crypto/signature"
"github.com/oasislabs/oasis-core/go/common/logging"
"github.com/oasislabs/oasis-core/go/common/pubsub"
Expand All @@ -37,6 +38,14 @@ type tendermintBackend struct {
closedCh chan struct{}
}

// Extend the abci Event struct with the transaction hash if the event was
// the result of a transaction. Block events have Hash set to the empty hash.
type abciEventWithHash struct {
abcitypes.Event

TxHash hash.Hash
}

func (tb *tendermintBackend) TotalSupply(ctx context.Context, height int64) (*quantity.Quantity, error) {
q, err := tb.querier.QueryAt(ctx, height)
if err != nil {
Expand Down Expand Up @@ -142,6 +151,23 @@ func (tb *tendermintBackend) StateToGenesis(ctx context.Context, height int64) (
return q.Genesis(ctx)
}

func convertTmBlockEvents(beginBlockEvents []abcitypes.Event, endBlockEvents []abcitypes.Event) []abciEventWithHash {
var tmEvents []abciEventWithHash
for _, bbe := range beginBlockEvents {
var ev abciEventWithHash
ev.Event = bbe
ev.TxHash.Empty()
tmEvents = append(tmEvents, ev)
}
for _, ebe := range endBlockEvents {
var ev abciEventWithHash
ev.Event = ebe
ev.TxHash.Empty()
tmEvents = append(tmEvents, ev)
}
return tmEvents
}

func (tb *tendermintBackend) GetEvents(ctx context.Context, height int64) ([]api.Event, error) {
// Get block results at given height.
var results *tmrpctypes.ResultBlockResults
Expand All @@ -154,10 +180,33 @@ func (tb *tendermintBackend) GetEvents(ctx context.Context, height int64) ([]api
return nil, err
}

// Get transactions at given height.
txns, err := tb.service.GetTransactions(ctx, height)
if err != nil {
tb.logger.Error("failed to get tendermint transactions",
"err", err,
"height", height,
)
return nil, err
}

// Decode events from block results.
tmEvents := append(results.BeginBlockEvents, results.EndBlockEvents...)
for _, txResults := range results.TxsResults {
tmEvents = append(tmEvents, txResults.Events...)
tmEvents := convertTmBlockEvents(results.BeginBlockEvents, results.EndBlockEvents)
for txIdx, txResults := range results.TxsResults {
// The order of transactions in txns and results.TxsResults is
// supposed to match, so the same index in both slices refers to the
// same transaction.

// Generate hash of transaction.
evHash := hash.NewFromBytes(txns[txIdx])

// Append hash to each event.
for _, tmEv := range txResults.Events {
var ev abciEventWithHash
ev.Event = tmEv
ev.TxHash = evHash
tmEvents = append(tmEvents, ev)
}
}
return tb.onABCIEvents(ctx, tmEvents, height, false)
}
Expand Down Expand Up @@ -210,24 +259,35 @@ func (tb *tendermintBackend) worker(ctx context.Context) {
}

func (tb *tendermintBackend) onEventDataNewBlock(ctx context.Context, ev tmtypes.EventDataNewBlock) {
events := append([]abcitypes.Event{}, ev.ResultBeginBlock.GetEvents()...)
events = append(events, ev.ResultEndBlock.GetEvents()...)
events := convertTmBlockEvents(ev.ResultBeginBlock.GetEvents(), ev.ResultEndBlock.GetEvents())

_, _ = tb.onABCIEvents(ctx, events, ev.Block.Header.Height, true)
}

func (tb *tendermintBackend) onEventDataTx(ctx context.Context, tx tmtypes.EventDataTx) {
_, _ = tb.onABCIEvents(ctx, tx.Result.Events, tx.Height, true)
evHash := hash.NewFromBytes(tx.Tx)

var events []abciEventWithHash
for _, tmEv := range tx.Result.Events {
var ev abciEventWithHash
ev.Event = tmEv
ev.TxHash = evHash
events = append(events, ev)
}

_, _ = tb.onABCIEvents(ctx, events, tx.Height, true)
}

func (tb *tendermintBackend) onABCIEvents(context context.Context, tmEvents []abcitypes.Event, height int64, doBroadcast bool) ([]api.Event, error) {
func (tb *tendermintBackend) onABCIEvents(context context.Context, tmEvents []abciEventWithHash, height int64, doBroadcast bool) ([]api.Event, error) {
var events []api.Event
for _, tmEv := range tmEvents {
// Ignore events that don't relate to the staking app.
if tmEv.GetType() != app.EventType {
continue
}

eh := tmEv.TxHash

for _, pair := range tmEv.GetAttributes() {
key := pair.GetKey()
val := pair.GetValue()
Expand All @@ -250,7 +310,7 @@ func (tb *tendermintBackend) onABCIEvents(context context.Context, tmEvents []ab
if doBroadcast {
tb.escrowNotifier.Broadcast(ee)
} else {
events = append(events, api.Event{EscrowEvent: ee})
events = append(events, api.Event{TxHash: eh, EscrowEvent: ee})
}
} else if bytes.Equal(key, app.KeyTransfer) {
// Transfer event.
Expand All @@ -269,7 +329,7 @@ func (tb *tendermintBackend) onABCIEvents(context context.Context, tmEvents []ab
if doBroadcast {
tb.transferNotifier.Broadcast(&e)
} else {
events = append(events, api.Event{TransferEvent: &e})
events = append(events, api.Event{TxHash: eh, TransferEvent: &e})
}
} else if bytes.Equal(key, app.KeyReclaimEscrow) {
// Reclaim escrow event.
Expand All @@ -290,7 +350,7 @@ func (tb *tendermintBackend) onABCIEvents(context context.Context, tmEvents []ab
if doBroadcast {
tb.escrowNotifier.Broadcast(ee)
} else {
events = append(events, api.Event{EscrowEvent: ee})
events = append(events, api.Event{TxHash: eh, EscrowEvent: ee})
}
} else if bytes.Equal(key, app.KeyAddEscrow) {
// Add escrow event.
Expand All @@ -311,7 +371,7 @@ func (tb *tendermintBackend) onABCIEvents(context context.Context, tmEvents []ab
if doBroadcast {
tb.escrowNotifier.Broadcast(ee)
} else {
events = append(events, api.Event{EscrowEvent: ee})
events = append(events, api.Event{TxHash: eh, EscrowEvent: ee})
}
} else if bytes.Equal(key, app.KeyBurn) {
// Burn event.
Expand All @@ -330,7 +390,7 @@ func (tb *tendermintBackend) onABCIEvents(context context.Context, tmEvents []ab
if doBroadcast {
tb.burnNotifier.Broadcast(&e)
} else {
events = append(events, api.Event{BurnEvent: &e})
events = append(events, api.Event{TxHash: eh, BurnEvent: &e})
}
}
}
Expand Down
20 changes: 6 additions & 14 deletions go/consensus/tendermint/tendermint.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ import (
tmstaking "github.com/oasislabs/oasis-core/go/consensus/tendermint/staking"
epochtimeAPI "github.com/oasislabs/oasis-core/go/epochtime/api"
genesisAPI "github.com/oasislabs/oasis-core/go/genesis/api"
"github.com/oasislabs/oasis-core/go/genesis/file"
keymanagerAPI "github.com/oasislabs/oasis-core/go/keymanager/api"
cmbackground "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common/background"
cmflags "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common/flags"
Expand Down Expand Up @@ -361,16 +360,9 @@ func (t *tendermintService) StateToGenesis(ctx context.Context, blockHeight int6
blockHeight = blk.Header.Height

// Get initial genesis doc.
genesisFileProvider, err := file.DefaultFileProvider()
genesisDoc, err := t.GetGenesisDocument(ctx)
if err != nil {
t.Logger.Error("failed getting genesis file provider",
"err", err,
)
return nil, err
}
genesisDoc, err := genesisFileProvider.GetGenesisDocument()
if err != nil {
t.Logger.Error("failed getting genesis document from file provider",
t.Logger.Error("failed getting genesis document",
"err", err,
)
return nil, err
Expand Down Expand Up @@ -449,6 +441,10 @@ func (t *tendermintService) StateToGenesis(ctx context.Context, blockHeight int6
}, nil
}

func (t *tendermintService) GetGenesisDocument(ctx context.Context) (*genesisAPI.Document, error) {
Copy link
Member

@kostko kostko May 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to remove the existing GetGenesis method that exists in the tendermint-specific service (any callers should use this new one).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the right thing to name the method? It's a state dump, not a genesis document (#2886 is illustrative of the fact that there is a difference).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the suggested changes, GetGenesisDocument returns t.genesis, so it should be equivalent to the old GetGenesis method.

return t.genesis, nil
}

func (t *tendermintService) RegisterHaltHook(hook func(context.Context, int64, epochtimeAPI.EpochTime)) {
if !t.initialized() {
return
Expand Down Expand Up @@ -618,10 +614,6 @@ func (t *tendermintService) SetTransactionAuthHandler(handler abci.TransactionAu
return t.mux.SetTransactionAuthHandler(handler)
}

func (t *tendermintService) GetGenesis() *genesisAPI.Document {
return t.genesis
}

func (t *tendermintService) TransactionAuthHandler() consensusAPI.TransactionAuthHandler {
return t.mux.TransactionAuthHandler()
}
Expand Down
4 changes: 4 additions & 0 deletions go/consensus/tests/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ func ConsensusImplementationTests(t *testing.T, backend consensus.ClientBackend)
ctx, cancel := context.WithTimeout(context.Background(), recvTimeout)
defer cancel()

genDoc, err := backend.GetGenesisDocument(ctx)
require.NoError(err, "GetGenesisDocument")
require.NotNil(genDoc, "returned genesis document should not be nil")

blk, err := backend.GetBlock(ctx, consensus.HeightLatest)
require.NoError(err, "GetBlock")
require.NotNil(blk, "returned block should not be nil")
Expand Down
3 changes: 3 additions & 0 deletions go/staking/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"fmt"

"github.com/oasislabs/oasis-core/go/common/crypto/hash"
"github.com/oasislabs/oasis-core/go/common/crypto/signature"
"github.com/oasislabs/oasis-core/go/common/errors"
"github.com/oasislabs/oasis-core/go/common/pubsub"
Expand Down Expand Up @@ -156,6 +157,8 @@ type EscrowEvent struct {

// Event signifies a staking event, returned via GetEvents.
type Event struct {
TxHash hash.Hash `json:"tx_hash,omitempty"`

TransferEvent *TransferEvent `json:"transfer,omitempty"`
BurnEvent *BurnEvent `json:"burn,omitempty"`
EscrowEvent *EscrowEvent `json:"escrow,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions go/staking/tests/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ func testTransfer(t *testing.T, state *stakingTestsState, backend api.Backend, c
if evt.TransferEvent != nil {
if evt.TransferEvent.From.Equal(ev.From) && evt.TransferEvent.To.Equal(ev.To) && evt.TransferEvent.Tokens.Cmp(&ev.Tokens) == 0 {
gotIt = true
require.True(!evt.TxHash.IsEmpty(), "GetEvents should return valid txn hash")
break
}
}
Expand Down