code.vegaprotocol.io/vega@v0.79.0/wallet/api/admin_send_raw_transaction_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package api_test
    17  
    18  import (
    19  	"context"
    20  	"errors"
    21  	"fmt"
    22  	"testing"
    23  	"time"
    24  
    25  	"code.vegaprotocol.io/vega/libs/jsonrpc"
    26  	vgrand "code.vegaprotocol.io/vega/libs/rand"
    27  	apipb "code.vegaprotocol.io/vega/protos/vega/api/v1"
    28  	"code.vegaprotocol.io/vega/wallet/api"
    29  	"code.vegaprotocol.io/vega/wallet/api/mocks"
    30  	walletnode "code.vegaprotocol.io/vega/wallet/api/node"
    31  	nodemocks "code.vegaprotocol.io/vega/wallet/api/node/mocks"
    32  
    33  	"github.com/golang/mock/gomock"
    34  	"github.com/stretchr/testify/assert"
    35  )
    36  
    37  func TestAdminSendRawTransaction(t *testing.T) {
    38  	t.Run("Documentation matches the code", testAdminSendRawTransactionSchemaCorrect)
    39  	t.Run("Sending transaction with invalid params fails", testAdminSendingRawTransactionWithInvalidParamsFails)
    40  	t.Run("Sending transaction with valid params succeeds", testAdminSendingRawTransactionWithValidParamsSucceeds)
    41  	t.Run("Sending transaction with network that doesn't exist fails", testAdminSendingRawTransactionWithNetworkThatDoesntExistFails)
    42  	t.Run("Sending transaction with network that fails existence check fails", testAdminSendingRawTransactionWithNetworkThatFailsExistenceCheckFails)
    43  	t.Run("Sending transaction with failure to get network", testAdminSendingRawTransactionWithFailureToGetNetworkFails)
    44  	t.Run("Getting internal error during node selector building fails", testAdminSendingRawTransactionGettingInternalErrorDuringNodeSelectorBuildingFails)
    45  	t.Run("Sending transaction without healthy node fails", testAdminSendingRawTransactionWithoutHealthyNodeFails)
    46  	t.Run("Sending transaction with failed sending fails", testAdminSendingRawTransactionWithFailedSendingFails)
    47  }
    48  
    49  func testAdminSendRawTransactionSchemaCorrect(t *testing.T) {
    50  	assertEqualSchema(t, "admin.send_raw_transaction", api.AdminSendRawTransactionParams{}, api.AdminSendRawTransactionResult{})
    51  }
    52  
    53  func testAdminSendingRawTransactionWithInvalidParamsFails(t *testing.T) {
    54  	tcs := []struct {
    55  		name          string
    56  		params        interface{}
    57  		expectedError error
    58  	}{
    59  		{
    60  			name:          "with nil params",
    61  			params:        nil,
    62  			expectedError: api.ErrParamsRequired,
    63  		},
    64  		{
    65  			name:          "with wrong type of params",
    66  			params:        "test",
    67  			expectedError: api.ErrParamsDoNotMatch,
    68  		},
    69  		{
    70  			name: "with empty sending mode",
    71  			params: api.AdminSendRawTransactionParams{
    72  				Network:     "fairground",
    73  				SendingMode: "",
    74  			},
    75  			expectedError: api.ErrSendingModeIsRequired,
    76  		},
    77  		{
    78  			name: "with empty transaction",
    79  			params: api.AdminSendRawTransactionParams{
    80  				Network:            "fairground",
    81  				SendingMode:        "TYPE_SYNC",
    82  				EncodedTransaction: "",
    83  			},
    84  			expectedError: api.ErrEncodedTransactionIsRequired,
    85  		},
    86  		{
    87  			name: "with non-base64 transaction",
    88  			params: api.AdminSendRawTransactionParams{
    89  				Network:            "fairground",
    90  				SendingMode:        "TYPE_SYNC",
    91  				EncodedTransaction: "1234567890",
    92  			},
    93  			expectedError: api.ErrEncodedTransactionIsNotValidBase64String,
    94  		},
    95  		{
    96  			name: "with network and node address",
    97  			params: api.AdminSendRawTransactionParams{
    98  				Network:            "fairground",
    99  				NodeAddress:        "localhost:3002",
   100  				SendingMode:        "TYPE_SYNC",
   101  				EncodedTransaction: "Cip0ZXN0bmV0LWU5MGU2NwAI85ubpLO4mOnIARCEyogByrsBBwgCEgN7fQoSkwEKgAFlY2E4YjQ1MzNhNGNiZmFkY2VlMGNhYmZlNjdmMWRjZTAwN2RlODFlZjFlMTE3YTM4ZWVhMDJmYTNlMTcxMWM5NzI3YTQ3MmM3ZmNiNzU3ZDJmNTE4MTIxZTg2MzNiNjNlNTNmMWZjNjY0MTA1NjhmYjI5ODBmNDc4NjhiOTIwNRIMdmVnYS9lZDI1NTE5GAGAfQPCuwFGCkAxMjUzOGU0OTQ0ZjhjOWQ4MmU4MDNlNDE2YjM0MGQ2YmE0Mzk0NDIyZWQ1YWVmYmM2ZDYwNzYyZTcxMGFhNzk0ENLQAtI+QDNmZDQyZmQ1Y2ViMjJkOTlhYzQ1MDg2ZjFkODJkNTE2MTE4YTVjYjdhZDlhMmUwOTZjZDc4Y2EyYzg5NjBjODA=",
   102  			},
   103  			expectedError: api.ErrSpecifyingNetworkAndNodeAddressIsNotSupported,
   104  		},
   105  		{
   106  			name: "with network and node address missing",
   107  			params: api.AdminSendRawTransactionParams{
   108  				SendingMode:        "TYPE_SYNC",
   109  				EncodedTransaction: "Cip0ZXN0bmV0LWU5MGU2NwAI85ubpLO4mOnIARCEyogByrsBBwgCEgN7fQoSkwEKgAFlY2E4YjQ1MzNhNGNiZmFkY2VlMGNhYmZlNjdmMWRjZTAwN2RlODFlZjFlMTE3YTM4ZWVhMDJmYTNlMTcxMWM5NzI3YTQ3MmM3ZmNiNzU3ZDJmNTE4MTIxZTg2MzNiNjNlNTNmMWZjNjY0MTA1NjhmYjI5ODBmNDc4NjhiOTIwNRIMdmVnYS9lZDI1NTE5GAGAfQPCuwFGCkAxMjUzOGU0OTQ0ZjhjOWQ4MmU4MDNlNDE2YjM0MGQ2YmE0Mzk0NDIyZWQ1YWVmYmM2ZDYwNzYyZTcxMGFhNzk0ENLQAtI+QDNmZDQyZmQ1Y2ViMjJkOTlhYzQ1MDg2ZjFkODJkNTE2MTE4YTVjYjdhZDlhMmUwOTZjZDc4Y2EyYzg5NjBjODA=",
   110  			},
   111  			expectedError: api.ErrNetworkOrNodeAddressIsRequired,
   112  		},
   113  	}
   114  
   115  	for _, tc := range tcs {
   116  		t.Run(tc.name, func(tt *testing.T) {
   117  			// given
   118  			ctx := context.Background()
   119  
   120  			// setup
   121  			handler := newAdminSendRawTransactionHandler(tt, unexpectedNodeSelectorCall(tt))
   122  
   123  			// when
   124  			result, errorDetails := handler.handle(t, ctx, tc.params)
   125  
   126  			// then
   127  			assertInvalidParams(tt, errorDetails, tc.expectedError)
   128  			assert.Empty(tt, result)
   129  		})
   130  	}
   131  }
   132  
   133  func testAdminSendingRawTransactionWithValidParamsSucceeds(t *testing.T) {
   134  	// given
   135  	ctx := context.Background()
   136  	sendingMode := "TYPE_SYNC"
   137  	network := newNetwork(t)
   138  	txHash := vgrand.RandomStr(64)
   139  	nodeHost := vgrand.RandomStr(5)
   140  
   141  	// setup
   142  	handler := newAdminSendRawTransactionHandler(t, func(hosts []string, _ uint64, _ time.Duration) (walletnode.Selector, error) {
   143  		ctrl := gomock.NewController(t)
   144  		nodeSelector := nodemocks.NewMockSelector(ctrl)
   145  		node := nodemocks.NewMockNode(ctrl)
   146  		nodeSelector.EXPECT().Node(ctx, gomock.Any()).Times(1).Return(node, nil)
   147  		node.EXPECT().Host().Times(1).Return(nodeHost)
   148  		node.EXPECT().SendTransaction(ctx, gomock.Any(), apipb.SubmitTransactionRequest_TYPE_SYNC).Times(1).Return(txHash, nil)
   149  		return nodeSelector, nil
   150  	})
   151  
   152  	// -- expected calls
   153  	handler.networkStore.EXPECT().NetworkExists(network.Name).Times(1).Return(true, nil)
   154  	handler.networkStore.EXPECT().GetNetwork(network.Name).Times(1).Return(&network, nil)
   155  
   156  	// when
   157  	result, errorDetails := handler.handle(t, ctx, api.AdminSendRawTransactionParams{
   158  		Network:            network.Name,
   159  		SendingMode:        sendingMode,
   160  		EncodedTransaction: "Cip0ZXN0bmV0LWU5MGU2NwAI85ubpLO4mOnIARCEyogByrsBBwgCEgN7fQoSkwEKgAFlY2E4YjQ1MzNhNGNiZmFkY2VlMGNhYmZlNjdmMWRjZTAwN2RlODFlZjFlMTE3YTM4ZWVhMDJmYTNlMTcxMWM5NzI3YTQ3MmM3ZmNiNzU3ZDJmNTE4MTIxZTg2MzNiNjNlNTNmMWZjNjY0MTA1NjhmYjI5ODBmNDc4NjhiOTIwNRIMdmVnYS9lZDI1NTE5GAGAfQPCuwFGCkAxMjUzOGU0OTQ0ZjhjOWQ4MmU4MDNlNDE2YjM0MGQ2YmE0Mzk0NDIyZWQ1YWVmYmM2ZDYwNzYyZTcxMGFhNzk0ENLQAtI+QDNmZDQyZmQ1Y2ViMjJkOTlhYzQ1MDg2ZjFkODJkNTE2MTE4YTVjYjdhZDlhMmUwOTZjZDc4Y2EyYzg5NjBjODA=",
   161  	})
   162  
   163  	// then
   164  	assert.Nil(t, errorDetails)
   165  	assert.NotEmpty(t, result.Transaction)
   166  	assert.Equal(t, txHash, result.TransactionHash)
   167  	assert.NotEmpty(t, result.ReceivedAt)
   168  	assert.NotEmpty(t, result.SentAt)
   169  }
   170  
   171  func testAdminSendingRawTransactionWithNetworkThatDoesntExistFails(t *testing.T) {
   172  	// given
   173  	ctx := context.Background()
   174  
   175  	// setup
   176  	handler := newAdminSendRawTransactionHandler(t, unexpectedNodeSelectorCall(t))
   177  
   178  	// -- expected calls
   179  	handler.networkStore.EXPECT().NetworkExists(gomock.Any()).Times(1).Return(false, nil)
   180  
   181  	// when
   182  	result, errorDetails := handler.handle(t, ctx, api.AdminSendRawTransactionParams{
   183  		Network:            "fairground",
   184  		SendingMode:        "TYPE_SYNC",
   185  		EncodedTransaction: "Cip0ZXN0bmV0LWU5MGU2NwAI85ubpLO4mOnIARCEyogByrsBBwgCEgN7fQoSkwEKgAFlY2E4YjQ1MzNhNGNiZmFkY2VlMGNhYmZlNjdmMWRjZTAwN2RlODFlZjFlMTE3YTM4ZWVhMDJmYTNlMTcxMWM5NzI3YTQ3MmM3ZmNiNzU3ZDJmNTE4MTIxZTg2MzNiNjNlNTNmMWZjNjY0MTA1NjhmYjI5ODBmNDc4NjhiOTIwNRIMdmVnYS9lZDI1NTE5GAGAfQPCuwFGCkAxMjUzOGU0OTQ0ZjhjOWQ4MmU4MDNlNDE2YjM0MGQ2YmE0Mzk0NDIyZWQ1YWVmYmM2ZDYwNzYyZTcxMGFhNzk0ENLQAtI+QDNmZDQyZmQ1Y2ViMjJkOTlhYzQ1MDg2ZjFkODJkNTE2MTE4YTVjYjdhZDlhMmUwOTZjZDc4Y2EyYzg5NjBjODA=",
   186  	})
   187  
   188  	// then
   189  	assertInvalidParams(t, errorDetails, api.ErrNetworkDoesNotExist)
   190  	assert.Empty(t, result)
   191  }
   192  
   193  func testAdminSendingRawTransactionWithNetworkThatFailsExistenceCheckFails(t *testing.T) {
   194  	// given
   195  	ctx := context.Background()
   196  
   197  	// setup
   198  	handler := newAdminSendRawTransactionHandler(t, unexpectedNodeSelectorCall(t))
   199  
   200  	// -- expected calls
   201  	handler.networkStore.EXPECT().NetworkExists(gomock.Any()).Times(1).Return(false, assert.AnError)
   202  
   203  	// when
   204  	result, errorDetails := handler.handle(t, ctx, api.AdminSendRawTransactionParams{
   205  		Network:            "fairground",
   206  		SendingMode:        "TYPE_SYNC",
   207  		EncodedTransaction: "Cip0ZXN0bmV0LWU5MGU2NwAI85ubpLO4mOnIARCEyogByrsBBwgCEgN7fQoSkwEKgAFlY2E4YjQ1MzNhNGNiZmFkY2VlMGNhYmZlNjdmMWRjZTAwN2RlODFlZjFlMTE3YTM4ZWVhMDJmYTNlMTcxMWM5NzI3YTQ3MmM3ZmNiNzU3ZDJmNTE4MTIxZTg2MzNiNjNlNTNmMWZjNjY0MTA1NjhmYjI5ODBmNDc4NjhiOTIwNRIMdmVnYS9lZDI1NTE5GAGAfQPCuwFGCkAxMjUzOGU0OTQ0ZjhjOWQ4MmU4MDNlNDE2YjM0MGQ2YmE0Mzk0NDIyZWQ1YWVmYmM2ZDYwNzYyZTcxMGFhNzk0ENLQAtI+QDNmZDQyZmQ1Y2ViMjJkOTlhYzQ1MDg2ZjFkODJkNTE2MTE4YTVjYjdhZDlhMmUwOTZjZDc4Y2EyYzg5NjBjODA=",
   208  	})
   209  
   210  	// then
   211  	assertInternalError(t, errorDetails, fmt.Errorf("could not determine if the network exists: %w", assert.AnError))
   212  	assert.Empty(t, result)
   213  }
   214  
   215  func testAdminSendingRawTransactionWithFailureToGetNetworkFails(t *testing.T) {
   216  	// given
   217  	ctx := context.Background()
   218  	network := "fairground"
   219  
   220  	// setup
   221  	handler := newAdminSendRawTransactionHandler(t, unexpectedNodeSelectorCall(t))
   222  
   223  	// -- expected calls
   224  	handler.networkStore.EXPECT().NetworkExists(network).Times(1).Return(true, nil)
   225  	handler.networkStore.EXPECT().GetNetwork(network).Times(1).Return(nil, assert.AnError)
   226  
   227  	// when
   228  	result, errorDetails := handler.handle(t, ctx, api.AdminSendRawTransactionParams{
   229  		Network:            network,
   230  		SendingMode:        "TYPE_SYNC",
   231  		EncodedTransaction: "Cip0ZXN0bmV0LWU5MGU2NwAI85ubpLO4mOnIARCEyogByrsBBwgCEgN7fQoSkwEKgAFlY2E4YjQ1MzNhNGNiZmFkY2VlMGNhYmZlNjdmMWRjZTAwN2RlODFlZjFlMTE3YTM4ZWVhMDJmYTNlMTcxMWM5NzI3YTQ3MmM3ZmNiNzU3ZDJmNTE4MTIxZTg2MzNiNjNlNTNmMWZjNjY0MTA1NjhmYjI5ODBmNDc4NjhiOTIwNRIMdmVnYS9lZDI1NTE5GAGAfQPCuwFGCkAxMjUzOGU0OTQ0ZjhjOWQ4MmU4MDNlNDE2YjM0MGQ2YmE0Mzk0NDIyZWQ1YWVmYmM2ZDYwNzYyZTcxMGFhNzk0ENLQAtI+QDNmZDQyZmQ1Y2ViMjJkOTlhYzQ1MDg2ZjFkODJkNTE2MTE4YTVjYjdhZDlhMmUwOTZjZDc4Y2EyYzg5NjBjODA=",
   232  	})
   233  
   234  	// then
   235  	assertInternalError(t, errorDetails, fmt.Errorf("could not retrieve the network configuration: %w", assert.AnError))
   236  	assert.Empty(t, result)
   237  }
   238  
   239  func testAdminSendingRawTransactionGettingInternalErrorDuringNodeSelectorBuildingFails(t *testing.T) {
   240  	// given
   241  	ctx := context.Background()
   242  	network := newNetwork(t)
   243  
   244  	// setup
   245  	handler := newAdminSendRawTransactionHandler(t, func(hosts []string, _ uint64, _ time.Duration) (walletnode.Selector, error) {
   246  		return nil, assert.AnError
   247  	})
   248  
   249  	// -- expected calls
   250  	handler.networkStore.EXPECT().NetworkExists(network.Name).Times(1).Return(true, nil)
   251  	handler.networkStore.EXPECT().GetNetwork(network.Name).Times(1).Return(&network, nil)
   252  
   253  	// when
   254  	result, errorDetails := handler.handle(t, ctx, api.AdminSendRawTransactionParams{
   255  		Network:            network.Name,
   256  		SendingMode:        "TYPE_SYNC",
   257  		EncodedTransaction: "Cip0ZXN0bmV0LWU5MGU2NwAI85ubpLO4mOnIARCEyogByrsBBwgCEgN7fQoSkwEKgAFlY2E4YjQ1MzNhNGNiZmFkY2VlMGNhYmZlNjdmMWRjZTAwN2RlODFlZjFlMTE3YTM4ZWVhMDJmYTNlMTcxMWM5NzI3YTQ3MmM3ZmNiNzU3ZDJmNTE4MTIxZTg2MzNiNjNlNTNmMWZjNjY0MTA1NjhmYjI5ODBmNDc4NjhiOTIwNRIMdmVnYS9lZDI1NTE5GAGAfQPCuwFGCkAxMjUzOGU0OTQ0ZjhjOWQ4MmU4MDNlNDE2YjM0MGQ2YmE0Mzk0NDIyZWQ1YWVmYmM2ZDYwNzYyZTcxMGFhNzk0ENLQAtI+QDNmZDQyZmQ1Y2ViMjJkOTlhYzQ1MDg2ZjFkODJkNTE2MTE4YTVjYjdhZDlhMmUwOTZjZDc4Y2EyYzg5NjBjODA=",
   258  	})
   259  
   260  	// then
   261  	assertInternalError(t, errorDetails, fmt.Errorf("could not initialize the node selector: %w", assert.AnError))
   262  	assert.Empty(t, result)
   263  }
   264  
   265  func testAdminSendingRawTransactionWithoutHealthyNodeFails(t *testing.T) {
   266  	// given
   267  	ctx := context.Background()
   268  	network := newNetwork(t)
   269  
   270  	// setup
   271  	handler := newAdminSendRawTransactionHandler(t, func(hosts []string, _ uint64, _ time.Duration) (walletnode.Selector, error) {
   272  		ctrl := gomock.NewController(t)
   273  		nodeSelector := nodemocks.NewMockSelector(ctrl)
   274  		nodeSelector.EXPECT().Node(ctx, gomock.Any()).Times(1).Return(nil, assert.AnError)
   275  		return nodeSelector, nil
   276  	})
   277  
   278  	// -- expected calls
   279  	handler.networkStore.EXPECT().NetworkExists(network.Name).Times(1).Return(true, nil)
   280  	handler.networkStore.EXPECT().GetNetwork(network.Name).Times(1).Return(&network, nil)
   281  
   282  	// when
   283  	result, errorDetails := handler.handle(t, ctx, api.AdminSendRawTransactionParams{
   284  		Network:            network.Name,
   285  		SendingMode:        "TYPE_SYNC",
   286  		EncodedTransaction: "Cip0ZXN0bmV0LWU5MGU2NwAI85ubpLO4mOnIARCEyogByrsBBwgCEgN7fQoSkwEKgAFlY2E4YjQ1MzNhNGNiZmFkY2VlMGNhYmZlNjdmMWRjZTAwN2RlODFlZjFlMTE3YTM4ZWVhMDJmYTNlMTcxMWM5NzI3YTQ3MmM3ZmNiNzU3ZDJmNTE4MTIxZTg2MzNiNjNlNTNmMWZjNjY0MTA1NjhmYjI5ODBmNDc4NjhiOTIwNRIMdmVnYS9lZDI1NTE5GAGAfQPCuwFGCkAxMjUzOGU0OTQ0ZjhjOWQ4MmU4MDNlNDE2YjM0MGQ2YmE0Mzk0NDIyZWQ1YWVmYmM2ZDYwNzYyZTcxMGFhNzk0ENLQAtI+QDNmZDQyZmQ1Y2ViMjJkOTlhYzQ1MDg2ZjFkODJkNTE2MTE4YTVjYjdhZDlhMmUwOTZjZDc4Y2EyYzg5NjBjODA=",
   287  	})
   288  
   289  	// then
   290  	assertNetworkError(t, errorDetails, api.ErrNoHealthyNodeAvailable)
   291  	assert.Empty(t, result)
   292  }
   293  
   294  func testAdminSendingRawTransactionWithFailedSendingFails(t *testing.T) {
   295  	// given
   296  	ctx := context.Background()
   297  	sendingMode := "TYPE_SYNC"
   298  	network := newNetwork(t)
   299  
   300  	// setup
   301  	handler := newAdminSendRawTransactionHandler(t, func(hosts []string, _ uint64, _ time.Duration) (walletnode.Selector, error) {
   302  		ctrl := gomock.NewController(t)
   303  		nodeSelector := nodemocks.NewMockSelector(ctrl)
   304  		node := nodemocks.NewMockNode(ctrl)
   305  		nodeSelector.EXPECT().Node(ctx, gomock.Any()).Times(1).Return(node, nil)
   306  		node.EXPECT().SendTransaction(ctx, gomock.Any(), apipb.SubmitTransactionRequest_TYPE_SYNC).Times(1).Return("", assert.AnError)
   307  		return nodeSelector, nil
   308  	})
   309  
   310  	// -- expected calls
   311  	handler.networkStore.EXPECT().NetworkExists(network.Name).Times(1).Return(true, nil)
   312  	handler.networkStore.EXPECT().GetNetwork(network.Name).Times(1).Return(&network, nil)
   313  
   314  	// when
   315  	result, errorDetails := handler.handle(t, ctx, api.AdminSendRawTransactionParams{
   316  		Network:            network.Name,
   317  		SendingMode:        sendingMode,
   318  		EncodedTransaction: "Cip0ZXN0bmV0LWU5MGU2NwAI85ubpLO4mOnIARCEyogByrsBBwgCEgN7fQoSkwEKgAFlY2E4YjQ1MzNhNGNiZmFkY2VlMGNhYmZlNjdmMWRjZTAwN2RlODFlZjFlMTE3YTM4ZWVhMDJmYTNlMTcxMWM5NzI3YTQ3MmM3ZmNiNzU3ZDJmNTE4MTIxZTg2MzNiNjNlNTNmMWZjNjY0MTA1NjhmYjI5ODBmNDc4NjhiOTIwNRIMdmVnYS9lZDI1NTE5GAGAfQPCuwFGCkAxMjUzOGU0OTQ0ZjhjOWQ4MmU4MDNlNDE2YjM0MGQ2YmE0Mzk0NDIyZWQ1YWVmYmM2ZDYwNzYyZTcxMGFhNzk0ENLQAtI+QDNmZDQyZmQ1Y2ViMjJkOTlhYzQ1MDg2ZjFkODJkNTE2MTE4YTVjYjdhZDlhMmUwOTZjZDc4Y2EyYzg5NjBjODA=",
   319  	})
   320  
   321  	// then
   322  	assertNetworkError(t, errorDetails, errors.New("the transaction failed: assert.AnError general error for testing"))
   323  	assert.Empty(t, result)
   324  }
   325  
   326  type adminSendRawTransactionHandler struct {
   327  	*api.AdminSendRawTransaction
   328  	ctrl         *gomock.Controller
   329  	networkStore *mocks.MockNetworkStore
   330  }
   331  
   332  func (h *adminSendRawTransactionHandler) handle(t *testing.T, ctx context.Context, params jsonrpc.Params) (api.AdminSendRawTransactionResult, *jsonrpc.ErrorDetails) {
   333  	t.Helper()
   334  
   335  	rawResult, err := h.Handle(ctx, params)
   336  	if rawResult != nil {
   337  		result, ok := rawResult.(api.AdminSendRawTransactionResult)
   338  		if !ok {
   339  			t.Fatal("AdminUpdatePermissions handler result is not a AdminSignTransactionResult")
   340  		}
   341  		return result, err
   342  	}
   343  	return api.AdminSendRawTransactionResult{}, err
   344  }
   345  
   346  func newAdminSendRawTransactionHandler(t *testing.T, selectorBuilder api.NodeSelectorBuilder) *adminSendRawTransactionHandler {
   347  	t.Helper()
   348  
   349  	ctrl := gomock.NewController(t)
   350  	networkStore := mocks.NewMockNetworkStore(ctrl)
   351  
   352  	return &adminSendRawTransactionHandler{
   353  		AdminSendRawTransaction: api.NewAdminSendRawTransaction(networkStore, selectorBuilder),
   354  		ctrl:                    ctrl,
   355  		networkStore:            networkStore,
   356  	}
   357  }