github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/transaction_unit_test.go (about)

     1  //go:build all || unit
     2  // +build all unit
     3  
     4  package hedera
     5  
     6  /*-
     7   *
     8   * Hedera Go SDK
     9   *
    10   * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC
    11   *
    12   * Licensed under the Apache License, Version 2.0 (the "License");
    13   * you may not use this file except in compliance with the License.
    14   * You may obtain a copy of the License at
    15   *
    16   *      http://www.apache.org/licenses/LICENSE-2.0
    17   *
    18   * Unless required by applicable law or agreed to in writing, software
    19   * distributed under the License is distributed on an "AS IS" BASIS,
    20   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    21   * See the License for the specific language governing permissions and
    22   * limitations under the License.
    23   *
    24   */
    25  
    26  import (
    27  	"fmt"
    28  	"reflect"
    29  	"testing"
    30  	"time"
    31  
    32  	"github.com/hashgraph/hedera-protobufs-go/sdk"
    33  	"github.com/hashgraph/hedera-protobufs-go/services"
    34  	protobuf "google.golang.org/protobuf/proto"
    35  
    36  	"github.com/stretchr/testify/assert"
    37  
    38  	"github.com/stretchr/testify/require"
    39  )
    40  
    41  func TestUnitTransactionSerializationDeserialization(t *testing.T) {
    42  	t.Parallel()
    43  
    44  	transaction, err := _NewMockTransaction()
    45  	require.NoError(t, err)
    46  
    47  	_, err = transaction.Freeze()
    48  	require.NoError(t, err)
    49  
    50  	_, err = transaction.GetSignatures()
    51  	require.NoError(t, err)
    52  
    53  	_, err = transaction.GetTransactionHash()
    54  	require.NoError(t, err)
    55  
    56  	transaction.
    57  		SetTransactionMemo("memo").
    58  		SetMaxTransactionFee(NewHbar(5))
    59  
    60  	txBytes, err := transaction.ToBytes()
    61  	require.NoError(t, err)
    62  
    63  	deserializedTX, err := TransactionFromBytes(txBytes)
    64  	require.NoError(t, err)
    65  
    66  	var deserializedTXTyped TransferTransaction
    67  	switch tx := deserializedTX.(type) {
    68  	case TransferTransaction:
    69  		deserializedTXTyped = tx
    70  	default:
    71  		panic("Transaction was not TransferTransaction")
    72  	}
    73  
    74  	require.Equal(t, "memo", deserializedTXTyped.memo)
    75  	require.Equal(t, NewHbar(5), deserializedTXTyped.GetMaxTransactionFee())
    76  	assert.Equal(t, transaction.String(), deserializedTXTyped.String())
    77  }
    78  
    79  func TestUnitTransactionValidateBodiesEqual(t *testing.T) {
    80  	t.Parallel()
    81  
    82  	key, err := PrivateKeyFromString(mockPrivateKey)
    83  	require.NoError(t, err)
    84  	transaction := services.TransactionBody{
    85  		TransactionID:            testTransactionID._ToProtobuf(),
    86  		NodeAccountID:            AccountID{Account: 3}._ToProtobuf(),
    87  		TransactionFee:           0,
    88  		TransactionValidDuration: nil,
    89  		GenerateRecord:           false,
    90  		Memo:                     "",
    91  		Data: &services.TransactionBody_CryptoCreateAccount{
    92  			CryptoCreateAccount: &services.CryptoCreateTransactionBody{
    93  				Key:                           key._ToProtoKey(),
    94  				InitialBalance:                0,
    95  				ProxyAccountID:                AccountID{Account: 123}._ToProtobuf(),
    96  				SendRecordThreshold:           0,
    97  				ReceiveRecordThreshold:        0,
    98  				ReceiverSigRequired:           false,
    99  				AutoRenewPeriod:               nil,
   100  				ShardID:                       nil,
   101  				RealmID:                       nil,
   102  				NewRealmAdminKey:              nil,
   103  				Memo:                          "",
   104  				MaxAutomaticTokenAssociations: 0,
   105  			},
   106  		},
   107  	}
   108  
   109  	transactionBody, err := protobuf.Marshal(&transaction)
   110  	require.NoError(t, err)
   111  
   112  	signed, err := protobuf.Marshal(&services.SignedTransaction{
   113  		BodyBytes: transactionBody,
   114  	})
   115  	require.NoError(t, err)
   116  	list, err := protobuf.Marshal(&sdk.TransactionList{
   117  		TransactionList: []*services.Transaction{
   118  			{
   119  				SignedTransactionBytes: signed,
   120  			},
   121  			{
   122  				SignedTransactionBytes: signed,
   123  			},
   124  			{
   125  				SignedTransactionBytes: signed,
   126  			},
   127  		},
   128  	})
   129  
   130  	deserializedTX, err := TransactionFromBytes(list)
   131  	require.NoError(t, err)
   132  
   133  	var deserializedTXTyped AccountCreateTransaction
   134  	switch tx := deserializedTX.(type) {
   135  	case AccountCreateTransaction:
   136  		deserializedTXTyped = tx
   137  	default:
   138  		panic("Transaction was not AccountCreateTransaction")
   139  	}
   140  
   141  	assert.Equal(t, uint64(transaction.TransactionID.AccountID.GetAccountNum()), deserializedTXTyped.GetTransactionID().AccountID.Account)
   142  }
   143  
   144  func DisabledTestUnitTransactionValidateBodiesNotEqual(t *testing.T) {
   145  	t.Parallel()
   146  
   147  	key, err := PrivateKeyFromString(mockPrivateKey)
   148  	require.NoError(t, err)
   149  	transaction := services.TransactionBody{
   150  		TransactionID:            testTransactionID._ToProtobuf(),
   151  		NodeAccountID:            AccountID{Account: 3}._ToProtobuf(),
   152  		TransactionFee:           0,
   153  		TransactionValidDuration: nil,
   154  		GenerateRecord:           false,
   155  		Memo:                     "",
   156  		Data: &services.TransactionBody_CryptoCreateAccount{
   157  			CryptoCreateAccount: &services.CryptoCreateTransactionBody{
   158  				Key:                           key._ToProtoKey(),
   159  				InitialBalance:                0,
   160  				ProxyAccountID:                AccountID{Account: 123}._ToProtobuf(),
   161  				SendRecordThreshold:           0,
   162  				ReceiveRecordThreshold:        0,
   163  				ReceiverSigRequired:           false,
   164  				AutoRenewPeriod:               nil,
   165  				ShardID:                       nil,
   166  				RealmID:                       nil,
   167  				NewRealmAdminKey:              nil,
   168  				Memo:                          "",
   169  				MaxAutomaticTokenAssociations: 0,
   170  			},
   171  		},
   172  	}
   173  
   174  	transaction2 := services.TransactionBody{
   175  		TransactionID:            testTransactionID._ToProtobuf(),
   176  		NodeAccountID:            AccountID{Account: 3}._ToProtobuf(),
   177  		TransactionFee:           0,
   178  		TransactionValidDuration: nil,
   179  		GenerateRecord:           false,
   180  		Memo:                     "",
   181  		Data: &services.TransactionBody_CryptoCreateAccount{
   182  			CryptoCreateAccount: &services.CryptoCreateTransactionBody{
   183  				Key:                           key._ToProtoKey(),
   184  				InitialBalance:                0,
   185  				ProxyAccountID:                AccountID{Account: 1}._ToProtobuf(),
   186  				SendRecordThreshold:           0,
   187  				ReceiveRecordThreshold:        0,
   188  				ReceiverSigRequired:           false,
   189  				AutoRenewPeriod:               nil,
   190  				ShardID:                       nil,
   191  				RealmID:                       nil,
   192  				NewRealmAdminKey:              nil,
   193  				Memo:                          "",
   194  				MaxAutomaticTokenAssociations: 0,
   195  			},
   196  		},
   197  	}
   198  
   199  	transactionBody, err := protobuf.Marshal(&transaction)
   200  	require.NoError(t, err)
   201  
   202  	signed, err := protobuf.Marshal(&services.SignedTransaction{
   203  		BodyBytes: transactionBody,
   204  	})
   205  
   206  	transactionBody2, err := protobuf.Marshal(&transaction2)
   207  	require.NoError(t, err)
   208  
   209  	signed2, err := protobuf.Marshal(&services.SignedTransaction{
   210  		BodyBytes: transactionBody2,
   211  	})
   212  
   213  	require.NoError(t, err)
   214  	list, err := protobuf.Marshal(&sdk.TransactionList{
   215  		TransactionList: []*services.Transaction{
   216  			{
   217  				SignedTransactionBytes: signed,
   218  			},
   219  			{
   220  				SignedTransactionBytes: signed2,
   221  			},
   222  			{
   223  				SignedTransactionBytes: signed2,
   224  			},
   225  		},
   226  	})
   227  
   228  	_, err = TransactionFromBytes(list)
   229  	require.Error(t, err)
   230  	if err != nil {
   231  		assert.Equal(t, fmt.Sprintf("failed to validate transaction bodies"), err.Error())
   232  	}
   233  }
   234  
   235  func TestUnitTransactionToFromBytes(t *testing.T) {
   236  	t.Parallel()
   237  
   238  	duration := time.Second * 10
   239  	operatorID := AccountID{Account: 5}
   240  	recepientID := AccountID{Account: 4}
   241  	node := []AccountID{{Account: 3}}
   242  	transaction, err := NewTransferTransaction().
   243  		SetTransactionID(testTransactionID).
   244  		SetNodeAccountIDs(node).
   245  		AddHbarTransfer(operatorID, NewHbar(-1)).
   246  		AddHbarTransfer(recepientID, NewHbar(1)).
   247  		SetTransactionMemo("go sdk example multi_app_transfer/main.go").
   248  		SetTransactionValidDuration(duration).
   249  		Freeze()
   250  	require.NoError(t, err)
   251  
   252  	_ = transaction.GetTransactionID()
   253  	nodeID := transaction.GetNodeAccountIDs()
   254  	require.NotEmpty(t, nodeID)
   255  	require.False(t, nodeID[0]._IsZero())
   256  
   257  	var tx services.TransactionBody
   258  	_ = protobuf.Unmarshal(transaction.signedTransactions._Get(0).(*services.SignedTransaction).BodyBytes, &tx)
   259  	require.Equal(t, tx.TransactionID.String(), testTransactionID._ToProtobuf().String())
   260  	require.Equal(t, tx.NodeAccountID.String(), node[0]._ToProtobuf().String())
   261  	require.Equal(t, tx.Memo, "go sdk example multi_app_transfer/main.go")
   262  	require.Equal(t, duration, _DurationFromProtobuf(tx.TransactionValidDuration))
   263  	require.Equal(t, tx.GetCryptoTransfer().Transfers.AccountAmounts,
   264  		[]*services.AccountAmount{
   265  			{
   266  				AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{5}},
   267  				Amount:    -100000000,
   268  			},
   269  			{
   270  				AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{4}},
   271  				Amount:    100000000,
   272  			},
   273  		})
   274  
   275  	txBytes, err := transaction.ToBytes()
   276  	require.NoError(t, err)
   277  
   278  	newTransaction, err := TransactionFromBytes(txBytes)
   279  
   280  	_ = protobuf.Unmarshal(newTransaction.(TransferTransaction).signedTransactions._Get(0).(*services.SignedTransaction).BodyBytes, &tx)
   281  	require.Equal(t, tx.TransactionID.String(), testTransactionID._ToProtobuf().String())
   282  	require.Equal(t, tx.NodeAccountID.String(), node[0]._ToProtobuf().String())
   283  	require.Equal(t, tx.Memo, "go sdk example multi_app_transfer/main.go")
   284  	require.Equal(t, duration, _DurationFromProtobuf(tx.TransactionValidDuration))
   285  	require.Equal(t, tx.GetCryptoTransfer().Transfers.AccountAmounts,
   286  		[]*services.AccountAmount{
   287  			{
   288  				AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{5}},
   289  				Amount:    -100000000,
   290  			},
   291  			{
   292  				AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{4}},
   293  				Amount:    100000000,
   294  			},
   295  		})
   296  }
   297  
   298  func TestUnitTransactionToFromBytesWithClient(t *testing.T) {
   299  	t.Parallel()
   300  
   301  	duration := time.Second * 10
   302  	operatorID := AccountID{Account: 5}
   303  	recepientID := AccountID{Account: 4}
   304  	client, err := _NewMockClient()
   305  	client.SetLedgerID(*NewLedgerIDTestnet())
   306  	require.NoError(t, err)
   307  	privateKey, err := PrivateKeyFromString(mockPrivateKey)
   308  	client.SetOperator(AccountID{Account: 2}, privateKey)
   309  
   310  	transaction, err := NewTransferTransaction().
   311  		AddHbarTransfer(operatorID, NewHbar(-1)).
   312  		AddHbarTransfer(recepientID, NewHbar(1)).
   313  		SetTransactionMemo("go sdk example multi_app_transfer/main.go").
   314  		SetTransactionValidDuration(duration).
   315  		FreezeWith(client)
   316  	require.NoError(t, err)
   317  
   318  	var tx services.TransactionBody
   319  	_ = protobuf.Unmarshal(transaction.signedTransactions._Get(0).(*services.SignedTransaction).BodyBytes, &tx)
   320  	require.NotNil(t, tx.TransactionID, tx.NodeAccountID)
   321  	require.Equal(t, tx.Memo, "go sdk example multi_app_transfer/main.go")
   322  	require.Equal(t, duration, _DurationFromProtobuf(tx.TransactionValidDuration))
   323  	require.Equal(t, tx.GetCryptoTransfer().Transfers.AccountAmounts,
   324  		[]*services.AccountAmount{
   325  			{
   326  				AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{5}},
   327  				Amount:    -100000000,
   328  			},
   329  			{
   330  				AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{4}},
   331  				Amount:    100000000,
   332  			},
   333  		})
   334  
   335  	initialTxID := tx.TransactionID
   336  	initialNode := tx.NodeAccountID
   337  
   338  	txBytes, err := transaction.ToBytes()
   339  	require.NoError(t, err)
   340  
   341  	newTransaction, err := TransactionFromBytes(txBytes)
   342  
   343  	_ = protobuf.Unmarshal(newTransaction.(TransferTransaction).signedTransactions._Get(0).(*services.SignedTransaction).BodyBytes, &tx)
   344  	require.NotNil(t, tx.TransactionID, tx.NodeAccountID)
   345  	require.Equal(t, tx.TransactionID.String(), initialTxID.String())
   346  	require.Equal(t, tx.NodeAccountID.String(), initialNode.String())
   347  	require.Equal(t, tx.Memo, "go sdk example multi_app_transfer/main.go")
   348  	require.Equal(t, duration, _DurationFromProtobuf(tx.TransactionValidDuration))
   349  	require.Equal(t, tx.GetCryptoTransfer().Transfers.AccountAmounts,
   350  		[]*services.AccountAmount{
   351  			{
   352  				AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{5}},
   353  				Amount:    -100000000,
   354  			},
   355  			{
   356  				AccountID: &services.AccountID{Account: &services.AccountID_AccountNum{4}},
   357  				Amount:    100000000,
   358  			},
   359  		})
   360  }
   361  
   362  func TestUnitQueryRegression(t *testing.T) {
   363  	t.Parallel()
   364  
   365  	accountID := AccountID{Account: 5}
   366  	node := []AccountID{{Account: 3}}
   367  	client, err := _NewMockClient()
   368  	client.SetLedgerID(*NewLedgerIDTestnet())
   369  	require.NoError(t, err)
   370  	privateKey, err := PrivateKeyFromString(mockPrivateKey)
   371  	client.SetOperator(AccountID{Account: 2}, privateKey)
   372  
   373  	query := NewAccountInfoQuery().
   374  		SetAccountID(accountID).
   375  		SetNodeAccountIDs(node).
   376  		SetPaymentTransactionID(testTransactionID).
   377  		SetMaxQueryPayment(NewHbar(1)).
   378  		SetQueryPayment(HbarFromTinybar(25))
   379  
   380  	body := query.buildQuery()
   381  	_, err = query.generatePayments(client, HbarFromTinybar(20))
   382  	require.NoError(t, err)
   383  
   384  	var paymentTx services.TransactionBody
   385  	_ = protobuf.Unmarshal(query.Query.paymentTransactions[0].BodyBytes, &paymentTx)
   386  
   387  	require.Equal(t, body.GetCryptoGetInfo().AccountID.String(), accountID._ToProtobuf().String())
   388  	require.Equal(t, paymentTx.NodeAccountID.String(), node[0]._ToProtobuf().String())
   389  	require.Equal(t, paymentTx.TransactionFee, uint64(NewHbar(1).tinybar))
   390  	require.Equal(t, paymentTx.TransactionValidDuration, &services.Duration{Seconds: 120})
   391  	require.Equal(t, paymentTx.Data, &services.TransactionBody_CryptoTransfer{
   392  		CryptoTransfer: &services.CryptoTransferTransactionBody{
   393  			Transfers: &services.TransferList{
   394  				AccountAmounts: []*services.AccountAmount{
   395  					{
   396  						AccountID: node[0]._ToProtobuf(),
   397  						Amount:    HbarFromTinybar(20).AsTinybar(),
   398  					},
   399  					{
   400  						AccountID: client.GetOperatorAccountID()._ToProtobuf(),
   401  						Amount:    -HbarFromTinybar(20).AsTinybar(),
   402  					},
   403  				},
   404  			},
   405  		},
   406  	})
   407  }
   408  func TestUnitTransactionInitFeeMaxTransactionWithouthSettingFee(t *testing.T) {
   409  	t.Parallel()
   410  
   411  	//Default Max Fee for TransferTransaction
   412  	fee := NewHbar(1)
   413  	client, err := _NewMockClient()
   414  	client.SetLedgerID(*NewLedgerIDTestnet())
   415  	require.NoError(t, err)
   416  	transaction, err := NewTransferTransaction().
   417  		AddHbarTransfer(AccountID{Account: 2}, HbarFromTinybar(-100)).
   418  		AddHbarTransfer(AccountID{Account: 3}, HbarFromTinybar(100)).
   419  		FreezeWith(client)
   420  	require.NoError(t, err)
   421  	require.Equal(t, uint64(fee.AsTinybar()), transaction.transactionFee)
   422  }
   423  
   424  func TestUnitTransactionInitFeeMaxTransactionFeeSetExplicitly(t *testing.T) {
   425  	t.Parallel()
   426  
   427  	clientMaxFee := NewHbar(14)
   428  	explicitMaxFee := NewHbar(15)
   429  	client, err := _NewMockClient()
   430  	client.SetLedgerID(*NewLedgerIDTestnet())
   431  	client.SetDefaultMaxTransactionFee(clientMaxFee)
   432  	require.NoError(t, err)
   433  	transaction, err := NewTransferTransaction().
   434  		AddHbarTransfer(AccountID{Account: 2}, HbarFromTinybar(-100)).
   435  		AddHbarTransfer(AccountID{Account: 3}, HbarFromTinybar(100)).
   436  		SetMaxTransactionFee(explicitMaxFee).
   437  		FreezeWith(client)
   438  	require.NoError(t, err)
   439  	require.Equal(t, uint64(explicitMaxFee.AsTinybar()), transaction.transactionFee)
   440  }
   441  
   442  func TestUnitTransactionInitFeeMaxTransactionFromClientDefault(t *testing.T) {
   443  	t.Parallel()
   444  
   445  	fee := NewHbar(14)
   446  	client, err := _NewMockClient()
   447  	client.SetLedgerID(*NewLedgerIDTestnet())
   448  	client.SetDefaultMaxTransactionFee(fee)
   449  	require.NoError(t, err)
   450  	transaction, err := NewTransferTransaction().
   451  		AddHbarTransfer(AccountID{Account: 2}, HbarFromTinybar(-100)).
   452  		AddHbarTransfer(AccountID{Account: 3}, HbarFromTinybar(100)).
   453  		FreezeWith(client)
   454  	require.NoError(t, err)
   455  	require.Equal(t, uint64(fee.AsTinybar()), transaction.transactionFee)
   456  }
   457  
   458  func TestUnitTransactionSignSwitchCases(t *testing.T) {
   459  	t.Parallel()
   460  
   461  	newKey, client, nodeAccountId := signSwitchCaseaSetup(t)
   462  
   463  	txs := []Executable{
   464  		NewAccountCreateTransaction(),
   465  		NewAccountDeleteTransaction(),
   466  		NewAccountUpdateTransaction(),
   467  		NewAccountAllowanceApproveTransaction(),
   468  		NewAccountAllowanceDeleteTransaction(),
   469  		NewFileCreateTransaction(),
   470  		NewFileDeleteTransaction(),
   471  		NewFileUpdateTransaction(),
   472  		NewLiveHashAddTransaction(),
   473  		NewLiveHashDeleteTransaction(),
   474  		NewTokenAssociateTransaction(),
   475  		NewTokenBurnTransaction(),
   476  		NewTokenCreateTransaction(),
   477  		NewTokenDeleteTransaction(),
   478  		NewTokenDissociateTransaction(),
   479  		NewTokenFeeScheduleUpdateTransaction(),
   480  		NewTokenFreezeTransaction(),
   481  		NewTokenGrantKycTransaction(),
   482  		NewTokenMintTransaction(),
   483  		NewTokenRevokeKycTransaction(),
   484  		NewTokenUnfreezeTransaction(),
   485  		NewTokenUpdateTransaction(),
   486  		NewTokenWipeTransaction(),
   487  		NewTopicCreateTransaction(),
   488  		NewTopicDeleteTransaction(),
   489  		NewTopicUpdateTransaction(),
   490  		NewTransferTransaction(),
   491  	}
   492  
   493  	for _, tx := range txs {
   494  
   495  		txVal, signature, transferTxBytes := signSwitchCaseaHelper(t, tx, newKey, client)
   496  
   497  		signTests := signTestsForTransaction(txVal, newKey, signature, client)
   498  
   499  		for _, tt := range signTests {
   500  			t.Run(tt.name, func(t *testing.T) {
   501  				transactionInterface, err := TransactionFromBytes(transferTxBytes)
   502  				require.NoError(t, err)
   503  
   504  				tx, err := tt.sign(transactionInterface, newKey)
   505  				assert.NoError(t, err)
   506  				assert.NotEmpty(t, tx)
   507  
   508  				signs, err := TransactionGetSignatures(transactionInterface)
   509  				assert.NoError(t, err)
   510  
   511  				// verify with range because var signs = map[AccountID]map[*PublicKey][]byte, where *PublicKey is unknown memory address
   512  				for key := range signs[nodeAccountId] {
   513  					assert.Equal(t, signs[nodeAccountId][key], signature)
   514  				}
   515  			})
   516  		}
   517  	}
   518  }
   519  
   520  func TestUnitTransactionSignSwitchCasesPointers(t *testing.T) {
   521  	t.Parallel()
   522  
   523  	newKey, client, nodeAccountId := signSwitchCaseaSetup(t)
   524  
   525  	txs := []interface{}{
   526  		NewAccountCreateTransaction(),
   527  		NewAccountDeleteTransaction(),
   528  		NewAccountUpdateTransaction(),
   529  		NewAccountAllowanceApproveTransaction(),
   530  		NewAccountAllowanceDeleteTransaction(),
   531  		NewFileCreateTransaction(),
   532  		NewFileDeleteTransaction(),
   533  		NewFileUpdateTransaction(),
   534  		NewLiveHashAddTransaction(),
   535  		NewLiveHashDeleteTransaction(),
   536  		NewTokenAssociateTransaction(),
   537  		NewTokenBurnTransaction(),
   538  		NewTokenCreateTransaction(),
   539  		NewTokenDeleteTransaction(),
   540  		NewTokenDissociateTransaction(),
   541  		NewTokenFeeScheduleUpdateTransaction(),
   542  		NewTokenFreezeTransaction(),
   543  		NewTokenGrantKycTransaction(),
   544  		NewTokenMintTransaction(),
   545  		NewTokenRevokeKycTransaction(),
   546  		NewTokenUnfreezeTransaction(),
   547  		NewTokenUpdateTransaction(),
   548  		NewTokenWipeTransaction(),
   549  		NewTopicCreateTransaction(),
   550  		NewTopicDeleteTransaction(),
   551  		NewTopicUpdateTransaction(),
   552  		NewTransferTransaction(),
   553  	}
   554  
   555  	for _, tx := range txs {
   556  
   557  		txVal, signature, transferTxBytes := signSwitchCaseaHelper(t, tx, newKey, client)
   558  		signTests := signTestsForTransaction(txVal, newKey, signature, client)
   559  
   560  		for _, tt := range signTests {
   561  			t.Run(tt.name, func(t *testing.T) {
   562  				transactionInterface, err := TransactionFromBytes(transferTxBytes)
   563  				require.NoError(t, err)
   564  
   565  				// Convert the transactionInterface to a pointer
   566  				ptr := reflect.New(reflect.TypeOf(transactionInterface))
   567  				ptr.Elem().Set(reflect.ValueOf(transactionInterface))
   568  
   569  				tx, err := tt.sign(ptr.Interface(), newKey)
   570  				assert.NoError(t, err)
   571  				assert.NotEmpty(t, tx)
   572  
   573  				signs, err := TransactionGetSignatures(ptr.Interface())
   574  				assert.NoError(t, err)
   575  
   576  				// verify with range because var signs = map[AccountID]map[*PublicKey][]byte, where *PublicKey is unknown memory address
   577  				for key := range signs[nodeAccountId] {
   578  					assert.Equal(t, signs[nodeAccountId][key], signature)
   579  				}
   580  			})
   581  		}
   582  	}
   583  }
   584  
   585  func TestUnitTransactionAttributes(t *testing.T) {
   586  	t.Parallel()
   587  
   588  	client, err := _NewMockClient()
   589  	require.NoError(t, err)
   590  	client.SetLedgerID(*NewLedgerIDTestnet())
   591  	nodeAccountIds := client.network._GetNodeAccountIDsForExecute()
   592  
   593  	txs := []interface{}{
   594  		NewAccountCreateTransaction(),
   595  		NewAccountDeleteTransaction(),
   596  		NewAccountUpdateTransaction(),
   597  		NewAccountAllowanceApproveTransaction(),
   598  		NewAccountAllowanceDeleteTransaction(),
   599  		NewContractCreateTransaction(),
   600  		NewContractDeleteTransaction(),
   601  		NewContractExecuteTransaction(),
   602  		NewContractUpdateTransaction(),
   603  		NewFileAppendTransaction(),
   604  		NewFileCreateTransaction(),
   605  		NewFileDeleteTransaction(),
   606  		NewFileUpdateTransaction(),
   607  		NewLiveHashAddTransaction(),
   608  		NewLiveHashDeleteTransaction(),
   609  		NewScheduleCreateTransaction(),
   610  		NewScheduleDeleteTransaction(),
   611  		NewScheduleSignTransaction(),
   612  		NewSystemDeleteTransaction(),
   613  		NewSystemUndeleteTransaction(),
   614  		NewTokenAssociateTransaction(),
   615  		NewTokenBurnTransaction(),
   616  		NewTokenCreateTransaction(),
   617  		NewTokenDeleteTransaction(),
   618  		NewTokenDissociateTransaction(),
   619  		NewTokenFeeScheduleUpdateTransaction(),
   620  		NewTokenFreezeTransaction(),
   621  		NewTokenGrantKycTransaction(),
   622  		NewTokenMintTransaction(),
   623  		NewTokenRevokeKycTransaction(),
   624  		NewTokenUnfreezeTransaction(),
   625  		NewTokenUpdateTransaction(),
   626  		NewTokenWipeTransaction(),
   627  		NewTopicCreateTransaction(),
   628  		NewTopicDeleteTransaction(),
   629  		NewTopicUpdateTransaction(),
   630  		NewTransferTransaction(),
   631  	}
   632  
   633  	for _, tx := range txs {
   634  		txName := reflect.TypeOf(tx).Elem().Name()
   635  
   636  		tests := createTransactionTests(txName, nodeAccountIds)
   637  
   638  		for _, tt := range tests {
   639  			t.Run(tt.name, func(t *testing.T) {
   640  				txSet, err := tt.set(tx)
   641  				require.NoError(t, err)
   642  
   643  				txGet, err := tt.get(txSet)
   644  				require.NoError(t, err)
   645  
   646  				tt.assert(t, txGet)
   647  			})
   648  		}
   649  	}
   650  }
   651  
   652  func TestUnitTransactionAttributesDereferanced(t *testing.T) {
   653  	t.Parallel()
   654  
   655  	client, err := _NewMockClient()
   656  	require.NoError(t, err)
   657  	client.SetLedgerID(*NewLedgerIDTestnet())
   658  	nodeAccountIds := client.network._GetNodeAccountIDsForExecute()
   659  
   660  	txs := []interface{}{
   661  		NewAccountCreateTransaction(),
   662  		NewAccountDeleteTransaction(),
   663  		NewAccountUpdateTransaction(),
   664  		NewAccountAllowanceApproveTransaction(),
   665  		NewAccountAllowanceDeleteTransaction(),
   666  		NewContractCreateTransaction(),
   667  		NewContractDeleteTransaction(),
   668  		NewContractExecuteTransaction(),
   669  		NewContractUpdateTransaction(),
   670  		NewFileAppendTransaction(),
   671  		NewFileCreateTransaction(),
   672  		NewFileDeleteTransaction(),
   673  		NewFileUpdateTransaction(),
   674  		NewLiveHashAddTransaction(),
   675  		NewLiveHashDeleteTransaction(),
   676  		NewScheduleCreateTransaction(),
   677  		NewScheduleDeleteTransaction(),
   678  		NewScheduleSignTransaction(),
   679  		NewSystemDeleteTransaction(),
   680  		NewSystemUndeleteTransaction(),
   681  		NewTokenAssociateTransaction(),
   682  		NewTokenBurnTransaction(),
   683  		NewTokenCreateTransaction(),
   684  		NewTokenDeleteTransaction(),
   685  		NewTokenDissociateTransaction(),
   686  		NewTokenFeeScheduleUpdateTransaction(),
   687  		NewTokenFreezeTransaction(),
   688  		NewTokenGrantKycTransaction(),
   689  		NewTokenMintTransaction(),
   690  		NewTokenRevokeKycTransaction(),
   691  		NewTokenUnfreezeTransaction(),
   692  		NewTokenUpdateTransaction(),
   693  		NewTokenWipeTransaction(),
   694  		NewTopicCreateTransaction(),
   695  		NewTopicDeleteTransaction(),
   696  		NewTopicUpdateTransaction(),
   697  		NewTransferTransaction(),
   698  	}
   699  
   700  	for _, tx := range txs {
   701  		txName := reflect.TypeOf(tx).Elem().Name()
   702  
   703  		tests := createTransactionTests(txName, nodeAccountIds)
   704  
   705  		for _, tt := range tests {
   706  			t.Run(tt.name, func(t *testing.T) {
   707  				txValue := reflect.ValueOf(tx).Elem().Interface()
   708  				txSet, err := tt.set(txValue)
   709  				require.NoError(t, err)
   710  
   711  				txGet, err := tt.get(txSet)
   712  				require.NoError(t, err)
   713  
   714  				tt.assert(t, txGet)
   715  			})
   716  		}
   717  	}
   718  }
   719  
   720  func TestUnitTransactionAttributesSerialization(t *testing.T) {
   721  	t.Parallel()
   722  
   723  	client, err := _NewMockClient()
   724  	require.NoError(t, err)
   725  	client.SetLedgerID(*NewLedgerIDTestnet())
   726  
   727  	txs := []interface{}{
   728  		NewAccountCreateTransaction(),
   729  		NewAccountDeleteTransaction(),
   730  		NewAccountUpdateTransaction(),
   731  		NewAccountAllowanceApproveTransaction(),
   732  		NewAccountAllowanceDeleteTransaction(),
   733  		NewContractCreateTransaction(),
   734  		NewContractDeleteTransaction(),
   735  		NewContractExecuteTransaction(),
   736  		NewContractUpdateTransaction(),
   737  		NewFileCreateTransaction(),
   738  		NewFileDeleteTransaction(),
   739  		NewFileUpdateTransaction(),
   740  		NewLiveHashAddTransaction(),
   741  		NewLiveHashDeleteTransaction(),
   742  		NewScheduleCreateTransaction(),
   743  		NewScheduleDeleteTransaction(),
   744  		NewScheduleSignTransaction(),
   745  		NewSystemDeleteTransaction(),
   746  		NewSystemUndeleteTransaction(),
   747  		NewTokenAssociateTransaction(),
   748  		NewTokenBurnTransaction(),
   749  		NewTokenCreateTransaction(),
   750  		NewTokenDeleteTransaction(),
   751  		NewTokenDissociateTransaction(),
   752  		NewTokenFeeScheduleUpdateTransaction(),
   753  		NewTokenFreezeTransaction(),
   754  		NewTokenGrantKycTransaction(),
   755  		NewTokenMintTransaction(),
   756  		NewTokenRevokeKycTransaction(),
   757  		NewTokenUnfreezeTransaction(),
   758  		NewTokenUpdateTransaction(),
   759  		NewTokenWipeTransaction(),
   760  		NewTopicCreateTransaction(),
   761  		NewTopicDeleteTransaction(),
   762  		NewTopicUpdateTransaction(),
   763  		NewTransferTransaction(),
   764  	}
   765  
   766  	for _, tx := range txs {
   767  		txName := reflect.TypeOf(tx).Elem().Name()
   768  
   769  		// Get the reflect.Value of the pointer to the Transaction
   770  		txPtr := reflect.ValueOf(tx)
   771  		txPtr.MethodByName("FreezeWith").Call([]reflect.Value{reflect.ValueOf(client)})
   772  
   773  		tests := []struct {
   774  			name string
   775  			act  func(transactionInterface interface{})
   776  		}{
   777  			{
   778  				name: "TransactionString/" + txName,
   779  				act: func(transactionInterface interface{}) {
   780  					txString, err := TransactionString(transactionInterface)
   781  					require.NoError(t, err)
   782  					require.NotEmpty(t, txString)
   783  				},
   784  			},
   785  			{
   786  				name: "TransactionToBytes/" + txName,
   787  				act: func(transactionInterface interface{}) {
   788  					txBytes, err := TransactionToBytes(transactionInterface)
   789  					require.NoError(t, err)
   790  					require.NotEmpty(t, txBytes)
   791  				},
   792  			},
   793  		}
   794  
   795  		for _, tt := range tests {
   796  			t.Run(tt.name, func(t *testing.T) {
   797  				tt.act(tx)
   798  				txValue := reflect.ValueOf(tx).Elem().Interface()
   799  				tt.act(txValue)
   800  			})
   801  		}
   802  	}
   803  }
   804  
   805  func signSwitchCaseaSetup(t *testing.T) (PrivateKey, *Client, AccountID) {
   806  	newKey, err := GeneratePrivateKey()
   807  	require.NoError(t, err)
   808  
   809  	client, err := _NewMockClient()
   810  	require.NoError(t, err)
   811  	client.SetLedgerID(*NewLedgerIDTestnet())
   812  
   813  	nodeAccountIds := client.network._GetNodeAccountIDsForExecute()
   814  	nodeAccountId := nodeAccountIds[0]
   815  
   816  	return newKey, client, nodeAccountId
   817  }
   818  
   819  func signSwitchCaseaHelper(t *testing.T, tx interface{}, newKey PrivateKey, client *Client) (txVal reflect.Value, signature []byte, transferTxBytes []byte) {
   820  	// Get the reflect.Value of the pointer to the transaction
   821  	txPtr := reflect.ValueOf(tx)
   822  	txPtr.MethodByName("FreezeWith").Call([]reflect.Value{reflect.ValueOf(client)})
   823  
   824  	// Get the reflect.Value of the transaction
   825  	txVal = txPtr.Elem()
   826  
   827  	// Get the transaction field by name
   828  	txField := txVal.FieldByName("Transaction")
   829  
   830  	// Get the value of the Transaction field
   831  	txValue := txField.Interface().(Transaction)
   832  
   833  	refl_signature := reflect.ValueOf(newKey).MethodByName("SignTransaction").Call([]reflect.Value{reflect.ValueOf(&txValue)})
   834  	signature = refl_signature[0].Interface().([]byte)
   835  
   836  	transferTxBytes, err := TransactionToBytes(tx)
   837  	assert.NoError(t, err)
   838  	assert.NotEmpty(t, transferTxBytes)
   839  
   840  	return txVal, signature, transferTxBytes
   841  }
   842  
   843  func signTestsForTransaction(txVal reflect.Value, newKey PrivateKey, signature []byte, client *Client) []struct {
   844  	name string
   845  	sign func(transactionInterface interface{}, key Key) (interface{}, error)
   846  } {
   847  	return []struct {
   848  		name string
   849  		sign func(transactionInterface interface{}, key Key) (interface{}, error)
   850  	}{
   851  		{
   852  			name: "TransactionSign/" + txVal.Type().Name(),
   853  			sign: func(transactionInterface interface{}, key Key) (interface{}, error) {
   854  				privateKey, ok := key.(PrivateKey)
   855  				if !ok {
   856  					panic("key is not a PrivateKey")
   857  				}
   858  				return TransactionSign(transactionInterface, privateKey)
   859  			},
   860  		},
   861  		{
   862  			name: "TransactionSignWith/" + txVal.Type().Name(),
   863  			sign: func(transactionInterface interface{}, key Key) (interface{}, error) {
   864  				return TransactionSignWth(transactionInterface, newKey.PublicKey(), newKey.Sign)
   865  			},
   866  		},
   867  		{
   868  			name: "TransactionSignWithOperator/" + txVal.Type().Name(),
   869  			sign: func(transactionInterface interface{}, key Key) (interface{}, error) {
   870  				return TransactionSignWithOperator(transactionInterface, client)
   871  			},
   872  		},
   873  		{
   874  			name: "TransactionAddSignature/" + txVal.Type().Name(),
   875  			sign: func(transactionInterface interface{}, key Key) (interface{}, error) {
   876  				return TransactionAddSignature(transactionInterface, newKey.PublicKey(), signature)
   877  			},
   878  		},
   879  	}
   880  }
   881  
   882  type transactionTest struct {
   883  	name   string
   884  	set    func(transactionInterface interface{}) (interface{}, error)
   885  	get    func(transactionInterface interface{}) (interface{}, error)
   886  	assert func(t *testing.T, actual interface{})
   887  }
   888  
   889  func createTransactionTests(txName string, nodeAccountIds []AccountID) []transactionTest {
   890  	return []transactionTest{
   891  		{
   892  			name: "TransactionTransactionID/" + txName,
   893  			set: func(transactionInterface interface{}) (interface{}, error) {
   894  				transactionID := TransactionID{AccountID: &AccountID{Account: 9999}, ValidStart: &time.Time{}, scheduled: false, Nonce: nil}
   895  				return TransactionSetTransactionID(transactionInterface, transactionID)
   896  			},
   897  			get: func(transactionInterface interface{}) (interface{}, error) {
   898  				return TransactionGetTransactionID(transactionInterface)
   899  			},
   900  			assert: func(t *testing.T, actual interface{}) {
   901  				transactionID := TransactionID{AccountID: &AccountID{Account: 9999}, ValidStart: &time.Time{}, scheduled: false, Nonce: nil}
   902  				A := actual.(TransactionID)
   903  
   904  				require.Equal(t, transactionID.AccountID, A.AccountID)
   905  			},
   906  		},
   907  		{
   908  			name: "TransactionTransactionMemo/" + txName,
   909  			set: func(transactionInterface interface{}) (interface{}, error) {
   910  				return TransactionSetTransactionMemo(transactionInterface, "test memo")
   911  			},
   912  			get: func(transactionInterface interface{}) (interface{}, error) {
   913  				return TransactionGetTransactionMemo(transactionInterface)
   914  			},
   915  			assert: func(t *testing.T, actual interface{}) {
   916  				require.Equal(t, "test memo", actual)
   917  			},
   918  		},
   919  		{
   920  			name: "TransactionMaxTransactionFee/" + txName,
   921  			set: func(transactionInterface interface{}) (interface{}, error) {
   922  				return TransactionSetMaxTransactionFee(transactionInterface, NewHbar(1))
   923  			},
   924  			get: func(transactionInterface interface{}) (interface{}, error) {
   925  				return TransactionGetMaxTransactionFee(transactionInterface)
   926  			},
   927  			assert: func(t *testing.T, actual interface{}) {
   928  				require.Equal(t, NewHbar(1), actual)
   929  			},
   930  		},
   931  		{
   932  			name: "TransactionTransactionValidDuration/" + txName,
   933  			set: func(transactionInterface interface{}) (interface{}, error) {
   934  				return TransactionSetTransactionValidDuration(transactionInterface, time.Second*10)
   935  			},
   936  			get: func(transactionInterface interface{}) (interface{}, error) {
   937  				return TransactionGetTransactionValidDuration(transactionInterface)
   938  			},
   939  			assert: func(t *testing.T, actual interface{}) {
   940  				require.Equal(t, time.Second*10, actual)
   941  			},
   942  		},
   943  		{
   944  			name: "TransactionNodeAccountIDs/" + txName,
   945  			set: func(transactionInterface interface{}) (interface{}, error) {
   946  				return TransactionSetNodeAccountIDs(transactionInterface, nodeAccountIds)
   947  			},
   948  			get: func(transactionInterface interface{}) (interface{}, error) {
   949  				return TransactionGetNodeAccountIDs(transactionInterface)
   950  			},
   951  			assert: func(t *testing.T, actual interface{}) {
   952  				require.Equal(t, nodeAccountIds, actual)
   953  			},
   954  		},
   955  		{
   956  			name: "TransactionMinBackoff/" + txName,
   957  			set: func(transactionInterface interface{}) (interface{}, error) {
   958  				tx, _ := TransactionSetMaxBackoff(transactionInterface, time.Second*200)
   959  				return TransactionSetMinBackoff(tx, time.Second*10)
   960  			},
   961  			get: func(transactionInterface interface{}) (interface{}, error) {
   962  				return TransactionGetMinBackoff(transactionInterface)
   963  			},
   964  			assert: func(t *testing.T, actual interface{}) {
   965  				require.Equal(t, time.Second*10, actual)
   966  			},
   967  		},
   968  		{
   969  			name: "TransactionMaxBackoff/" + txName,
   970  			set: func(transactionInterface interface{}) (interface{}, error) {
   971  				return TransactionSetMaxBackoff(transactionInterface, time.Second*200)
   972  			},
   973  			get: func(transactionInterface interface{}) (interface{}, error) {
   974  				return TransactionGetMaxBackoff(transactionInterface)
   975  			},
   976  			assert: func(t *testing.T, actual interface{}) {
   977  				require.Equal(t, time.Second*200, actual)
   978  			},
   979  		},
   980  	}
   981  }
   982  
   983  // TransactionGetTransactionHash //needs to be tested in e2e tests
   984  // TransactionGetTransactionHashPerNode //needs to be tested in e2e tests
   985  // TransactionExecute //needs to be tested in e2e tests