package transactions import ( "math/big" "reflect" "testing" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/status-im/status-go/account" "github.com/status-im/status-go/params" e2e "github.com/status-im/status-go/t/e2e" . "github.com/status-im/status-go/t/utils" "github.com/status-im/status-go/transactions" "github.com/stretchr/testify/suite" ) type initFunc func([]byte, *transactions.SendTxArgs) func TestTransactionsTestSuite(t *testing.T) { suite.Run(t, new(TransactionsTestSuite)) } type TransactionsTestSuite struct { e2e.BackendTestSuite } func (s *TransactionsTestSuite) TestCallRPCSendTransaction() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID) s.StartTestBackend() defer s.StopTestBackend() EnsureNodeSync(s.Backend.StatusNode().EnsureSync) s.sendTransactionUsingRPCClient(s.Backend.CallRPC) } func (s *TransactionsTestSuite) TestCallUpstreamRPCSendTransaction() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID, params.StatusChainNetworkID) addr, err := GetRemoteURL() s.NoError(err) s.StartTestBackend(e2e.WithUpstream(addr)) defer s.StopTestBackend() s.sendTransactionUsingRPCClient(s.Backend.CallRPC) } func (s *TransactionsTestSuite) TestCallPrivateRPCSendTransaction() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID) s.StartTestBackend() defer s.StopTestBackend() EnsureNodeSync(s.Backend.StatusNode().EnsureSync) s.sendTransactionUsingRPCClient(s.Backend.CallPrivateRPC) } func (s *TransactionsTestSuite) TestCallUpstreamPrivateRPCSendTransaction() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID, params.StatusChainNetworkID) addr, err := GetRemoteURL() s.NoError(err) s.StartTestBackend(e2e.WithUpstream(addr)) defer s.StopTestBackend() s.sendTransactionUsingRPCClient(s.Backend.CallPrivateRPC) } func (s *TransactionsTestSuite) sendTransactionUsingRPCClient( callRPCFn func(string) (string, error), ) { err := s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) s.NoError(err) result, err := callRPCFn(`{ "jsonrpc": "2.0", "id": 1, "method": "eth_sendTransaction", "params": [{ "from": "` + TestConfig.Account1.Address + `", "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", "value": "0x9184e72a" }] }`) s.NoError(err) s.Contains(result, `"error":{"code":-32700,"message":"method is unsupported by RPC interface"}`) } func (s *TransactionsTestSuite) TestEmptyToFieldPreserved() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID) s.StartTestBackend() defer s.StopTestBackend() EnsureNodeSync(s.Backend.StatusNode().EnsureSync) err := s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) s.NoError(err) args := transactions.SendTxArgs{ From: account.FromAddress(TestConfig.Account1.Address), } hash, err := s.Backend.SendTransaction(args, TestConfig.Account1.Password) s.NoError(err) s.NotNil(hash) } // TestSendContractCompat tries to send transaction using the legacy "Data" // field, which is supported for backward compatibility reasons. func (s *TransactionsTestSuite) TestSendContractTxCompat() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID) initFunc := func(byteCode []byte, args *transactions.SendTxArgs) { args.Data = (hexutil.Bytes)(byteCode) } s.testSendContractTx(initFunc, nil, "") } // TestSendContractCompat tries to send transaction using both the legacy // "Data" and "Input" fields. Also makes sure that the error is returned if // they have different values. func (s *TransactionsTestSuite) TestSendContractTxCollision() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID) // Scenario 1: Both fields are filled and have the same value, expect success initFunc := func(byteCode []byte, args *transactions.SendTxArgs) { args.Input = (hexutil.Bytes)(byteCode) args.Data = (hexutil.Bytes)(byteCode) } s.testSendContractTx(initFunc, nil, "") // Scenario 2: Both fields are filled with different values, expect an error inverted := func(source []byte) []byte { inverse := make([]byte, len(source)) copy(inverse, source) for i, b := range inverse { inverse[i] = b ^ 0xFF } return inverse } initFunc2 := func(byteCode []byte, args *transactions.SendTxArgs) { args.Input = (hexutil.Bytes)(byteCode) args.Data = (hexutil.Bytes)(inverted(byteCode)) } s.testSendContractTx(initFunc2, transactions.ErrInvalidSendTxArgs, "expected error when invalid tx args are sent") } func (s *TransactionsTestSuite) TestSendContractTx() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID) initFunc := func(byteCode []byte, args *transactions.SendTxArgs) { args.Input = (hexutil.Bytes)(byteCode) } s.testSendContractTx(initFunc, nil, "") } func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc, expectedError error, expectedErrorDescription string) { s.StartTestBackend() defer s.StopTestBackend() EnsureNodeSync(s.Backend.StatusNode().EnsureSync) err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) s.NoError(err) // this call blocks, up until Complete Transaction is called byteCode, err := hexutil.Decode(`0x6060604052341561000c57fe5b5b60a58061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680636ffa1caa14603a575bfe5b3415604157fe5b60556004808035906020019091905050606b565b6040518082815260200191505060405180910390f35b60008160020290505b9190505600a165627a7a72305820ccdadd737e4ac7039963b54cee5e5afb25fa859a275252bdcf06f653155228210029`) s.NoError(err) gas := uint64(params.DefaultGas) args := transactions.SendTxArgs{ From: account.FromAddress(TestConfig.Account1.Address), To: nil, // marker, contract creation is expected //Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), gethcommon.Ether)), Gas: (*hexutil.Uint64)(&gas), } setInputAndDataValue(byteCode, &args) hash, err := s.Backend.SendTransaction(args, TestConfig.Account1.Password) if expectedError != nil { s.Equal(expectedError, err, expectedErrorDescription) return } s.NoError(err) s.False(reflect.DeepEqual(hash, gethcommon.Hash{})) s.NoError(s.Backend.Logout()) } func (s *TransactionsTestSuite) TestSendEther() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID) s.StartTestBackend() defer s.StopTestBackend() EnsureNodeSync(s.Backend.StatusNode().EnsureSync) err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) s.NoError(err) hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{ From: account.FromAddress(TestConfig.Account1.Address), To: account.ToAddress(TestConfig.Account2.Address), Value: (*hexutil.Big)(big.NewInt(1000000000000)), }, TestConfig.Account1.Password) s.NoError(err) s.False(reflect.DeepEqual(hash, gethcommon.Hash{})) } func (s *TransactionsTestSuite) TestSendEtherTxUpstream() { CheckTestSkipForNetworks(s.T(), params.MainNetworkID, params.StatusChainNetworkID) addr, err := GetRemoteURL() s.NoError(err) s.StartTestBackend(e2e.WithUpstream(addr)) defer s.StopTestBackend() err = s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) s.NoError(err) hash, err := s.Backend.SendTransaction(transactions.SendTxArgs{ From: account.FromAddress(TestConfig.Account1.Address), To: account.ToAddress(TestConfig.Account2.Address), GasPrice: (*hexutil.Big)(big.NewInt(28000000000)), Value: (*hexutil.Big)(big.NewInt(1000000000000)), }, TestConfig.Account1.Password) s.NoError(err) s.False(reflect.DeepEqual(hash, gethcommon.Hash{})) }