Repository: vegaprotocol/vegawallet (go)

Issue:
Allow non-blocking transaction confirmation process
When we `Policy.Ask()` for transaction review and give consent, the confirmation channel is blocking, it shouldn't otherwise it's preventing the application to quit. That shouldn't.

Pull request description:
Make consent request cancelable
Close #565 

Patch:
diff --git a/cmd/service_run.go b/cmd/service_run.go
index 84ab1c6..f4cae7d 100644
--- a/cmd/service_run.go
+++ b/cmd/service_run.go
@@ -8,7 +8,6 @@ import (
 	"net/http"
 	"os"
 	"os/signal"
-	"strings"
 	"syscall"
 
 	vgterm "code.vegaprotocol.io/shared/libs/term"
@@ -24,12 +23,15 @@ import (
 	"code.vegaprotocol.io/vegawallet/service"
 	svcstore "code.vegaprotocol.io/vegawallet/service/store/v1"
 	"code.vegaprotocol.io/vegawallet/wallets"
+	"github.com/golang/protobuf/jsonpb"
 
 	"github.com/skratchdot/open-golang/open"
 	"github.com/spf13/cobra"
 	"go.uber.org/zap"
 )
 
+const MaxConsentRequests = 100
+
 var ErrEnableAutomaticConsentFlagIsRequiredWithoutTTY = errors.New("--automatic-consent flag is required without TTY")
 
 var (
@@ -209,9 +211,6 @@ func RunService(w io.Writer, rf *RootFlags, f *RunServiceFlags) error {
 		return fmt.Errorf("couldn't initialise the node forwarder: %w", err)
 	}
 
-	pendingConsents := make(chan service.ConsentRequest, 1)
-	sentTxs := make(chan service.SentTransaction)
-
 	cliLog, cliLogPath, err := BuildJSONLogger(cfg.Level.String(), vegaPaths, paths.WalletCLILogsHome)
 	if err != nil {
 		return err
@@ -220,6 +219,11 @@ func RunService(w io.Writer, rf *RootFlags, f *RunServiceFlags) error {
 
 	cliLog = cliLog.Named("command")
 
+	consentRequests := make(chan service.ConsentRequest, MaxConsentRequests)
+	defer close(consentRequests)
+	sentTransactions := make(chan service.SentTransaction)
+	defer close(sentTransactions)
+
 	var policy service.Policy
 	if vgterm.HasTTY() {
 		cliLog.Info("TTY detected")
@@ -228,7 +232,7 @@ func RunService(w io.Writer, rf *RootFlags, f *RunServiceFlags) error {
 			policy = service.NewAutomaticConsentPolicy()
 		} else {
 			cliLog.Info("Explicit consent enabled")
-			policy = service.NewExplicitConsentPolicy(pendingConsents, sentTxs)
+			policy = service.NewExplicitConsentPolicy(ctx, consentRequests, sentTransactions)
 		}
 	} else {
 		cliLog.Info("No TTY detected")
@@ -296,7 +300,7 @@ func RunService(w io.Writer, rf *RootFlags, f *RunServiceFlags) error {
 		p.NextLine()
 	}
 
-	waitSig(ctx, cancel, cliLog, pendingConsents, sentTxs, p)
+	waitSig(ctx, cancel, cliLog, consentRequests, sentTransactions, p)
 
 	return nil
 }
@@ -366,54 +370,77 @@ func startTokenDApp(log *zap.Logger, f *RunServiceFlags, cfg *network.Network, c
 }
 
 // waitSig will wait for a sigterm or sigint interrupt.
-func waitSig(ctx context.Context, cfunc func(), log *zap.Logger, pendingSigRequests chan service.ConsentRequest, sentTxs chan service.SentTransaction, p *printer.InteractivePrinter) {
+func waitSig(
+	ctx context.Context,
+	cancelFunc context.CancelFunc,
+	log *zap.Logger,
+	consentRequests chan service.ConsentRequest,
+	sentTransactions chan service.SentTransaction,
+	p *printer.InteractivePrinter,
+) {
 	gracefulStop := make(chan os.Signal, 1)
+	defer close(gracefulStop)
 
 	signal.Notify(gracefulStop, syscall.SIGTERM)
 	signal.Notify(gracefulStop, syscall.SIGINT)
 	signal.Notify(gracefulStop, syscall.SIGQUIT)
 
+	go func() {
+		if err := handleConsentRequests(ctx, log, consentRequests, sentTransactions, p); err != nil {
+			cancelFunc()
+		}
+	}()
+
 	for {
 		select {
 		case sig := <-gracefulStop:
 			log.Info("caught signal", zap.String("signal", fmt.Sprintf("%+v", sig)))
-			cfunc()
+			cancelFunc()
 			return
 		case <-ctx.Done():
 			// nothing to do
 			return
-		case signRequest := <-pendingSigRequests:
-			txStr, err := signRequest.String()
+		}
+	}
+}
+
+func handleConsentRequests(ctx context.Context, log *zap.Logger, consentRequests chan service.ConsentRequest, sentTransactions chan service.SentTransaction, p *printer.InteractivePrinter) error {
+	for {
+		select {
+		case <-ctx.Done():
+			// nothing to do
+			return nil
+		case consentRequest := <-consentRequests:
+			m := jsonpb.Marshaler{Indent: "    "}
+			marshalledTx, err := m.MarshalToString(consentRequest.Tx)
 			if err != nil {
-				log.Info("failed to marshall sign request content")
-				cfunc()
-				return
+				log.Error("couldn't marshal transaction from consent request", zap.Error(err))
+				return err
 			}
+
 			p.BlueArrow().Text("New transaction received: ").NextLine()
-			p.InfoText(txStr).NextLine()
+			p.InfoText(marshalledTx).NextLine()
 
 			if flags.DoYouApproveTx() {
-				log.Info("user approved the signing of the transaction", zap.Any("transaction", txStr))
-				signRequest.Confirmations <- service.ConsentConfirmation{Decision: true, TxStr: txStr}
+				log.Info("user approved the signing of the transaction", zap.Any("transaction", marshalledTx))
+				consentRequest.Confirmation <- service.ConsentConfirmation{Decision: true}
 				p.CheckMark().SuccessText("Transaction approved").NextLine()
 
-				sentTx := <-sentTxs
+				sentTx := <-sentTransactions
 				log.Info("transaction sent", zap.Any("ID", sentTx.TxID), zap.Any("hash", sentTx.TxHash))
 				if sentTx.Error != nil {
-					log.Error("transaction failed", zap.Any("transaction", txStr))
-					p.BangMark().DangerText("Transaction failed! ").NextLine()
-					p.BangMark().DangerText("Error: ").DangerText(sentTx.Error.Error()).NextLine()
-					p.BangMark().DangerText("Details: ").DangerText(strings.Join(sentTx.ErrorDetails, " ,")).NextSection()
+					log.Error("transaction failed", zap.Any("transaction", marshalledTx))
+					p.BangMark().DangerText("Transaction failed").NextLine()
+					p.BangMark().DangerText("Error: ").DangerText(sentTx.Error.Error()).NextSection()
 				} else {
 					log.Info("transaction sent", zap.Any("hash", sentTx.TxHash))
 					p.CheckMark().Text("Transaction with hash ").SuccessText(sentTx.TxHash).Text(" sent!").NextSection()
 				}
 			} else {
-				log.Info("user rejected the signing of the transaction", zap.Any("transaction", txStr))
-				signRequest.Confirmations <- service.ConsentConfirmation{Decision: false, TxStr: txStr}
+				log.Info("user rejected the signing of the transaction", zap.Any("transaction", marshalledTx))
+				consentRequest.Confirmation <- service.ConsentConfirmation{Decision: false}
 				p.BangMark().DangerText("Transaction rejected").NextSection()
 			}
-			close(signRequest.Confirmations)
 		}
 	}
 }
diff --git a/service/errors.go b/service/errors.go
index 93a4d9c..ebd00ba 100644
--- a/service/errors.go
+++ b/service/errors.go
@@ -7,14 +7,15 @@ import (
 )
 
 var (
-	ErrInvalidToken           = errors.New("invalid token")
-	ErrInvalidClaims          = errors.New("invalid claims")
-	ErrInvalidOrMissingToken  = newErrorResponse("invalid or missing token")
-	ErrCouldNotReadRequest    = errors.New("couldn't read request")
-	ErrCouldNotGetBlockHeight = errors.New("couldn't get last block height")
-	ErrShouldBeBase64Encoded  = errors.New("should be base64 encoded")
-	ErrRSAKeysAlreadyExists   = errors.New("RSA keys already exist")
-	ErrRejectedSignRequest    = errors.New("user rejected sign request")
+	ErrInvalidToken              = errors.New("invalid token")
+	ErrInvalidClaims             = errors.New("invalid claims")
+	ErrInvalidOrMissingToken     = newErrorResponse("invalid or missing token")
+	ErrCouldNotReadRequest       = errors.New("couldn't read request")
+	ErrCouldNotGetBlockHeight    = errors.New("couldn't get last block height")
+	ErrShouldBeBase64Encoded     = errors.New("should be base64 encoded")
+	ErrRSAKeysAlreadyExists      = errors.New("RSA keys already exist")
+	ErrRejectedSignRequest       = errors.New("user rejected sign request")
+	ErrInterruptedConsentRequest = errors.New("process to request consent has been interrupted")
 )
 
 type ErrorsResponse struct {
@@ -35,10 +36,3 @@ func newErrorResponse(e string) ErrorResponse {
 		ErrorStr: e,
 	}
 }
-
-func newErrorWithDetails(e string, details []string) ErrorResponse {
-	return ErrorResponse{
-		ErrorStr: e,
-		Details:  details,
-	}
-}
diff --git a/service/mocks/policies_mock.go b/service/mocks/policies_mock.go
index 6ed0daa..395fe14 100644
--- a/service/mocks/policies_mock.go
+++ b/service/mocks/policies_mock.go
@@ -29,7 +29,3 @@ func (p *MockConsentPolicy) Ask(tx *v1.SubmitTransactionRequest, txID string, re
 	}
 	return true, nil
 }
-
-func (p *MockConsentPolicy) NeedsInteractiveOutput() bool {
-	return true
-}
diff --git a/service/policies.go b/service/policies.go
index b9306df..f97cd96 100644
--- a/service/policies.go
+++ b/service/policies.go
@@ -1,44 +1,35 @@
 package service
 
 import (
+	"context"
 	"time"
 
 	commandspb "code.vegaprotocol.io/protos/vega/commands/v1"
 	v1 "code.vegaprotocol.io/protos/vega/wallet/v1"
-	"github.com/golang/protobuf/jsonpb"
 )
 
 type ConsentConfirmation struct {
-	TxStr    string
+	TxID     string
 	Decision bool
 }
 
 type ConsentRequest struct {
-	TxID          string
-	Tx            *v1.SubmitTransactionRequest
-	ReceivedAt    time.Time
-	Confirmations chan ConsentConfirmation
-}
-
-func (r *ConsentRequest) String() (string, error) {
-	m := jsonpb.Marshaler{Indent: "    "}
-	marshalledRequest, err := m.MarshalToString(r.Tx)
-	return marshalledRequest, err
+	TxID         string
+	Tx           *v1.SubmitTransactionRequest
+	ReceivedAt   time.Time
+	Confirmation chan ConsentConfirmation
 }
 
 type SentTransaction struct {
-	TxHash       string
-	TxID         string
-	ReceivedAt   time.Time
-	Tx           *commandspb.Transaction
-	Error        error
-	ErrorDetails []string
+	TxHash string
+	TxID   string
+	Tx     *commandspb.Transaction
+	Error  error
 }
 
 type Policy interface {
 	Ask(tx *v1.SubmitTransactionRequest, txID string, receivedAt time.Time) (bool, error)
 	Report(tx SentTransaction)
-	NeedsInteractiveOutput() bool
 }
 
 type AutomaticConsentPolicy struct{}
@@ -47,7 +38,7 @@ func NewAutomaticConsentPolicy() Policy {
 	return &AutomaticConsentPolicy{}
 }
 
-func (p *AutomaticConsentPolicy) Ask(_ *v1.SubmitTransactionRequest, txID string, receivedAt time.Time) (bool, error) {
+func (p *AutomaticConsentPolicy) Ask(_ *v1.SubmitTransactionRequest, _ string, _ time.Time) (bool, error) {
 	return true, nil
 }
 
@@ -55,36 +46,62 @@ func (p *AutomaticConsentPolicy) Report(_ SentTransaction) {
 	// Nothing to report as we expect this policy to be non-interactive.
 }
 
-func (p *AutomaticConsentPolicy) NeedsInteractiveOutput() bool {
-	return false
-}
-
 type ExplicitConsentPolicy struct {
-	pendingEvents chan ConsentRequest
-	sentTxs       chan SentTransaction
+	// ctx is used to interrupt the wait for consent confirmation
+	ctx context.Context
+
+	consentRequestsChan  chan ConsentRequest
+	sentTransactionsChan chan SentTransaction
 }
 
-func NewExplicitConsentPolicy(pending chan ConsentRequest, sentTxs chan SentTransaction) Policy {
+func NewExplicitConsentPolicy(ctx context.Context, consentRequests chan ConsentRequest, sentTransactions chan SentTransaction) Policy {
 	return &ExplicitConsentPolicy{
-		pendingEvents: pending,
-		sentTxs:       sentTxs,
+		ctx:                  ctx,
+		consentRequestsChan:  consentRequests,
+		sentTransactionsChan: sentTransactions,
 	}
 }
 
 func (p *ExplicitConsentPolicy) Ask(tx *v1.SubmitTransactionRequest, txID string, receivedAt time.Time) (bool, error) {
-	confirmations := make(chan ConsentConfirmation)
-	consentReq := ConsentRequest{Tx: tx, Confirmations: confirmations, ReceivedAt: receivedAt}
-	consentReq.TxID = txID
-	p.pendingEvents <- consentReq
+	confirmationChan := make(chan ConsentConfirmation, 1)
+	defer close(confirmationChan)
+
+	consentRequest := ConsentRequest{
+		TxID:         txID,
+		Tx:           tx,
+		ReceivedAt:   receivedAt,
+		Confirmation: confirmationChan,
+	}
+
+	if err := p.sendConsentRequest(consentRequest); err != nil {
+		return false, err
+	}
 
-	c := <-confirmations
-	return c.Decision, nil
+	return p.receiveConsentConfirmation(consentRequest)
 }
 
-func (p *ExplicitConsentPolicy) Report(tx SentTransaction) {
-	p.sentTxs <- tx
+func (p *ExplicitConsentPolicy) receiveConsentConfirmation(consentRequest ConsentRequest) (bool, error) {
+	for {
+		select {
+		case <-p.ctx.Done():
+			return false, ErrInterruptedConsentRequest
+		case decision := <-consentRequest.Confirmation:
+			return decision.Decision, nil
+		}
+	}
 }
 
-func (p *ExplicitConsentPolicy) NeedsInteractiveOutput() bool {
-	return true
+func (p *ExplicitConsentPolicy) sendConsentRequest(consentRequest ConsentRequest) error {
+	for {
+		select {
+		case <-p.ctx.Done():
+			return ErrInterruptedConsentRequest
+		case p.consentRequestsChan <- consentRequest:
+			return nil
+		}
+	}
+}
+
+func (p *ExplicitConsentPolicy) Report(tx SentTransaction) {
+	p.sentTransactionsChan <- tx
 }
diff --git a/service/service.go b/service/service.go
index aec8f82..a1093fd 100644
--- a/service/service.go
+++ b/service/service.go
@@ -14,7 +14,6 @@ import (
 	vgrand "code.vegaprotocol.io/shared/libs/rand"
 
 	"code.vegaprotocol.io/protos/commands"
-	typespb "code.vegaprotocol.io/protos/vega"
 	api "code.vegaprotocol.io/protos/vega/api/v1"
 	commandspb "code.vegaprotocol.io/protos/vega/commands/v1"
 	walletpb "code.vegaprotocol.io/protos/vega/wallet/v1"
@@ -28,7 +27,6 @@ import (
 	"github.com/julienschmidt/httprouter"
 	"github.com/rs/cors"
 	"go.uber.org/zap"
-	"google.golang.org/grpc/status"
 )
 
 type Service struct {
@@ -716,7 +714,7 @@ func (s *Service) VerifyAny(w http.ResponseWriter, r *http.Request, _ httprouter
 	s.writeSuccess(w, VerifyAnyResponse{Valid: verified})
 }
 
-func (s *Service) CheckTx(token string, w http.ResponseWriter, r *http.Request, p httprouter.Params) {
+func (s *Service) CheckTx(token string, w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
 	defer r.Body.Close()
 
 	name, err := s.auth.VerifyToken(token)
@@ -757,20 +755,7 @@ func (s *Service) CheckTx(token string, w http.ResponseWriter, r *http.Request,
 
 	result, err := s.nodeForward.CheckTx(r.Context(), tx, cltIdx)
 	if err != nil {
-		if st, ok := status.FromError(err); ok {
-			var details []string
-			for _, v := range st.Details() {
-				v, ok := v.(*typespb.ErrorDetail)
-				if !ok {
-					s.writeError(w, newErrorResponse(fmt.Sprintf("couldn't cast status details to error details: %v", v)), http.StatusInternalServerError)
-				}
-				details = append(details, v.Message)
-			}
-
-			s.writeError(w, newErrorWithDetails(err.Error(), details), http.StatusInternalServerError)
-		} else {
-			s.writeInternalError(w, err)
-		}
+		s.writeInternalError(w, err)
 		return
 	}
 
@@ -820,7 +805,9 @@ func (s *Service) signTx(token string, w http.ResponseWriter, r *http.Request, _
 	receivedAt := time.Now()
 	approved, err := s.policy.Ask(req, txID, receivedAt)
 	if err != nil {
-		s.log.Panic("failed getting transaction sign request answer", zap.Error(err))
+		s.log.Error("couldn't get user consent", zap.Error(err))
+		s.writeError(w, err, http.StatusServiceUnavailable)
+		return
 	}
 
 	if !approved {
@@ -832,12 +819,20 @@ func (s *Service) signTx(token string, w http.ResponseWriter, r *http.Request, _
 
 	blockData, cltIdx, err := s.nodeForward.LastBlockHeightAndHash(r.Context())
 	if err != nil {
+		s.policy.Report(SentTransaction{
+			TxID:  txID,
+			Error: ErrCouldNotGetBlockHeight,
+		})
 		s.writeInternalError(w, ErrCouldNotGetBlockHeight)
 		return
 	}
 
 	tx, err := s.handler.SignTx(name, req, blockData.Height)
 	if err != nil {
+		s.policy.Report(SentTransaction{
+			TxID:  txID,
+			Error: err,
+		})
 		s.writeInternalError(w, err)
 		return
 	}
@@ -846,6 +841,11 @@ func (s *Service) signTx(token string, w http.ResponseWriter, r *http.Request, _
 	tid := vgcrypto.RandomHash()
 	powNonce, _, err := vgcrypto.PoW(blockData.Hash, tid, uint(blockData.SpamPowDifficulty), vgcrypto.Sha3)
 	if err != nil {
+		s.policy.Report(SentTransaction{
+			Tx:    tx,
+			TxID:  txID,
+			Error: err,
+		})
 		s.writeInternalError(w, err)
 		return
 	}
@@ -856,40 +856,19 @@ func (s *Service) signTx(token string, w http.ResponseWriter, r *http.Request, _
 
 	txHash, err := s.nodeForward.SendTx(r.Context(), tx, ty, cltIdx)
 	if err != nil {
-		if st, ok := status.FromError(err); ok {
-			var details []string
-			for _, v := range st.Details() {
-				v, ok := v.(*typespb.ErrorDetail)
-				if !ok {
-					continue
-				}
-				details = append(details, v.Message)
-			}
-			s.policy.Report(SentTransaction{
-				Tx:           tx,
-				ReceivedAt:   receivedAt,
-				TxID:         txID,
-				Error:        err,
-				ErrorDetails: details,
-			})
-			s.writeInternalError(w, newErrorWithDetails(err.Error(), details))
-			return
-		}
 		s.policy.Report(SentTransaction{
-			Tx:         tx,
-			ReceivedAt: receivedAt,
-			TxID:       txID,
-			Error:      err,
+			Tx:    tx,
+			TxID:  txID,
+			Error: err,
 		})
 		s.writeInternalError(w, err)
 		return
 	}
 
 	s.policy.Report(SentTransaction{
-		TxHash:     txHash,
-		ReceivedAt: receivedAt,
-		TxID:       txID,
-		Tx:         tx,
+		TxHash: txHash,
+		TxID:   txID,
+		Tx:     tx,
 	})
 
 	s.writeSuccess(w, struct {
@@ -1021,9 +1000,9 @@ func (s *Service) writeSuccess(w http.ResponseWriter, data interface{}) {
 
 func (s *Service) handle(method string, path string, handle httprouter.Handle) {
 	loggedEndpoint := func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
-		s.log.Info(fmt.Sprintf("--> %s %s", method, path))
+		s.log.Info(fmt.Sprintf("Entering %s %s", method, path))
 		handle(w, r, p)
-		s.log.Info(fmt.Sprintf("<-- %s %s", method, path))
+		s.log.Info(fmt.Sprintf("Leaving %s %s", method, path))
 	}
 	s.Handle(method, path, loggedEndpoint)
 }


Test patch:
diff --git a/service/policies_test.go b/service/policies_test.go
new file mode 100644
index 0000000..1fcfbb5
--- /dev/null
+++ b/service/policies_test.go
@@ -0,0 +1,97 @@
+package service_test
+
+import (
+	"context"
+	"sync"
+	"testing"
+	"time"
+
+	commandspb "code.vegaprotocol.io/protos/vega/commands/v1"
+	walletpb "code.vegaprotocol.io/protos/vega/wallet/v1"
+	vgrand "code.vegaprotocol.io/shared/libs/rand"
+	"code.vegaprotocol.io/vegawallet/service"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestExplicitConsentPolicy(t *testing.T) {
+	t.Run("Requesting explicit consent succeeds", testRequestingExplicitConsentSucceeds)
+	t.Run("Canceling consent requests succeeds", testCancelingConsentRequestSucceeds)
+	t.Run("Reporting sent transaction succeeds", testReportingSentTransactionSucceeds)
+}
+
+func testRequestingExplicitConsentSucceeds(t *testing.T) {
+	// given
+	txn := &walletpb.SubmitTransactionRequest{}
+	txID := vgrand.RandomStr(5)
+	consentRequestsChan := make(chan service.ConsentRequest, 1)
+	sentTransactionsChan := make(chan service.SentTransaction, 1)
+
+	// setup
+	p := service.NewExplicitConsentPolicy(context.Background(), consentRequestsChan, sentTransactionsChan)
+
+	go func() {
+		req := <-consentRequestsChan
+		d := service.ConsentConfirmation{TxID: txID, Decision: false}
+		req.Confirmation <- d
+	}()
+
+	// when
+	answer, err := p.Ask(txn, txID, time.Now())
+	require.Nil(t, err)
+	require.False(t, answer)
+}
+
+func testCancelingConsentRequestSucceeds(t *testing.T) {
+	// given
+	ctx, cancelFn := context.WithCancel(context.Background())
+	txn := &walletpb.SubmitTransactionRequest{}
+	txID := vgrand.RandomStr(5)
+	// Channels have a smaller buffer than the number of requests, on purpose.
+	// We have to ensure channels are not blocking and preventing interruption
+	// when full.
+	consentRequestsChan := make(chan service.ConsentRequest, 1)
+	sentTransactionsChan := make(chan service.SentTransaction, 1)
+
+	// setup
+	p := service.NewExplicitConsentPolicy(ctx, consentRequestsChan, sentTransactionsChan)
+
+	var wg sync.WaitGroup
+	for i := 0; i < 5; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			answer, err := p.Ask(txn, txID, time.Now())
+			require.ErrorIs(t, err, service.ErrInterruptedConsentRequest)
+			assert.False(t, answer)
+		}()
+	}
+
+	// interrupting the consent requests
+	cancelFn()
+
+	// waiting for all consent request to be interrupted
+	wg.Wait()
+}
+
+func testReportingSentTransactionSucceeds(t *testing.T) {
+	txID := vgrand.RandomStr(5)
+	txHash := vgrand.RandomStr(5)
+	consentRequestsChan := make(chan service.ConsentRequest, 1)
+	sentTransactionsChan := make(chan service.SentTransaction, 1)
+
+	// setup
+	p := service.NewExplicitConsentPolicy(context.Background(), consentRequestsChan, sentTransactionsChan)
+
+	// when
+	p.Report(service.SentTransaction{
+		TxHash: txHash,
+		TxID:   txID,
+		Tx:     &commandspb.Transaction{},
+	})
+
+	// then
+	sentTransaction := <-sentTransactionsChan
+	require.Equal(t, txHash, sentTransaction.TxHash)
+	require.Equal(t, txID, sentTransaction.TxID)
+}
diff --git a/service/service_test.go b/service/service_test.go
index fcf03b4..b694855 100644
--- a/service/service_test.go
+++ b/service/service_test.go
@@ -11,10 +11,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/stretchr/testify/require"
-
-	v1 "code.vegaprotocol.io/protos/vega/wallet/v1"
-
 	api "code.vegaprotocol.io/protos/vega/api/v1"
 	commandspb "code.vegaprotocol.io/protos/vega/commands/v1"
 	vgrand "code.vegaprotocol.io/shared/libs/rand"
@@ -100,7 +96,6 @@ func TestService(t *testing.T) {
 	t.Run("update metadata", testServiceUpdateMetaOK)
 	t.Run("update metadata invalid request", testServiceUpdateMetaFailInvalidRequest)
 	t.Run("Signing transaction succeeds", testAcceptSigningTransactionSucceeds)
-	t.Run("using ask function in policy succeeds", testAskingConsentPolicySucceeds)
 	t.Run("Checking transaction succeeds", testCheckTransactionSucceeds)
 	t.Run("Checking transaction with rejected transaction succeeds", testCheckTransactionWithRejectedTransactionSucceeds)
 	t.Run("Checking transaction with failed transaction fails", testCheckTransactionWithFailedTransactionFails)
@@ -829,38 +824,6 @@ func testAcceptSigningTransactionSucceeds(t *testing.T) {
 	assert.Equal(t, http.StatusOK, statusCode)
 }
 
-func testAskingConsentPolicySucceeds(t *testing.T) {
-	txn := &v1.SubmitTransactionRequest{}
-
-	pendingConsents := make(chan service.ConsentRequest, 1)
-	sentTxs := make(chan service.SentTransaction, 1)
-	p := service.NewExplicitConsentPolicy(pendingConsents, sentTxs)
-
-	go func() {
-		req := <-pendingConsents
-		st, _ := req.String()
-		d := service.ConsentConfirmation{TxStr: st, Decision: false}
-		req.Confirmations <- d
-	}()
-
-	nowTime := time.Now()
-	answer, err := p.Ask(txn, "testTx", nowTime)
-	require.Nil(t, err)
-	require.False(t, answer)
-
-	p.Report(service.SentTransaction{
-		TxHash:     "txHash",
-		ReceivedAt: nowTime,
-		TxID:       "testTx",
-		Tx:         &commandspb.Transaction{},
-	})
-
-	sent := <-sentTxs
-	require.Equal(t, "txHash", sent.TxHash)
-	require.Equal(t, "testTx", sent.TxID)
-	require.Equal(t, nowTime, sent.ReceivedAt)
-}
-
 func testDeclineSigningTransactionManuallySucceeds(t *testing.T) {
 	s := getTestService(t, "manual")
 	defer s.ctrl.Finish()