Skip to content

Commit

Permalink
go/consensus: Add SubmitTxNoWait method
Browse files Browse the repository at this point in the history
The new method allows submitting a transaction without waiting for it to be
included in a block.
  • Loading branch information
kostko committed Jul 31, 2020
1 parent bb17ffd commit 6f8f7ee
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .changelog/3152.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
go/consensus: Add SubmitTxNoWait method

The new method allows submitting a transaction without waiting for it to be
included in a block.
3 changes: 2 additions & 1 deletion go/consensus/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ type ClientBackend interface {
LightClientBackend
TransactionAuthHandler

// SubmitTx submits a signed consensus transaction.
// SubmitTx submits a signed consensus transaction and waits for the transaction to be included
// in a block. Use SubmitTxNoWait if you only need to broadcast the transaction.
SubmitTx(ctx context.Context, tx *transaction.SignedTransaction) error

// StateToGenesis returns the genesis state at the specified block height.
Expand Down
5 changes: 5 additions & 0 deletions go/consensus/api/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,8 @@ func (b *BaseBackend) GetParameters(ctx context.Context, height int64) (*Paramet
func (b *BaseBackend) State() syncer.ReadSyncer {
panic(ErrUnsupported)
}

// Implements Backend.
func (b *BaseBackend) SubmitTxNoWait(ctx context.Context, tx *transaction.SignedTransaction) error {
panic(ErrUnsupported)
}
34 changes: 34 additions & 0 deletions go/consensus/api/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ var (
methodStateSyncGetPrefixes = lightServiceName.NewMethod("StateSyncGetPrefixes", syncer.GetPrefixesRequest{})
// methodStateSyncIterate is the StateSyncIterate method.
methodStateSyncIterate = lightServiceName.NewMethod("StateSyncIterate", syncer.IterateRequest{})
// methodSubmitTxNoWait is the SubmitTxNoWait method.
methodSubmitTxNoWait = lightServiceName.NewMethod("SubmitTxNoWait", transaction.SignedTransaction{})

// serviceDesc is the gRPC service descriptor.
serviceDesc = grpc.ServiceDesc{
Expand Down Expand Up @@ -146,6 +148,10 @@ var (
MethodName: methodStateSyncIterate.ShortName(),
Handler: handlerStateSyncIterate,
},
{
MethodName: methodSubmitTxNoWait.ShortName(),
Handler: handlerSubmitTxNoWait,
},
},
}
)
Expand Down Expand Up @@ -561,6 +567,29 @@ func handlerStateSyncIterate( // nolint: golint
return interceptor(ctx, rq, info, handler)
}

func handlerSubmitTxNoWait( // nolint: golint
srv interface{},
ctx context.Context,
dec func(interface{}) error,
interceptor grpc.UnaryServerInterceptor,
) (interface{}, error) {
rq := new(transaction.SignedTransaction)
if err := dec(rq); err != nil {
return nil, err
}
if interceptor == nil {
return nil, srv.(LightClientBackend).SubmitTxNoWait(ctx, rq)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: methodSubmitTxNoWait.FullName(),
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return nil, srv.(LightClientBackend).SubmitTxNoWait(ctx, req.(*transaction.SignedTransaction))
}
return interceptor(ctx, rq, info, handler)
}

// RegisterService registers a new client backend service with the given gRPC server.
func RegisterService(server *grpc.Server, service ClientBackend) {
server.RegisterService(&serviceDesc, service)
Expand Down Expand Up @@ -639,6 +668,11 @@ func (c *consensusLightClient) State() syncer.ReadSyncer {
return &stateReadSync{c}
}

// Implements LightClientBackend.
func (c *consensusLightClient) SubmitTxNoWait(ctx context.Context, tx *transaction.SignedTransaction) error {
return c.conn.Invoke(ctx, methodSubmitTxNoWait.FullName(), tx, nil)
}

type consensusClient struct {
consensusLightClient

Expand Down
5 changes: 5 additions & 0 deletions go/consensus/api/light.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"context"

"github.com/oasisprotocol/oasis-core/go/consensus/api/transaction"
"github.com/oasisprotocol/oasis-core/go/storage/mkvs/syncer"
)

Expand All @@ -21,6 +22,10 @@ type LightClientBackend interface {
// and verify it against the trusted local root.
State() syncer.ReadSyncer

// SubmitTxNoWait submits a signed consensus transaction, but does not wait for the transaction
// to be included in a block. Use SubmitTx if you need to wait for execution.
SubmitTxNoWait(ctx context.Context, tx *transaction.SignedTransaction) error

// TODO: Move SubmitEvidence etc. from Backend.
}

Expand Down
7 changes: 7 additions & 0 deletions go/consensus/tendermint/full/light.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import (
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
tmstate "github.com/tendermint/tendermint/state"

"github.com/oasisprotocol/oasis-core/go/common/cbor"
consensusAPI "github.com/oasisprotocol/oasis-core/go/consensus/api"
"github.com/oasisprotocol/oasis-core/go/consensus/api/transaction"
"github.com/oasisprotocol/oasis-core/go/storage/mkvs/syncer"
)

Expand Down Expand Up @@ -79,3 +81,8 @@ func (t *fullService) GetParameters(ctx context.Context, height int64) (*consens
func (t *fullService) State() syncer.ReadSyncer {
return t.mux.State().Storage()
}

// Implements LightClientBackend.
func (t *fullService) SubmitTxNoWait(ctx context.Context, tx *transaction.SignedTransaction) error {
return t.broadcastTxRaw(cbor.Marshal(tx))
}
10 changes: 10 additions & 0 deletions go/consensus/tests/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,16 @@ func ConsensusImplementationTests(t *testing.T, backend consensus.ClientBackend)
require.Equal(params.Height, blk.Height, "returned parameters height should be correct")
require.NotNil(params.Meta, "returned parameters should contain metadata")

err = backend.SubmitTxNoWait(ctx, &transaction.SignedTransaction{})
require.Error(err, "SubmitTxNoWait should fail with invalid transaction")

testTx := transaction.NewTransaction(0, nil, epochtimemock.MethodSetEpoch, epoch)
testSigner := memorySigner.NewTestSigner("consensus tests tx signer")
testSigTx, err := transaction.Sign(testSigner, testTx)
require.NoError(err, "transaction.Sign")
err = backend.SubmitTxNoWait(ctx, testSigTx)
require.NoError(err, "SubmitTxNoWait")

// We should be able to do remote state queries. Of course the state format is backend-specific
// so we simply perform some usual storage operations like fetching random keys and iterating
// through everything.
Expand Down

0 comments on commit 6f8f7ee

Please sign in to comment.