package wakuext import ( "context" "fmt" "io/ioutil" "math" "os" "strconv" "testing" "time" "go.uber.org/zap" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/storage" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/status-im/status-go/appdatabase" gethbridge "github.com/status-im/status-go/eth-node/bridge/geth" "github.com/status-im/status-go/eth-node/crypto" "github.com/status-im/status-go/eth-node/types" "github.com/status-im/status-go/multiaccounts" "github.com/status-im/status-go/params" "github.com/status-im/status-go/services/ext" "github.com/status-im/status-go/t/helpers" "github.com/status-im/status-go/waku" "github.com/status-im/status-go/walletdatabase" ) func TestRequestMessagesErrors(t *testing.T) { var err error waku := gethbridge.NewGethWakuWrapper(waku.New(nil, nil)) aNode, err := node.New(&node.Config{ P2P: p2p.Config{ MaxPeers: math.MaxInt32, NoDiscovery: true, }, NoUSB: true, }) // in-memory node as no data dir require.NoError(t, err) w := gethbridge.GetGethWakuFrom(waku) aNode.RegisterLifecycle(w) aNode.RegisterAPIs(w.APIs()) aNode.RegisterProtocols(w.Protocols()) require.NoError(t, err) err = aNode.Start() require.NoError(t, err) defer func() { require.NoError(t, aNode.Close()) }() handler := ext.NewHandlerMock(1) config := params.NodeConfig{ RootDataDir: os.TempDir(), ShhextConfig: params.ShhextConfig{ InstallationID: "1", PFSEnabled: true, }, } nodeWrapper := ext.NewTestNodeWrapper(nil, waku) service := New(config, nodeWrapper, nil, handler, nil) api := NewPublicAPI(service) const mailServerPeer = "enode://b7e65e1bedc2499ee6cbd806945af5e7df0e59e4070c96821570bd581473eade24a489f5ec95d060c0db118c879403ab88d827d3766978f28708989d35474f87@[::]:51920" var hash []byte // invalid MailServer enode address hash, err = api.RequestMessages(context.TODO(), ext.MessagesRequest{MailServerPeer: "invalid-address"}) require.Nil(t, hash) require.EqualError(t, err, "invalid mailServerPeer value: invalid URL scheme, want \"enode\"") // non-existent symmetric key hash, err = api.RequestMessages(context.TODO(), ext.MessagesRequest{ MailServerPeer: mailServerPeer, SymKeyID: "invalid-sym-key-id", }) require.Nil(t, hash) require.EqualError(t, err, "invalid symKeyID value: non-existent key ID") // with a symmetric key symKeyID, symKeyErr := waku.AddSymKeyFromPassword("some-pass") require.NoError(t, symKeyErr) hash, err = api.RequestMessages(context.TODO(), ext.MessagesRequest{ MailServerPeer: mailServerPeer, SymKeyID: symKeyID, }) require.Nil(t, hash) require.Contains(t, err.Error(), "could not find peer with ID") // from is greater than to hash, err = api.RequestMessages(context.TODO(), ext.MessagesRequest{ From: 10, To: 5, }) require.Nil(t, hash) require.Contains(t, err.Error(), "Query range is invalid: from > to (10 > 5)") } func TestInitProtocol(t *testing.T) { config := params.NodeConfig{ RootDataDir: t.TempDir(), ShhextConfig: params.ShhextConfig{ InstallationID: "2", PFSEnabled: true, MailServerConfirmations: true, ConnectionTarget: 10, }, } db, err := leveldb.Open(storage.NewMemStorage(), nil) require.NoError(t, err) waku := gethbridge.NewGethWakuWrapper(waku.New(nil, nil)) privateKey, err := crypto.GenerateKey() require.NoError(t, err) nodeWrapper := ext.NewTestNodeWrapper(nil, waku) service := New(config, nodeWrapper, nil, nil, db) appDB, cleanupDB, err := helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "db.sql") defer func() { require.NoError(t, cleanupDB()) }() require.NoError(t, err) tmpfile, err := ioutil.TempFile("", "multi-accounts-tests-") require.NoError(t, err) multiAccounts, err := multiaccounts.InitializeDB(tmpfile.Name()) require.NoError(t, err) acc := &multiaccounts.Account{KeyUID: "0xdeadbeef"} walletDB, cleanupWalletDB, err := helpers.SetupTestSQLDB(walletdatabase.DbInitializer{}, "db-wallet.sql") defer func() { require.NoError(t, cleanupWalletDB()) }() require.NoError(t, err) err = service.InitProtocol("Test", privateKey, appDB, walletDB, nil, multiAccounts, acc, nil, nil, nil, nil, nil, zap.NewNop()) require.NoError(t, err) } func TestShhExtSuite(t *testing.T) { suite.Run(t, new(ShhExtSuite)) } type ShhExtSuite struct { suite.Suite dir string nodes []*node.Node wakus []types.Waku services []*Service } func (s *ShhExtSuite) createAndAddNode() { idx := len(s.nodes) // create a node cfg := &node.Config{ Name: strconv.Itoa(idx), P2P: p2p.Config{ MaxPeers: math.MaxInt32, NoDiscovery: true, ListenAddr: ":0", }, NoUSB: true, } stack, err := node.New(cfg) s.NoError(err) w := waku.New(nil, nil) stack.RegisterLifecycle(w) stack.RegisterAPIs(w.APIs()) stack.RegisterProtocols(w.Protocols()) s.NoError(err) // set up protocol config := params.NodeConfig{ RootDataDir: s.dir, ShhextConfig: params.ShhextConfig{ InstallationID: "1", PFSEnabled: true, MailServerConfirmations: true, ConnectionTarget: 10, }, } db, err := leveldb.Open(storage.NewMemStorage(), nil) s.Require().NoError(err) nodeWrapper := ext.NewTestNodeWrapper(nil, gethbridge.NewGethWakuWrapper(w)) service := New(config, nodeWrapper, nil, nil, db) appDB, cleanupDB, err := helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, fmt.Sprintf("%d", idx)) s.Require().NoError(err) defer func() { s.Require().NoError(cleanupDB()) }() tmpfile, err := ioutil.TempFile("", "multi-accounts-tests-") s.Require().NoError(err) multiAccounts, err := multiaccounts.InitializeDB(tmpfile.Name()) s.Require().NoError(err) privateKey, err := crypto.GenerateKey() s.NoError(err) acc := &multiaccounts.Account{KeyUID: "0xdeadbeef"} walletDB, err := helpers.SetupTestMemorySQLDB(&walletdatabase.DbInitializer{}) s.Require().NoError(err) err = service.InitProtocol("Test", privateKey, appDB, walletDB, nil, multiAccounts, acc, nil, nil, nil, nil, nil, zap.NewNop()) s.NoError(err) stack.RegisterLifecycle(service) stack.RegisterAPIs(service.APIs()) stack.RegisterProtocols(service.Protocols()) s.NoError(err) // start the node err = stack.Start() s.Require().NoError(err) // store references s.nodes = append(s.nodes, stack) s.wakus = append(s.wakus, gethbridge.NewGethWakuWrapper(w)) s.services = append(s.services, service) } func (s *ShhExtSuite) SetupTest() { s.dir = s.T().TempDir() } func (s *ShhExtSuite) TearDownTest() { for _, n := range s.nodes { s.NoError(n.Close()) } s.nodes = nil s.wakus = nil s.services = nil } func (s *ShhExtSuite) TestRequestMessagesSuccess() { // two nodes needed: client and mailserver s.createAndAddNode() s.createAndAddNode() waitErr := helpers.WaitForPeerAsync(s.nodes[0].Server(), s.nodes[1].Server().Self().URLv4(), p2p.PeerEventTypeAdd, time.Second) s.nodes[0].Server().AddPeer(s.nodes[1].Server().Self()) s.Require().NoError(<-waitErr) api := NewPublicAPI(s.services[0]) _, err := api.RequestMessages(context.Background(), ext.MessagesRequest{ MailServerPeer: s.nodes[1].Server().Self().URLv4(), Topics: []types.TopicType{{1}}, }) s.NoError(err) } func (s *ShhExtSuite) TestMultipleRequestMessagesWithoutForce() { // two nodes needed: client and mailserver s.createAndAddNode() s.createAndAddNode() waitErr := helpers.WaitForPeerAsync(s.nodes[0].Server(), s.nodes[1].Server().Self().URLv4(), p2p.PeerEventTypeAdd, time.Second) s.nodes[0].Server().AddPeer(s.nodes[1].Server().Self()) s.Require().NoError(<-waitErr) api := NewPublicAPI(s.services[0]) _, err := api.RequestMessages(context.Background(), ext.MessagesRequest{ MailServerPeer: s.nodes[1].Server().Self().URLv4(), Topics: []types.TopicType{{1}}, }) s.NoError(err) _, err = api.RequestMessages(context.Background(), ext.MessagesRequest{ MailServerPeer: s.nodes[1].Server().Self().URLv4(), Topics: []types.TopicType{{2}}, }) s.NoError(err) } func (s *ShhExtSuite) TestFailedRequestWithUnknownMailServerPeer() { s.createAndAddNode() api := NewPublicAPI(s.services[0]) _, err := api.RequestMessages(context.Background(), ext.MessagesRequest{ MailServerPeer: "enode://19872f94b1e776da3a13e25afa71b47dfa99e658afd6427ea8d6e03c22a99f13590205a8826443e95a37eee1d815fc433af7a8ca9a8d0df7943d1f55684045b7@0.0.0.0:30305", Topics: []types.TopicType{{1}}, }) s.EqualError(err, "could not find peer with ID: 10841e6db5c02fc331bf36a8d2a9137a1696d9d3b6b1f872f780e02aa8ec5bba") }