Add populate db script

This commit adds a populate db script, used by QA, but also very useful
to test Login/Logout flows.
This commit is contained in:
Andrea Maria Piana 2021-06-30 14:44:49 +02:00
parent 92404a5ab7
commit 188eabef0b
8 changed files with 1407 additions and 0 deletions

2
cmd/populate-db/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
populate-db
tmp/

40
cmd/populate-db/README.md Normal file
View file

@ -0,0 +1,40 @@
### How to build
You must have go installed.
Then you can run, from `cmd/populate-db`
```
go build
```
which should create a `populate-db` executable
### How to run
```
./populate-db --added-contacts 100 --contacts 200 --public-chats 100 --one-to-one-chats 40 --number-of-messages 2 --seed-phrase "your seed phrase"
```
The parameters are:
`added-contacts`: contacts you have added
`contacts`: number of "contacts" in the database, these are not added by you
`one-to-one-chats`: the number of one to one chats open
`public-chats`: the number of public chats
`number-of-messages`: the number of messages in each chat
`seed-phrase`: the seed phrase of the account to be created
The db will be created in the `./tmp` directory
### How to import the db
1) Create an account in status-react
2) Login, copy the seed phrase
3) Create a db using this script using the seed phrase
4) Copy the db to the import directory
5) Import the database
6) Login
Note that the db is not complete, so the app might not be fully functioning, but it
should be good enough to test performance and probably migrations

37
cmd/populate-db/flags.go Normal file
View file

@ -0,0 +1,37 @@
package main
import (
"fmt"
"os"
"path"
"strings"
)
// configFlags represents an array of JSON configuration files passed to a command line utility
type configFlags []string
func (f *configFlags) String() string {
return strings.Join(*f, ", ")
}
func (f *configFlags) Set(value string) error {
if !path.IsAbs(value) {
// Convert to absolute path
cwd, err := os.Getwd()
if err != nil {
return err
}
value = path.Join(cwd, value)
}
// Check that the file exists
stat, err := os.Stat(value)
if err != nil {
return err
}
if stat.IsDir() {
return fmt.Errorf("path does not represent a file: %s", value)
}
*f = append(*f, value)
return nil
}

View file

@ -0,0 +1,96 @@
package main
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/status-im/status-go/params"
)
// nolint: deadcode
func TestStatusFlag(t *testing.T) {
service := "status"
scenarios := []struct {
ipcEnabled bool
httpEnabled bool
flag string
err error
enabled bool
public bool
}{
// no flags
{},
// -status=ipc -ipc
{
ipcEnabled: true,
flag: "ipc",
enabled: true,
},
// -status=http -http
{
httpEnabled: true,
flag: "http",
enabled: true,
public: true,
},
// -status=ipc -http -ipc
{
httpEnabled: true,
ipcEnabled: true,
flag: "ipc",
enabled: true,
},
// -http -ipc
{
httpEnabled: true,
ipcEnabled: true,
flag: "",
},
// -status=ipc
{
err: errStatusServiceRequiresIPC,
flag: "ipc",
},
// -status=http
{
err: errStatusServiceRequiresHTTP,
flag: "http",
},
// -status=bad-value
{
err: errStatusServiceInvalidFlag,
flag: "bad-value",
},
}
for i, s := range scenarios {
msg := fmt.Sprintf("scenario %d", i)
c, err := params.NewNodeConfig("", 0)
require.Nil(t, err, msg)
c.IPCEnabled = s.ipcEnabled
c.HTTPEnabled = s.httpEnabled
c, err = configureStatusService(s.flag, c)
if s.err != nil {
require.Equal(t, s.err, err, msg)
require.Nil(t, c, msg)
continue
}
require.Nil(t, err, msg)
require.Equal(t, s.enabled, c.EnableStatusService, msg)
modules := c.FormatAPIModules()
if s.public {
require.Contains(t, modules, service, msg)
} else {
require.NotContains(t, modules, service, msg)
}
}
}

524
cmd/populate-db/main.go Normal file
View file

@ -0,0 +1,524 @@
package main
import (
"context"
"encoding/json"
"errors"
"flag"
"fmt"
stdlog "log"
"math/rand"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/google/uuid"
"golang.org/x/crypto/ssh/terminal"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/account/generator"
"github.com/status-im/status-go/api"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/multiaccounts"
"github.com/status-im/status-go/multiaccounts/accounts"
//"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/logutils"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/protocol"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/identity/alias"
"github.com/status-im/status-go/protocol/protobuf"
wakuextn "github.com/status-im/status-go/services/wakuext"
)
type testTimeSource struct{}
func (t *testTimeSource) GetCurrentTime() uint64 {
return uint64(time.Now().Unix())
}
const (
serverClientName = "Statusd"
)
var (
configFiles configFlags
logLevel = flag.String("log", "", `Log level, one of: "ERROR", "WARN", "INFO", "DEBUG", and "TRACE"`)
logWithoutColors = flag.Bool("log-without-color", false, "Disables log colors")
ipcEnabled = flag.Bool("ipc", false, "Enable IPC RPC endpoint")
ipcFile = flag.String("ipcfile", "", "Set IPC file path")
seedPhrase = flag.String("seed-phrase", "", "Seed phrase")
pprofEnabled = flag.Bool("pprof", false, "Enable runtime profiling via pprof")
pprofPort = flag.Int("pprof-port", 52525, "Port for runtime profiling via pprof")
version = flag.Bool("version", false, "Print version and dump configuration")
nAddedContacts = flag.Int("added-contacts", 100, "Number of added contacts to create")
nContacts = flag.Int("contacts", 100, "Number of contacts to create")
nPublicChats = flag.Int("public-chats", 5, "Number of public chats")
nMessages = flag.Int("number-of-messages", 0, "Number of messages for each chat")
nOneToOneChats = flag.Int("one-to-one-chats", 5, "Number of one to one chats")
dataDir = flag.String("dir", getDefaultDataDir(), "Directory used by node to store data")
register = flag.Bool("register", false, "Register and make the node discoverable by other nodes")
networkID = flag.Int(
"network-id",
params.RopstenNetworkID,
fmt.Sprintf(
"A network ID: %d (Mainnet), %d (Ropsten), %d (Rinkeby), %d (Goerli)",
params.MainNetworkID, params.RopstenNetworkID, params.RinkebyNetworkID, params.GoerliNetworkID,
),
)
listenAddr = flag.String("addr", "", "address to bind listener to")
syncAndExit = flag.Int("sync-and-exit", -1, "Timeout in minutes for blockchain sync and exit, zero means no timeout unless sync is finished")
)
// All general log messages in this package should be routed through this logger.
var logger = log.New("package", "status-go/cmd/statusd")
func init() {
flag.Var(&configFiles, "c", "JSON configuration file(s). Multiple configuration files can be specified, and will be merged in occurrence order")
}
// nolint:gocyclo
func main() {
colors := terminal.IsTerminal(int(os.Stdin.Fd()))
if err := logutils.OverrideRootLog(true, "ERROR", logutils.FileOptions{}, colors); err != nil {
stdlog.Fatalf("Error initializing logger: %v", err)
}
flag.Usage = printUsage
flag.Parse()
if flag.NArg() > 0 {
printUsage()
logger.Error("Extra args in command line: %v", flag.Args())
os.Exit(1)
}
opts := []params.Option{}
config, err := params.NewNodeConfigWithDefaultsAndFiles(
*dataDir,
uint64(*networkID),
opts,
configFiles,
)
if err != nil {
printUsage()
logger.Error(err.Error())
os.Exit(1)
}
// Use listenAddr if and only if explicitly provided in the arguments.
// The default value is set in params.NewNodeConfigWithDefaultsAndFiles().
if *listenAddr != "" {
config.ListenAddr = *listenAddr
}
// enable IPC RPC
if *ipcEnabled {
config.IPCEnabled = true
config.IPCFile = *ipcFile
}
// set up logging options
setupLogging(config)
// We want statusd to be distinct from StatusIM client.
config.Name = serverClientName
if *version {
printVersion(config)
return
}
backend := api.NewGethStatusBackend()
err = ImportAccount(*seedPhrase, backend)
if err != nil {
logger.Error("failed", "err", err)
return
}
wakuextservice, err := backend.WakuExtService()
if err != nil {
logger.Error("failed", "err", err)
return
}
wakuext := wakuextn.NewPublicAPI(wakuextservice)
// This will start the push notification server as well as
// the config is set to Enabled
_, err = wakuext.StartMessenger()
if err != nil {
logger.Error("failed to start messenger", "error", err)
return
}
logger.Info("Creating added contacts")
for i := 0; i < *nAddedContacts; i++ {
key, err := crypto.GenerateKey()
if err != nil {
logger.Error("failed", err)
return
}
keyString := common.PubkeyToHex(&key.PublicKey)
_, err = wakuext.AddContact(context.Background(), keyString)
if err != nil {
logger.Error("failed", "err", err)
return
}
}
logger.Info("Creating contacts")
for i := 0; i < *nContacts; i++ {
key, err := crypto.GenerateKey()
if err != nil {
return
}
contact, err := protocol.BuildContactFromPublicKey(&key.PublicKey)
if err != nil {
return
}
err = wakuext.SaveContact(context.Background(), contact)
if err != nil {
return
}
}
logger.Info("Creating public chats")
for i := 0; i < *nPublicChats; i++ {
chat := protocol.CreatePublicChat(randomString(10), &testTimeSource{})
chat.SyncedTo = 0
chat.SyncedFrom = 0
err = wakuext.SaveChat(context.Background(), chat)
if err != nil {
return
}
var messages []*common.Message
for i := 0; i < *nMessages; i++ {
messages = append(messages, buildMessage(chat, i))
}
if len(messages) > 0 {
if err := wakuext.SaveMessages(context.Background(), messages); err != nil {
return
}
}
}
logger.Info("Creating one to one chats")
for i := 0; i < *nOneToOneChats; i++ {
key, err := crypto.GenerateKey()
if err != nil {
return
}
keyString := common.PubkeyToHex(&key.PublicKey)
chat := protocol.CreateOneToOneChat(keyString, &key.PublicKey, &testTimeSource{})
chat.SyncedTo = 0
chat.SyncedFrom = 0
err = wakuext.SaveChat(context.Background(), chat)
if err != nil {
return
}
var messages []*common.Message
for i := 0; i < *nMessages; i++ {
messages = append(messages, buildMessage(chat, i))
}
if len(messages) > 0 {
if err := wakuext.SaveMessages(context.Background(), messages); err != nil {
return
}
}
}
}
func getDefaultDataDir() string {
if home := os.Getenv("HOME"); home != "" {
return filepath.Join(home, ".statusd")
}
return "./statusd-data"
}
func setupLogging(config *params.NodeConfig) {
if *logLevel != "" {
config.LogLevel = *logLevel
}
colors := !(*logWithoutColors) && terminal.IsTerminal(int(os.Stdin.Fd()))
if err := logutils.OverrideRootLogWithConfig(config, colors); err != nil {
stdlog.Fatalf("Error initializing logger: %v", err)
}
}
var (
errStatusServiceRequiresIPC = errors.New("to enable the StatusService on IPC, -ipc flag must be set")
errStatusServiceRequiresHTTP = errors.New("to enable the StatusService on HTTP, -http flag must be set")
errStatusServiceInvalidFlag = errors.New("-status flag valid values are: ipc, http")
)
// printVersion prints verbose output about version and config.
func printVersion(config *params.NodeConfig) {
fmt.Println(strings.Title(config.Name))
fmt.Println("Version:", config.Version)
fmt.Println("Network ID:", config.NetworkID)
fmt.Println("Go Version:", runtime.Version())
fmt.Println("OS:", runtime.GOOS)
fmt.Printf("GOPATH=%s\n", os.Getenv("GOPATH"))
fmt.Printf("GOROOT=%s\n", runtime.GOROOT())
fmt.Println("Loaded Config: ", config)
}
func printUsage() {
usage := `
Usage: statusd [options]
Examples:
statusd # run regular Whisper node that joins Status network
statusd -c ./default.json # run node with configuration specified in ./default.json file
statusd -c ./default.json -c ./standalone.json # run node with configuration specified in ./default.json file, after merging ./standalone.json file
statusd -c ./default.json -metrics # run node with configuration specified in ./default.json file, and expose ethereum metrics with debug_metrics jsonrpc call
Options:
`
fmt.Fprint(os.Stderr, usage)
flag.PrintDefaults()
}
const pathWalletRoot = "m/44'/60'/0'/0"
const pathEIP1581 = "m/43'/60'/1581'"
const pathDefaultChat = pathEIP1581 + "/0'/0"
const pathDefaultWallet = pathWalletRoot + "/0"
var paths = []string{pathWalletRoot, pathEIP1581, pathDefaultChat, pathDefaultWallet}
func defaultSettings(generatedAccountInfo generator.GeneratedAccountInfo, derivedAddresses map[string]generator.AccountInfo, mnemonic *string) (*accounts.Settings, error) {
chatKeyString := derivedAddresses[pathDefaultChat].PublicKey
settings := &accounts.Settings{}
settings.KeyUID = generatedAccountInfo.KeyUID
settings.Address = types.HexToAddress(generatedAccountInfo.Address)
settings.WalletRootAddress = types.HexToAddress(derivedAddresses[pathWalletRoot].Address)
// Set chat key & name
name, err := alias.GenerateFromPublicKeyString(chatKeyString)
if err != nil {
return nil, err
}
settings.Name = name
settings.PublicKey = chatKeyString
settings.DappsAddress = types.HexToAddress(derivedAddresses[pathDefaultWallet].Address)
settings.EIP1581Address = types.HexToAddress(derivedAddresses[pathEIP1581].Address)
settings.Mnemonic = mnemonic
signingPhrase, err := buildSigningPhrase()
if err != nil {
return nil, err
}
settings.SigningPhrase = signingPhrase
settings.SendPushNotifications = true
settings.InstallationID = uuid.New().String()
settings.UseMailservers = true
settings.PreviewPrivacy = true
settings.Currency = "usd"
settings.ProfilePicturesVisibility = 1
settings.LinkPreviewRequestEnabled = true
visibleTokens := make(map[string][]string)
visibleTokens["mainnet"] = []string{"SNT"}
visibleTokensJSON, err := json.Marshal(visibleTokens)
if err != nil {
return nil, err
}
visibleTokenJSONRaw := json.RawMessage(visibleTokensJSON)
settings.WalletVisibleTokens = &visibleTokenJSONRaw
// TODO: fix this
networks := make([]map[string]string, 0)
networksJSON, err := json.Marshal(networks)
if err != nil {
return nil, err
}
networkRawMessage := json.RawMessage(networksJSON)
settings.Networks = &networkRawMessage
settings.CurrentNetwork = "mainnet_rpc"
return settings, nil
}
func defaultNodeConfig(installationID string) (*params.NodeConfig, error) {
// Set mainnet
nodeConfig := &params.NodeConfig{}
nodeConfig.NetworkID = 1
nodeConfig.LogLevel = "ERROR"
nodeConfig.DataDir = "/ethereum/mainnet_rpc"
nodeConfig.UpstreamConfig = params.UpstreamRPCConfig{
Enabled: true,
URL: "https://mainnet.infura.io/v3/800c641949d64d768a5070a1b0511938",
}
nodeConfig.Name = "StatusIM"
nodeConfig.Rendezvous = true
clusterConfig, err := params.LoadClusterConfigFromFleet("eth.prod")
if err != nil {
return nil, err
}
nodeConfig.ClusterConfig = *clusterConfig
nodeConfig.WalletConfig = params.WalletConfig{Enabled: true}
nodeConfig.LocalNotificationsConfig = params.LocalNotificationsConfig{Enabled: true}
nodeConfig.BrowsersConfig = params.BrowsersConfig{Enabled: true}
nodeConfig.PermissionsConfig = params.PermissionsConfig{Enabled: true}
nodeConfig.MailserversConfig = params.MailserversConfig{Enabled: true}
nodeConfig.EnableNTPSync = true
nodeConfig.WakuConfig = params.WakuConfig{
Enabled: true,
LightClient: true,
MinimumPoW: 0.000001,
}
nodeConfig.ShhextConfig = params.ShhextConfig{
BackupDisabledDataDir: "",
InstallationID: installationID,
MaxMessageDeliveryAttempts: 6,
MailServerConfirmations: true,
VerifyTransactionURL: "",
VerifyENSURL: "",
VerifyENSContractAddress: "",
VerifyTransactionChainID: 1,
DataSyncEnabled: true,
PFSEnabled: true,
}
// TODO: check topics
return nodeConfig, nil
}
func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error {
backend.UpdateRootDataDir("./tmp")
manager := backend.AccountManager()
manager.InitKeystore("./tmp")
err := backend.OpenAccounts()
if err != nil {
return err
}
generator := manager.AccountsGenerator()
generatedAccountInfo, err := generator.ImportMnemonic(seedPhrase, "")
if err != nil {
return err
}
derivedAddresses, err := generator.DeriveAddresses(generatedAccountInfo.ID, paths)
if err != nil {
return err
}
_, err = generator.StoreDerivedAccounts(generatedAccountInfo.ID, "", paths)
if err != nil {
return err
}
account := multiaccounts.Account{
KeyUID: generatedAccountInfo.KeyUID,
}
settings, err := defaultSettings(generatedAccountInfo, derivedAddresses, &seedPhrase)
if err != nil {
return err
}
nodeConfig, err := defaultNodeConfig(settings.InstallationID)
if err != nil {
return err
}
walletDerivedAccount := derivedAddresses[pathDefaultWallet]
walletAccount := accounts.Account{
PublicKey: types.Hex2Bytes(walletDerivedAccount.PublicKey),
Address: types.HexToAddress(walletDerivedAccount.Address),
Color: "",
Wallet: true,
Path: pathDefaultWallet,
Name: "Ethereum account",
}
chatDerivedAccount := derivedAddresses[pathDefaultChat]
chatAccount := accounts.Account{
PublicKey: types.Hex2Bytes(chatDerivedAccount.PublicKey),
Address: types.HexToAddress(chatDerivedAccount.Address),
Name: settings.Name,
Chat: true,
Path: pathDefaultChat,
}
accounts := []accounts.Account{walletAccount, chatAccount}
return backend.StartNodeWithAccountAndConfig(account, "", *settings, nodeConfig, accounts)
}
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func buildMessage(chat *protocol.Chat, count int) *common.Message {
key, err := crypto.GenerateKey()
if err != nil {
logger.Error("failed", err)
return nil
}
clock, timestamp := chat.NextClockAndTimestamp(&testTimeSource{})
message := &common.Message{}
message.Text = fmt.Sprintf("test message %d", count)
message.ChatId = chat.ID
message.Clock = clock
message.Timestamp = timestamp
message.From = common.PubkeyToHex(&key.PublicKey)
data := []byte(uuid.New().String())
message.ID = types.HexBytes(crypto.Keccak256(data)).String()
message.WhisperTimestamp = clock
message.LocalChatID = chat.ID
message.ContentType = protobuf.ChatMessage_TEXT_PLAIN
switch chat.ChatType {
case protocol.ChatTypePublic, protocol.ChatTypeProfile:
message.MessageType = protobuf.MessageType_PUBLIC_GROUP
case protocol.ChatTypeOneToOne:
message.MessageType = protobuf.MessageType_ONE_TO_ONE
case protocol.ChatTypePrivateGroupChat:
message.MessageType = protobuf.MessageType_PRIVATE_GROUP
}
message.PrepareContent("")
return message
}
func randomString(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}

View file

@ -0,0 +1,650 @@
package main
import (
"crypto/rand"
"math/big"
)
func buildSigningPhrase() (string, error) {
length := big.NewInt(int64(len(dictionary)))
a, err := rand.Int(rand.Reader, length)
if err != nil {
return "", err
}
b, err := rand.Int(rand.Reader, length)
if err != nil {
return "", err
}
c, err := rand.Int(rand.Reader, length)
if err != nil {
return "", err
}
return dictionary[a.Int64()] + " " + dictionary[b.Int64()] + " " + dictionary[c.Int64()], nil
}
var dictionary = []string{
"acid",
"alto",
"apse",
"arch",
"area",
"army",
"atom",
"aunt",
"babe",
"baby",
"back",
"bail",
"bait",
"bake",
"ball",
"band",
"bank",
"barn",
"base",
"bass",
"bath",
"bead",
"beak",
"beam",
"bean",
"bear",
"beat",
"beef",
"beer",
"beet",
"bell",
"belt",
"bend",
"bike",
"bill",
"bird",
"bite",
"blow",
"blue",
"boar",
"boat",
"body",
"bolt",
"bomb",
"bone",
"book",
"boot",
"bore",
"boss",
"bowl",
"brow",
"bulb",
"bull",
"burn",
"bush",
"bust",
"cafe",
"cake",
"calf",
"call",
"calm",
"camp",
"cane",
"cape",
"card",
"care",
"carp",
"cart",
"case",
"cash",
"cast",
"cave",
"cell",
"cent",
"chap",
"chef",
"chin",
"chip",
"chop",
"chub",
"chug",
"city",
"clam",
"clef",
"clip",
"club",
"clue",
"coal",
"coat",
"code",
"coil",
"coin",
"coke",
"cold",
"colt",
"comb",
"cone",
"cook",
"cope",
"copy",
"cord",
"cork",
"corn",
"cost",
"crab",
"craw",
"crew",
"crib",
"crop",
"crow",
"curl",
"cyst",
"dame",
"dare",
"dark",
"dart",
"dash",
"data",
"date",
"dead",
"deal",
"dear",
"debt",
"deck",
"deep",
"deer",
"desk",
"dhow",
"diet",
"dill",
"dime",
"dirt",
"dish",
"disk",
"dock",
"doll",
"door",
"dory",
"drag",
"draw",
"drop",
"drug",
"drum",
"duck",
"dump",
"dust",
"duty",
"ease",
"east",
"eave",
"eddy",
"edge",
"envy",
"epee",
"exam",
"exit",
"face",
"fact",
"fail",
"fall",
"fame",
"fang",
"farm",
"fawn",
"fear",
"feed",
"feel",
"feet",
"file",
"fill",
"film",
"find",
"fine",
"fire",
"fish",
"flag",
"flat",
"flax",
"flow",
"foam",
"fold",
"font",
"food",
"foot",
"fork",
"form",
"fort",
"fowl",
"frog",
"fuel",
"full",
"gain",
"gale",
"galn",
"game",
"garb",
"gate",
"gear",
"gene",
"gift",
"girl",
"give",
"glad",
"glen",
"glue",
"glut",
"goal",
"goat",
"gold",
"golf",
"gong",
"good",
"gown",
"grab",
"gram",
"gray",
"grey",
"grip",
"grit",
"gyro",
"hail",
"hair",
"half",
"hall",
"hand",
"hang",
"harm",
"harp",
"hate",
"hawk",
"head",
"heat",
"heel",
"hell",
"helo",
"help",
"hemp",
"herb",
"hide",
"high",
"hill",
"hire",
"hive",
"hold",
"hole",
"home",
"hood",
"hoof",
"hook",
"hope",
"hops",
"horn",
"hose",
"host",
"hour",
"hunt",
"hurt",
"icon",
"idea",
"inch",
"iris",
"iron",
"item",
"jail",
"jeep",
"jeff",
"joey",
"join",
"joke",
"judo",
"jump",
"junk",
"jury",
"jute",
"kale",
"keep",
"kick",
"kill",
"kilt",
"kind",
"king",
"kiss",
"kite",
"knee",
"knot",
"lace",
"lack",
"lady",
"lake",
"lamb",
"lamp",
"land",
"lark",
"lava",
"lawn",
"lead",
"leaf",
"leek",
"lier",
"life",
"lift",
"lily",
"limo",
"line",
"link",
"lion",
"lisa",
"list",
"load",
"loaf",
"loan",
"lock",
"loft",
"long",
"look",
"loss",
"lout",
"love",
"luck",
"lung",
"lute",
"lynx",
"lyre",
"maid",
"mail",
"main",
"make",
"male",
"mall",
"manx",
"many",
"mare",
"mark",
"mask",
"mass",
"mate",
"math",
"meal",
"meat",
"meet",
"menu",
"mess",
"mice",
"midi",
"mile",
"milk",
"mime",
"mind",
"mine",
"mini",
"mint",
"miss",
"mist",
"moat",
"mode",
"mole",
"mood",
"moon",
"most",
"moth",
"move",
"mule",
"mutt",
"nail",
"name",
"neat",
"neck",
"need",
"neon",
"nest",
"news",
"node",
"nose",
"note",
"oboe",
"okra",
"open",
"oval",
"oven",
"oxen",
"pace",
"pack",
"page",
"pail",
"pain",
"pair",
"palm",
"pard",
"park",
"part",
"pass",
"past",
"path",
"peak",
"pear",
"peen",
"peer",
"pelt",
"perp",
"pest",
"pick",
"pier",
"pike",
"pile",
"pimp",
"pine",
"ping",
"pink",
"pint",
"pipe",
"piss",
"pith",
"plan",
"play",
"plot",
"plow",
"poem",
"poet",
"pole",
"polo",
"pond",
"pony",
"poof",
"pool",
"port",
"post",
"prow",
"pull",
"puma",
"pump",
"pupa",
"push",
"quit",
"race",
"rack",
"raft",
"rage",
"rail",
"rain",
"rake",
"rank",
"rate",
"read",
"rear",
"reef",
"rent",
"rest",
"rice",
"rich",
"ride",
"ring",
"rise",
"risk",
"road",
"robe",
"rock",
"role",
"roll",
"roof",
"room",
"root",
"rope",
"rose",
"ruin",
"rule",
"rush",
"ruth",
"sack",
"safe",
"sage",
"sail",
"sale",
"salt",
"sand",
"sari",
"sash",
"save",
"scow",
"seal",
"seat",
"seed",
"self",
"sell",
"shed",
"shin",
"ship",
"shoe",
"shop",
"shot",
"show",
"sick",
"side",
"sign",
"silk",
"sill",
"silo",
"sing",
"sink",
"site",
"size",
"skin",
"sled",
"slip",
"smog",
"snob",
"snow",
"soap",
"sock",
"soda",
"sofa",
"soft",
"soil",
"song",
"soot",
"sort",
"soup",
"spot",
"spur",
"stag",
"star",
"stay",
"stem",
"step",
"stew",
"stop",
"stud",
"suck",
"suit",
"swan",
"swim",
"tail",
"tale",
"talk",
"tank",
"tard",
"task",
"taxi",
"team",
"tear",
"teen",
"tell",
"temp",
"tent",
"term",
"test",
"text",
"thaw",
"tile",
"till",
"time",
"tire",
"toad",
"toga",
"togs",
"tone",
"tool",
"toot",
"tote",
"tour",
"town",
"tram",
"tray",
"tree",
"trim",
"trip",
"tuba",
"tube",
"tuna",
"tune",
"turn",
"tutu",
"twig",
"type",
"unit",
"user",
"vane",
"vase",
"vast",
"veal",
"veil",
"vein",
"vest",
"vibe",
"view",
"vise",
"wait",
"wake",
"walk",
"wall",
"wash",
"wasp",
"wave",
"wear",
"weed",
"week",
"well",
"west",
"whip",
"wife",
"will",
"wind",
"wine",
"wing",
"wire",
"wish",
"wolf",
"wood",
"wool",
"word",
"work",
"worm",
"wrap",
"wren",
"yard",
"yarn",
"yawl",
"year",
"yoga",
"yoke",
"yurt",
"zinc",
"zone",
}

54
cmd/populate-db/sync.go Normal file
View file

@ -0,0 +1,54 @@
package main
import (
"context"
"time"
"github.com/status-im/status-go/node"
)
func createContextFromTimeout(timeout int) (context.Context, context.CancelFunc) {
if timeout == 0 {
return context.WithCancel(context.Background())
}
return context.WithTimeout(context.Background(), time.Duration(timeout)*time.Minute)
}
// syncAndStopNode tries to sync the blockchain and stop the node.
// It returns an exit code (`0` if successful or `1` in case of error)
// that can be used in `os.Exit` to exit immediately when the function returns.
// The special exit code `-1` is used if execution was interrupted.
func syncAndStopNode(interruptCh <-chan struct{}, statusNode *node.StatusNode, timeout int) (exitCode int) {
logger.Info("syncAndStopNode: node will synchronize the chain and exit", "timeoutInMins", timeout)
ctx, cancel := createContextFromTimeout(timeout)
defer cancel()
doneSync := make(chan struct{})
errSync := make(chan error)
go func() {
if err := statusNode.EnsureSync(ctx); err != nil {
errSync <- err
}
close(doneSync)
}()
select {
case err := <-errSync:
logger.Error("syncAndStopNode: failed to sync the chain", "error", err)
exitCode = 1
case <-doneSync:
case <-interruptCh:
// cancel context and return immediately if interrupted
// `-1` is used as a special exit code to denote interruption
return -1
}
if err := statusNode.Stop(); err != nil {
logger.Error("syncAndStopNode: failed to stop the node", "error", err)
return 1
}
return
}

View file

@ -302,6 +302,10 @@ func (api *PublicAPI) SaveChat(parent context.Context, chat *protocol.Chat) erro
return api.service.messenger.SaveChat(chat)
}
func (api *PublicAPI) SaveMessages(parent context.Context, messages []*common.Message) error {
return api.service.messenger.SaveMessages(messages)
}
func (api *PublicAPI) CreateOneToOneChat(parent context.Context, request *requests.CreateOneToOneChat) (*protocol.MessengerResponse, error) {
return api.service.messenger.CreateOneToOneChat(request)
}