From 8fba6e032b2e1b4a805526c57c2c1b72f3c469a0 Mon Sep 17 00:00:00 2001 From: Warren He Date: Wed, 18 Dec 2019 17:11:55 -0800 Subject: [PATCH 01/12] go oasis-test-runner: non-default scenarios --- go/oasis-test-runner/cmd/root.go | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/go/oasis-test-runner/cmd/root.go b/go/oasis-test-runner/cmd/root.go index f84bfe4e0cf..a7dec2788e0 100644 --- a/go/oasis-test-runner/cmd/root.go +++ b/go/oasis-test-runner/cmd/root.go @@ -49,8 +49,9 @@ var ( cfgFile string - scenarioMap = make(map[string]scenario.Scenario) - scenarios []scenario.Scenario + scenarioMap = make(map[string]scenario.Scenario) + defaultScenarios []scenario.Scenario + scenarios []scenario.Scenario ) // RootCmd returns the root command's structure that will be executed, so that @@ -69,8 +70,8 @@ func Execute() { } } -// Register adds a scenario to the runner. -func Register(scenario scenario.Scenario) error { +// RegisterNondefault adds a scenario to the runner. +func RegisterNondefault(scenario scenario.Scenario) error { n := strings.ToLower(scenario.Name()) if _, ok := scenarioMap[n]; ok { return errors.New("root: scenario already registered: " + n) @@ -81,6 +82,16 @@ func Register(scenario scenario.Scenario) error { return nil } +// Register adds a scenario to the runner and the default scenarios list. +func Register(scenario scenario.Scenario) error { + if err := RegisterNondefault(scenario); err != nil { + return err + } + + defaultScenarios = append(defaultScenarios, scenario) + return nil +} + func initRootEnv(cmd *cobra.Command) (*env.Env, error) { // Initialize the root dir. rootDir := env.GetRootDir() @@ -137,7 +148,7 @@ func runRoot(cmd *cobra.Command, args []string) error { logger := logging.GetLogger("test-runner") // Enumerate the requested test cases. - toRun := scenarios // Default to everything. + toRun := defaultScenarios // Run all default scenarios if not set. if vec := viper.GetStringSlice(cfgTest); len(vec) > 0 { toRun = nil for _, v := range vec { From 709894b6c993087fbffc9e08260c3f97704ba250 Mon Sep 17 00:00:00 2001 From: Warren He Date: Mon, 16 Dec 2019 17:10:38 -0800 Subject: [PATCH 02/12] go: add txsource --- go/oasis-node/cmd/debug/debug.go | 2 + .../cmd/debug/txsource/transferworkload.go | 128 ++++++++++++++++++ go/oasis-node/cmd/debug/txsource/txsource.go | 109 +++++++++++++++ go/oasis-test-runner/scenario/e2e/txsource.go | 53 ++++++++ go/oasis-test-runner/test-runner.go | 2 + scripts/run-e2e-txsource.sh | 10 ++ scripts/txsource-wrapper.sh | 26 ++++ .../txsource/staking-genesis.json | 15 ++ 8 files changed, 345 insertions(+) create mode 100644 go/oasis-node/cmd/debug/txsource/transferworkload.go create mode 100644 go/oasis-node/cmd/debug/txsource/txsource.go create mode 100644 go/oasis-test-runner/scenario/e2e/txsource.go create mode 100755 scripts/run-e2e-txsource.sh create mode 100755 scripts/txsource-wrapper.sh create mode 100644 tests/fixture-data/txsource/staking-genesis.json diff --git a/go/oasis-node/cmd/debug/debug.go b/go/oasis-node/cmd/debug/debug.go index da459f06ac7..eae5dcdd5d2 100644 --- a/go/oasis-node/cmd/debug/debug.go +++ b/go/oasis-node/cmd/debug/debug.go @@ -7,6 +7,7 @@ import ( "github.com/oasislabs/oasis-core/go/oasis-node/cmd/debug/byzantine" "github.com/oasislabs/oasis-core/go/oasis-node/cmd/debug/storage" "github.com/oasislabs/oasis-core/go/oasis-node/cmd/debug/tendermint" + "github.com/oasislabs/oasis-core/go/oasis-node/cmd/debug/txsource" ) var debugCmd = &cobra.Command{ @@ -19,6 +20,7 @@ func Register(parentCmd *cobra.Command) { storage.Register(debugCmd) tendermint.Register(debugCmd) byzantine.Register(debugCmd) + txsource.Register(debugCmd) parentCmd.AddCommand(debugCmd) } diff --git a/go/oasis-node/cmd/debug/txsource/transferworkload.go b/go/oasis-node/cmd/debug/txsource/transferworkload.go new file mode 100644 index 00000000000..9d56dd2c73f --- /dev/null +++ b/go/oasis-node/cmd/debug/txsource/transferworkload.go @@ -0,0 +1,128 @@ +package txsource + +import ( + "context" + "fmt" + "math/rand" + + "google.golang.org/grpc" + + "github.com/oasislabs/oasis-core/go/common/crypto/signature" + memorySigner "github.com/oasislabs/oasis-core/go/common/crypto/signature/signers/memory" + "github.com/oasislabs/oasis-core/go/common/quantity" + consensus "github.com/oasislabs/oasis-core/go/consensus/api" + "github.com/oasislabs/oasis-core/go/consensus/api/transaction" + runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" + staking "github.com/oasislabs/oasis-core/go/staking/api" +) + +const ( + NumAccounts = 10 + TransferAmount = 1 +) + +func workloadTransfer(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error { + // Load all the keys up front. Like, how annoyed would you be if down the line one of them turned out to be + // corrupted or something, ya know? + accounts := make([]struct { + signer signature.Signer + reckonedNonce uint64 + reckonedBalance quantity.Quantity + }, NumAccounts) + var err error + fac := memorySigner.NewFactory() + for i := range accounts { + accounts[i].signer, err = fac.Generate(signature.SignerEntity, rng) + if err != nil { + return fmt.Errorf("memory signer factory Generate account %d: %w", i, err) + } + } + + // Read all the account info up front. + ctx := context.Background() + stakingClient := staking.NewStakingClient(conn) + for i := range accounts { + var account *staking.Account + account, err = stakingClient.AccountInfo(ctx, &staking.OwnerQuery{ + Height: 0, + Owner: accounts[i].signer.Public(), + }) + if err != nil { + return fmt.Errorf("stakingClient.AccountInfo %s: %w", accounts[i].signer.Public(), err) + } + logger.Debug("account info", + "i", i, + "pub", accounts[i].signer.Public(), + "info", account, + ) + accounts[i].reckonedNonce = account.General.Nonce + accounts[i].reckonedBalance = account.General.Balance + } + + fee := transaction.Fee{ + Gas: 10, + } + var minBalance quantity.Quantity + if err = minBalance.FromInt64(TransferAmount); err != nil { + return fmt.Errorf("min balance FromInt64 %d: %w", TransferAmount, err) + } + if err = minBalance.Add(&fee.Amount); err != nil { + return fmt.Errorf("min balance %v Add fee amount %v: %w", minBalance, fee.Amount, err) + } + for { + perm := rng.Perm(NumAccounts) + fromPermIdx := 0 + for ; fromPermIdx < NumAccounts; fromPermIdx++ { + if accounts[perm[fromPermIdx]].reckonedBalance.Cmp(&minBalance) >= 0 { + break + } + } + if fromPermIdx >= NumAccounts { + return fmt.Errorf("all accounts %#v have gone broke", accounts) + } + toPermIdx := (fromPermIdx + 1) % NumAccounts + from := &accounts[perm[fromPermIdx]] + to := &accounts[perm[toPermIdx]] + + transfer := staking.Transfer{ + To: to.signer.Public(), + } + if err = transfer.Tokens.FromInt64(TransferAmount); err != nil { + return fmt.Errorf("transfer tokens FromInt64 %d: %w", TransferAmount, err) + } + tx := staking.NewTransferTx(from.reckonedNonce, &fee, &transfer) + signedTx, err := transaction.Sign(from.signer, tx) + if err != nil { + return fmt.Errorf("transaction.Sign: %w", err) + } + logger.Debug("submitting transfer", + "from", from.signer.Public(), + "to", to.signer.Public(), + ) + if err = cnsc.SubmitTx(ctx, signedTx); err != nil { + return fmt.Errorf("cnsc.SubmitTx: %w", err) + } + from.reckonedNonce++ + if err = from.reckonedBalance.Sub(&fee.Amount); err != nil { + return fmt.Errorf("from reckoned balance %v Sub fee amount %v: %w", from.reckonedBalance, fee.Amount, err) + } + if err = from.reckonedBalance.Sub(&transfer.Tokens); err != nil { + return fmt.Errorf("from reckoned balance %v Sub transfer tokens %v: %w", from.reckonedBalance, transfer.Tokens, err) + } + if err = to.reckonedBalance.Add(&transfer.Tokens); err != nil { + return fmt.Errorf("to reckoned balance %v Add transfer tokens %v: %w", to.reckonedBalance, transfer.Tokens, err) + } + } +} + +func _(_ *rand.Rand, _ consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error { + ctx := context.Background() + var tx *runtimeClient.SubmitTxRequest + // Placeholder for sending a runtime transaction from a workload. + out, err := rtc.SubmitTx(ctx, tx) + if err != nil { + return fmt.Errorf("rtc.SubmitTx: %w", err) + } + logger.Debug("output", "out", out) + return nil +} diff --git a/go/oasis-node/cmd/debug/txsource/txsource.go b/go/oasis-node/cmd/debug/txsource/txsource.go new file mode 100644 index 00000000000..a5f3b0376b4 --- /dev/null +++ b/go/oasis-node/cmd/debug/txsource/txsource.go @@ -0,0 +1,109 @@ +package txsource + +import ( + "context" + "crypto" + "fmt" + "math/rand" + + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "github.com/spf13/viper" + + "github.com/oasislabs/oasis-core/go/common/crypto/drbg" + "github.com/oasislabs/oasis-core/go/common/crypto/mathrand" + "github.com/oasislabs/oasis-core/go/common/logging" + consensus "github.com/oasislabs/oasis-core/go/consensus/api" + "github.com/oasislabs/oasis-core/go/control/api" + genesisFile "github.com/oasislabs/oasis-core/go/genesis/file" + "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common" + cmdFlags "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common/flags" + cmdGrpc "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common/grpc" + runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" +) + +const CfgSeed = "seed" + +var ( + logger = logging.GetLogger("cmd/txsource") + txsourceCmd = &cobra.Command{ + Use: "txsource", + Short: "send random transactions", + RunE: doRun, + } +) + +func doRun(cmd *cobra.Command, args []string) error { + cmd.SilenceUsage = true + + if err := common.Init(); err != nil { + common.EarlyLogAndExit(err) + } + + // Set up the genesis system for the signature system's chain context. + genesis, err := genesisFile.DefaultFileProvider() + if err != nil { + return fmt.Errorf("genesisFile.DefaultFileProvider: %w", err) + } + genesisDoc, err := genesis.GetGenesisDocument() + if err != nil { + return fmt.Errorf("genesis.GetGenesisDocument: %w", err) + } + logger.Debug("setting chain context", "chain_context", genesisDoc.ChainContext()) + genesisDoc.SetChainContext() + + // Set up the deterministic random source. + hash := crypto.SHA512 + seed := []byte(viper.GetString(CfgSeed)) + src, err := drbg.New(hash, seed, nil, []byte("txsource workload generator v1")) + if err != nil { + return fmt.Errorf("drbg.New: %w", err) + } + rng := rand.New(mathrand.New(src)) + + // Set up the gRPC client. + logger.Debug("dialing node", "addr", viper.GetString(cmdGrpc.CfgAddress)) + conn, err := cmdGrpc.NewClient(cmd) + if err != nil { + return fmt.Errorf("cmdGrpc.NewClient: %w", err) + } + defer conn.Close() + + // Set up the consensus client. + cnsc := consensus.NewConsensusClient(conn) + + // Set up the runtime client. + rtc := runtimeClient.NewRuntimeClient(conn) + + // Wait for sync before transferring control to the workload. + ncc := api.NewNodeControllerClient(conn) + logger.Debug("waiting for node sync") + if err = ncc.WaitSync(context.Background()); err != nil { + return fmt.Errorf("node controller client WaitSync: %w", err) + } + logger.Debug("node synced") + + logger.Debug("entering workload") + if err = workloadTransfer(rng, conn, cnsc, rtc); err != nil { + return fmt.Errorf("workload: %w", err) + } + logger.Debug("workload returned") + + return nil +} + +func Register(parentCmd *cobra.Command) { + parentCmd.AddCommand(txsourceCmd) +} + +func init() { + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.String(CfgSeed, "seeeeeeeeeeeeeeeeeeeeeeeeeeeeeed", "Seed to use for randomized workloads") + _ = viper.BindPFlags(fs) + txsourceCmd.Flags().AddFlagSet(fs) + + txsourceCmd.Flags().AddFlagSet(cmdGrpc.ClientFlags) + txsourceCmd.Flags().AddFlagSet(cmdFlags.DebugTestEntityFlags) + txsourceCmd.Flags().AddFlagSet(cmdFlags.GenesisFileFlags) + txsourceCmd.Flags().AddFlagSet(cmdFlags.DebugDontBlameOasisFlag) +} diff --git a/go/oasis-test-runner/scenario/e2e/txsource.go b/go/oasis-test-runner/scenario/e2e/txsource.go new file mode 100644 index 00000000000..354c9282a6d --- /dev/null +++ b/go/oasis-test-runner/scenario/e2e/txsource.go @@ -0,0 +1,53 @@ +package e2e + +import ( + "fmt" + + "github.com/oasislabs/oasis-core/go/oasis-test-runner/env" + "github.com/oasislabs/oasis-core/go/oasis-test-runner/oasis" + "github.com/oasislabs/oasis-core/go/oasis-test-runner/scenario" +) + +var TxSource scenario.Scenario = &txSourceImpl{basicImpl{ + name: "txsource", + clientBinary: "txsource-wrapper.sh", +}} + +type txSourceImpl struct { + basicImpl +} + +func (sc *txSourceImpl) Fixture() (*oasis.NetworkFixture, error) { + f, err := sc.basicImpl.Fixture() + if err != nil { + return nil, err + } + f.Network.StakingGenesis = "tests/fixture-data/txsource/staking-genesis.json" + + return f, nil +} + +func (sc *txSourceImpl) Init(childEnv *env.Env, net *oasis.Network) error { + sc.net = net + return nil +} + +func (sc *txSourceImpl) Run(childEnv *env.Env) error { + if err := sc.net.Start(); err != nil { + return fmt.Errorf("scenario net Start: %w", err) + } + + cmd, err := startClient(childEnv, sc.net, sc.clientBinary, append([]string{ + "--genesis-path", sc.net.GenesisPath(), + }, sc.clientArgs...)) + if err != nil { + return fmt.Errorf("startClient: %w", err) + } + + clientErrCh := make(chan error) + go func() { + clientErrCh <- cmd.Wait() + }() + + return sc.wait(childEnv, cmd, clientErrCh) +} diff --git a/go/oasis-test-runner/test-runner.go b/go/oasis-test-runner/test-runner.go index 2dedb708557..1a3a4ed1400 100644 --- a/go/oasis-test-runner/test-runner.go +++ b/go/oasis-test-runner/test-runner.go @@ -51,6 +51,8 @@ func main() { _ = cmd.Register(e2e.IdentityCLI) // Runtime prune test. _ = cmd.Register(e2e.RuntimePrune) + // Transaction source test. + _ = cmd.RegisterNondefault(e2e.TxSource) // Execute the command, now that everything has been initialized. cmd.Execute() diff --git a/scripts/run-e2e-txsource.sh b/scripts/run-e2e-txsource.sh new file mode 100755 index 00000000000..3f75b15c138 --- /dev/null +++ b/scripts/run-e2e-txsource.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# (no merge) +./go/oasis-test-runner/oasis-test-runner \ + --basedir.no_cleanup \ + --e2e.node.binary go/oasis-node/oasis-node \ + --e2e.client.binary_dir scripts \ + --e2e.runtime.binary_dir target/debug \ + --e2e.runtime.loader target/debug/oasis-core-runtime-loader \ + --log.level info \ + -t txsource diff --git a/scripts/txsource-wrapper.sh b/scripts/txsource-wrapper.sh new file mode 100755 index 00000000000..f7cc00cdff5 --- /dev/null +++ b/scripts/txsource-wrapper.sh @@ -0,0 +1,26 @@ +#!/bin/sh -eu + +usage() { + echo >&2 "usage: $0 --node-address --runtime-id --genesis-path " + exit 1 +} + +if [ "$1" = "--node-address" ]; then + node_address=$2 +else + usage +fi +if [ "$5" = "--genesis-path" ]; then + genesis_path=$6 +else + usage +fi + +exec ./go/oasis-node/oasis-node debug txsource \ + --address "$node_address" \ + --debug.allow_test_keys \ + --debug.dont_blame_oasis \ + --debug.test_entity \ + --genesis.file "$genesis_path" \ + --log.format JSON \ + --log.level DEBUG diff --git a/tests/fixture-data/txsource/staking-genesis.json b/tests/fixture-data/txsource/staking-genesis.json new file mode 100644 index 00000000000..df48d1e4fc3 --- /dev/null +++ b/tests/fixture-data/txsource/staking-genesis.json @@ -0,0 +1,15 @@ +{ + "total_supply": "1000", + "ledger": { + "qihOAOzylETIN28lq+XmtKSFmTiEo3NKfHXHnjrV0rA=": {"general": {"balance": "100"}}, + "bOnQrjMOkH9k3tgRy+zJYvYsPGxAOAr+heQNwuCkxQs=": {"general": {"balance": "100"}}, + "MY5gEDGOVhG2JkvJqLtuFzEyLBXOwnwPRZSmd1ljCdg=": {"general": {"balance": "100"}}, + "4ohqzsjinLP+HE8Jh1HmvBPgbWfOolAoBRfs5D5IC0A=": {"general": {"balance": "100"}}, + "5EOJGxu1d6BSvH95BxWPSl0cAy270+JpHMhIvdBjbWc=": {"general": {"balance": "100"}}, + "Y9b7wxlaXDmqaFNg2B6xTCcyTefHm9yEVXnTL+/C3kA=": {"general": {"balance": "100"}}, + "CqvWofjPCXbJdxAdxmFtiZ2AMb/fH+UxGYHymO28ppU=": {"general": {"balance": "100"}}, + "IJrjaBnQqXVtylLKiI70VjOIyV/Dk3zWsxIrz8ovha4=": {"general": {"balance": "100"}}, + "7hJlJ4x1dcqxCV0bGO8iTCPMucXHLcj5JeGBnTn7dQ4=": {"general": {"balance": "100"}}, + "Q16jPsco2bGCiacAlffWSHsDaMG0UBWv+FajU3c3MXg=": {"general": {"balance": "100"}} + } +} From a8f2004c386962abc842c7c55f9faf58046fa983 Mon Sep 17 00:00:00 2001 From: Warren He Date: Mon, 23 Dec 2019 13:56:40 -0800 Subject: [PATCH 03/12] go txsource: move workloads to a package --- go/oasis-node/cmd/debug/txsource/txsource.go | 3 ++- .../txsource/{transferworkload.go => workload/transfer.go} | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) rename go/oasis-node/cmd/debug/txsource/{transferworkload.go => workload/transfer.go} (95%) diff --git a/go/oasis-node/cmd/debug/txsource/txsource.go b/go/oasis-node/cmd/debug/txsource/txsource.go index a5f3b0376b4..b61c10d47a8 100644 --- a/go/oasis-node/cmd/debug/txsource/txsource.go +++ b/go/oasis-node/cmd/debug/txsource/txsource.go @@ -19,6 +19,7 @@ import ( "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common" cmdFlags "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common/flags" cmdGrpc "github.com/oasislabs/oasis-core/go/oasis-node/cmd/common/grpc" + "github.com/oasislabs/oasis-core/go/oasis-node/cmd/debug/txsource/workload" runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" ) @@ -84,7 +85,7 @@ func doRun(cmd *cobra.Command, args []string) error { logger.Debug("node synced") logger.Debug("entering workload") - if err = workloadTransfer(rng, conn, cnsc, rtc); err != nil { + if err = workload.WorkloadTransfer(rng, conn, cnsc, rtc); err != nil { return fmt.Errorf("workload: %w", err) } logger.Debug("workload returned") diff --git a/go/oasis-node/cmd/debug/txsource/transferworkload.go b/go/oasis-node/cmd/debug/txsource/workload/transfer.go similarity index 95% rename from go/oasis-node/cmd/debug/txsource/transferworkload.go rename to go/oasis-node/cmd/debug/txsource/workload/transfer.go index 9d56dd2c73f..39d7bf1d210 100644 --- a/go/oasis-node/cmd/debug/txsource/transferworkload.go +++ b/go/oasis-node/cmd/debug/txsource/workload/transfer.go @@ -1,4 +1,4 @@ -package txsource +package workload import ( "context" @@ -9,6 +9,7 @@ import ( "github.com/oasislabs/oasis-core/go/common/crypto/signature" memorySigner "github.com/oasislabs/oasis-core/go/common/crypto/signature/signers/memory" + "github.com/oasislabs/oasis-core/go/common/logging" "github.com/oasislabs/oasis-core/go/common/quantity" consensus "github.com/oasislabs/oasis-core/go/consensus/api" "github.com/oasislabs/oasis-core/go/consensus/api/transaction" @@ -21,7 +22,9 @@ const ( TransferAmount = 1 ) -func workloadTransfer(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error { +var logger = logging.GetLogger("cmd/txsource/workload/transfer") + +func WorkloadTransfer(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error { // Load all the keys up front. Like, how annoyed would you be if down the line one of them turned out to be // corrupted or something, ya know? accounts := make([]struct { From 3f7c6fec0639678c6a1cb0b24ae0a371ac2e5460 Mon Sep 17 00:00:00 2001 From: Warren He Date: Mon, 23 Dec 2019 14:21:31 -0800 Subject: [PATCH 04/12] go txsource: split out workloads --- go/oasis-node/cmd/debug/txsource/txsource.go | 15 ++++++++-- .../cmd/debug/txsource/workload/junk.go | 26 +++++++++++++++++ .../cmd/debug/txsource/workload/transfer.go | 29 ++++++------------- .../cmd/debug/txsource/workload/workload.go | 16 ++++++++++ scripts/txsource-wrapper.sh | 1 + 5 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 go/oasis-node/cmd/debug/txsource/workload/junk.go create mode 100644 go/oasis-node/cmd/debug/txsource/workload/workload.go diff --git a/go/oasis-node/cmd/debug/txsource/txsource.go b/go/oasis-node/cmd/debug/txsource/txsource.go index b61c10d47a8..67408184f49 100644 --- a/go/oasis-node/cmd/debug/txsource/txsource.go +++ b/go/oasis-node/cmd/debug/txsource/txsource.go @@ -23,7 +23,10 @@ import ( runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" ) -const CfgSeed = "seed" +const ( + CfgWorkload = "workload" + CfgSeed = "seed" +) var ( logger = logging.GetLogger("cmd/txsource") @@ -53,6 +56,13 @@ func doRun(cmd *cobra.Command, args []string) error { logger.Debug("setting chain context", "chain_context", genesisDoc.ChainContext()) genesisDoc.SetChainContext() + // Resolve the workload. + name := viper.GetString(CfgWorkload) + runner, ok := workload.ByName[name] + if !ok { + return fmt.Errorf("workload %s not found", name) + } + // Set up the deterministic random source. hash := crypto.SHA512 seed := []byte(viper.GetString(CfgSeed)) @@ -85,7 +95,7 @@ func doRun(cmd *cobra.Command, args []string) error { logger.Debug("node synced") logger.Debug("entering workload") - if err = workload.WorkloadTransfer(rng, conn, cnsc, rtc); err != nil { + if err = runner(rng, conn, cnsc, rtc); err != nil { return fmt.Errorf("workload: %w", err) } logger.Debug("workload returned") @@ -99,6 +109,7 @@ func Register(parentCmd *cobra.Command) { func init() { fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.String(CfgWorkload, workload.NameTransfer, "Name of the workload to run (see source for listing)") fs.String(CfgSeed, "seeeeeeeeeeeeeeeeeeeeeeeeeeeeeed", "Seed to use for randomized workloads") _ = viper.BindPFlags(fs) txsourceCmd.Flags().AddFlagSet(fs) diff --git a/go/oasis-node/cmd/debug/txsource/workload/junk.go b/go/oasis-node/cmd/debug/txsource/workload/junk.go new file mode 100644 index 00000000000..8634c9e94d5 --- /dev/null +++ b/go/oasis-node/cmd/debug/txsource/workload/junk.go @@ -0,0 +1,26 @@ +package workload + +import ( + "context" + "fmt" + "math/rand" + + "google.golang.org/grpc" + + consensus "github.com/oasislabs/oasis-core/go/consensus/api" + runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" +) + +var _ Runner = runRuntimePlaceholder + +func runRuntimePlaceholder(_ *rand.Rand, _ *grpc.ClientConn, _ consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error { + ctx := context.Background() + var tx *runtimeClient.SubmitTxRequest + // Placeholder for sending a runtime transaction from a workload. + out, err := rtc.SubmitTx(ctx, tx) + if err != nil { + return fmt.Errorf("rtc.SubmitTx: %w", err) + } + logger.Debug("output", "out", out) + return nil +} diff --git a/go/oasis-node/cmd/debug/txsource/workload/transfer.go b/go/oasis-node/cmd/debug/txsource/workload/transfer.go index 39d7bf1d210..9f3238ed98a 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/transfer.go +++ b/go/oasis-node/cmd/debug/txsource/workload/transfer.go @@ -18,20 +18,21 @@ import ( ) const ( - NumAccounts = 10 - TransferAmount = 1 + NameTransfer = "transfer" + TransferNumAccounts = 10 + TransferAmount = 1 ) var logger = logging.GetLogger("cmd/txsource/workload/transfer") -func WorkloadTransfer(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error { +func runTransfer(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error { // Load all the keys up front. Like, how annoyed would you be if down the line one of them turned out to be // corrupted or something, ya know? accounts := make([]struct { signer signature.Signer reckonedNonce uint64 reckonedBalance quantity.Quantity - }, NumAccounts) + }, TransferNumAccounts) var err error fac := memorySigner.NewFactory() for i := range accounts { @@ -73,17 +74,17 @@ func WorkloadTransfer(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.Clie return fmt.Errorf("min balance %v Add fee amount %v: %w", minBalance, fee.Amount, err) } for { - perm := rng.Perm(NumAccounts) + perm := rng.Perm(TransferNumAccounts) fromPermIdx := 0 - for ; fromPermIdx < NumAccounts; fromPermIdx++ { + for ; fromPermIdx < TransferNumAccounts; fromPermIdx++ { if accounts[perm[fromPermIdx]].reckonedBalance.Cmp(&minBalance) >= 0 { break } } - if fromPermIdx >= NumAccounts { + if fromPermIdx >= TransferNumAccounts { return fmt.Errorf("all accounts %#v have gone broke", accounts) } - toPermIdx := (fromPermIdx + 1) % NumAccounts + toPermIdx := (fromPermIdx + 1) % TransferNumAccounts from := &accounts[perm[fromPermIdx]] to := &accounts[perm[toPermIdx]] @@ -117,15 +118,3 @@ func WorkloadTransfer(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.Clie } } } - -func _(_ *rand.Rand, _ consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error { - ctx := context.Background() - var tx *runtimeClient.SubmitTxRequest - // Placeholder for sending a runtime transaction from a workload. - out, err := rtc.SubmitTx(ctx, tx) - if err != nil { - return fmt.Errorf("rtc.SubmitTx: %w", err) - } - logger.Debug("output", "out", out) - return nil -} diff --git a/go/oasis-node/cmd/debug/txsource/workload/workload.go b/go/oasis-node/cmd/debug/txsource/workload/workload.go new file mode 100644 index 00000000000..8233e2f5083 --- /dev/null +++ b/go/oasis-node/cmd/debug/txsource/workload/workload.go @@ -0,0 +1,16 @@ +package workload + +import ( + "math/rand" + + "google.golang.org/grpc" + + consensus "github.com/oasislabs/oasis-core/go/consensus/api" + runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" +) + +type Runner func(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error + +var ByName = map[string]Runner{ + NameTransfer: runTransfer, +} diff --git a/scripts/txsource-wrapper.sh b/scripts/txsource-wrapper.sh index f7cc00cdff5..e0998af06b6 100755 --- a/scripts/txsource-wrapper.sh +++ b/scripts/txsource-wrapper.sh @@ -17,6 +17,7 @@ else fi exec ./go/oasis-node/oasis-node debug txsource \ + --workload transfer \ --address "$node_address" \ --debug.allow_test_keys \ --debug.dont_blame_oasis \ From 0fb4915b202ee6e6fbc9ebf351486f6029982ff9 Mon Sep 17 00:00:00 2001 From: Warren He Date: Mon, 23 Dec 2019 14:29:13 -0800 Subject: [PATCH 05/12] go txsource: tweak rng init with workload name --- go/oasis-node/cmd/debug/txsource/txsource.go | 2 +- .../txsource/staking-genesis.json | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/go/oasis-node/cmd/debug/txsource/txsource.go b/go/oasis-node/cmd/debug/txsource/txsource.go index 67408184f49..af2fc0250c1 100644 --- a/go/oasis-node/cmd/debug/txsource/txsource.go +++ b/go/oasis-node/cmd/debug/txsource/txsource.go @@ -66,7 +66,7 @@ func doRun(cmd *cobra.Command, args []string) error { // Set up the deterministic random source. hash := crypto.SHA512 seed := []byte(viper.GetString(CfgSeed)) - src, err := drbg.New(hash, seed, nil, []byte("txsource workload generator v1")) + src, err := drbg.New(hash, seed, nil, []byte(fmt.Sprintf("txsource workload generator v1, workload %s", name))) if err != nil { return fmt.Errorf("drbg.New: %w", err) } diff --git a/tests/fixture-data/txsource/staking-genesis.json b/tests/fixture-data/txsource/staking-genesis.json index df48d1e4fc3..2da8939b67b 100644 --- a/tests/fixture-data/txsource/staking-genesis.json +++ b/tests/fixture-data/txsource/staking-genesis.json @@ -1,15 +1,15 @@ { "total_supply": "1000", "ledger": { - "qihOAOzylETIN28lq+XmtKSFmTiEo3NKfHXHnjrV0rA=": {"general": {"balance": "100"}}, - "bOnQrjMOkH9k3tgRy+zJYvYsPGxAOAr+heQNwuCkxQs=": {"general": {"balance": "100"}}, - "MY5gEDGOVhG2JkvJqLtuFzEyLBXOwnwPRZSmd1ljCdg=": {"general": {"balance": "100"}}, - "4ohqzsjinLP+HE8Jh1HmvBPgbWfOolAoBRfs5D5IC0A=": {"general": {"balance": "100"}}, - "5EOJGxu1d6BSvH95BxWPSl0cAy270+JpHMhIvdBjbWc=": {"general": {"balance": "100"}}, - "Y9b7wxlaXDmqaFNg2B6xTCcyTefHm9yEVXnTL+/C3kA=": {"general": {"balance": "100"}}, - "CqvWofjPCXbJdxAdxmFtiZ2AMb/fH+UxGYHymO28ppU=": {"general": {"balance": "100"}}, - "IJrjaBnQqXVtylLKiI70VjOIyV/Dk3zWsxIrz8ovha4=": {"general": {"balance": "100"}}, - "7hJlJ4x1dcqxCV0bGO8iTCPMucXHLcj5JeGBnTn7dQ4=": {"general": {"balance": "100"}}, - "Q16jPsco2bGCiacAlffWSHsDaMG0UBWv+FajU3c3MXg=": {"general": {"balance": "100"}} + "R3CRgwIWQxvnxpl1qmBm2HMOapCgaGswjtleKwnpyxg=": {"general": {"balance": "100"}}, + "arDOJeLJ9wZpuWa5t7+O8UGmZOXXdKQkN6t8IKbSylE=": {"general": {"balance": "100"}}, + "THXr3BkLrlDt89pu3AyeiVGB9u4igSx1fuLIFX98BNI=": {"general": {"balance": "100"}}, + "aYzCAO60yhEH0CWIGgEy+qM4TdNB+Ak8kq9Y/mpzQLY=": {"general": {"balance": "100"}}, + "aYGCs2K/owoE+nqLbOMFA5xqSo0SaHlI5Oj1btUFohI=": {"general": {"balance": "100"}}, + "GMGUREz0YmNCLGEvoLDpfRLYBxq1HQx9jQNDK6/Oajc=": {"general": {"balance": "100"}}, + "UJBCV7QyXc3cFIUqDvUT18RxNTtIIwZ3s6lVdC1Zs/U=": {"general": {"balance": "100"}}, + "QsJ1u2WAJiSH0m+ExtL1cRrmyfdhCV8pidgowj2g9rY=": {"general": {"balance": "100"}}, + "9zPKp7jryXaToR806PyzByNy5LVTwnie3Y3dkCxh1oo=": {"general": {"balance": "100"}}, + "+mLNei3EG4jmo6RDjjU6d/FswfbHHNpR+Lz0EdSaINw=": {"general": {"balance": "100"}} } } From 5823b9db8f260b70f8dfe48b411e2ade67316b3f Mon Sep 17 00:00:00 2001 From: Warren He Date: Thu, 26 Dec 2019 12:08:44 -0800 Subject: [PATCH 06/12] go txsource: convert Runner to interface --- go/oasis-node/cmd/debug/txsource/txsource.go | 4 ++-- go/oasis-node/cmd/debug/txsource/workload/junk.go | 6 ++++-- go/oasis-node/cmd/debug/txsource/workload/transfer.go | 4 +++- go/oasis-node/cmd/debug/txsource/workload/workload.go | 8 +++++--- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/go/oasis-node/cmd/debug/txsource/txsource.go b/go/oasis-node/cmd/debug/txsource/txsource.go index af2fc0250c1..a5237189fbe 100644 --- a/go/oasis-node/cmd/debug/txsource/txsource.go +++ b/go/oasis-node/cmd/debug/txsource/txsource.go @@ -58,7 +58,7 @@ func doRun(cmd *cobra.Command, args []string) error { // Resolve the workload. name := viper.GetString(CfgWorkload) - runner, ok := workload.ByName[name] + w, ok := workload.ByName[name] if !ok { return fmt.Errorf("workload %s not found", name) } @@ -95,7 +95,7 @@ func doRun(cmd *cobra.Command, args []string) error { logger.Debug("node synced") logger.Debug("entering workload") - if err = runner(rng, conn, cnsc, rtc); err != nil { + if err = w.Run(rng, conn, cnsc, rtc); err != nil { return fmt.Errorf("workload: %w", err) } logger.Debug("workload returned") diff --git a/go/oasis-node/cmd/debug/txsource/workload/junk.go b/go/oasis-node/cmd/debug/txsource/workload/junk.go index 8634c9e94d5..9f007bb75b7 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/junk.go +++ b/go/oasis-node/cmd/debug/txsource/workload/junk.go @@ -11,9 +11,11 @@ import ( runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" ) -var _ Runner = runRuntimePlaceholder +var _ Workload = runtimePlaceholder{} -func runRuntimePlaceholder(_ *rand.Rand, _ *grpc.ClientConn, _ consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error { +type runtimePlaceholder struct{} + +func (runtimePlaceholder) Run(_ *rand.Rand, _ *grpc.ClientConn, _ consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error { ctx := context.Background() var tx *runtimeClient.SubmitTxRequest // Placeholder for sending a runtime transaction from a workload. diff --git a/go/oasis-node/cmd/debug/txsource/workload/transfer.go b/go/oasis-node/cmd/debug/txsource/workload/transfer.go index 9f3238ed98a..d2f088960c0 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/transfer.go +++ b/go/oasis-node/cmd/debug/txsource/workload/transfer.go @@ -25,7 +25,9 @@ const ( var logger = logging.GetLogger("cmd/txsource/workload/transfer") -func runTransfer(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error { +type transfer struct{} + +func (transfer) Run(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error { // Load all the keys up front. Like, how annoyed would you be if down the line one of them turned out to be // corrupted or something, ya know? accounts := make([]struct { diff --git a/go/oasis-node/cmd/debug/txsource/workload/workload.go b/go/oasis-node/cmd/debug/txsource/workload/workload.go index 8233e2f5083..ec158246d34 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/workload.go +++ b/go/oasis-node/cmd/debug/txsource/workload/workload.go @@ -9,8 +9,10 @@ import ( runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" ) -type Runner func(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error +type Workload interface { + Run(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error +} -var ByName = map[string]Runner{ - NameTransfer: runTransfer, +var ByName = map[string]Workload{ + NameTransfer: transfer{}, } From 3cdb7221d3ad0577a22d970fd8fc9d97b6ac3941 Mon Sep 17 00:00:00 2001 From: Warren He Date: Thu, 26 Dec 2019 12:17:51 -0800 Subject: [PATCH 07/12] go txsource: address minor review comments Squashed from tests: add explanation to txsource fixture data go txsource: log workload name in a few more places go txsource: add some doc blocks to exported things --- go/oasis-node/cmd/debug/txsource/txsource.go | 7 ++++--- go/oasis-node/cmd/debug/txsource/workload/workload.go | 1 + go/oasis-test-runner/scenario/e2e/txsource.go | 1 + tests/fixture-data/txsource/README.md | 5 +++++ 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tests/fixture-data/txsource/README.md diff --git a/go/oasis-node/cmd/debug/txsource/txsource.go b/go/oasis-node/cmd/debug/txsource/txsource.go index a5237189fbe..7f2e3d54a4f 100644 --- a/go/oasis-node/cmd/debug/txsource/txsource.go +++ b/go/oasis-node/cmd/debug/txsource/txsource.go @@ -94,15 +94,16 @@ func doRun(cmd *cobra.Command, args []string) error { } logger.Debug("node synced") - logger.Debug("entering workload") + logger.Debug("entering workload", "name", name) if err = w.Run(rng, conn, cnsc, rtc); err != nil { - return fmt.Errorf("workload: %w", err) + return fmt.Errorf("workload %s: %w", name, err) } - logger.Debug("workload returned") + logger.Debug("workload returned", "name", name) return nil } +// Register registers the txsource sub-command. func Register(parentCmd *cobra.Command) { parentCmd.AddCommand(txsourceCmd) } diff --git a/go/oasis-node/cmd/debug/txsource/workload/workload.go b/go/oasis-node/cmd/debug/txsource/workload/workload.go index ec158246d34..c21a6763cbe 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/workload.go +++ b/go/oasis-node/cmd/debug/txsource/workload/workload.go @@ -13,6 +13,7 @@ type Workload interface { Run(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error } +// ByName is the registry of workloads that you can access with `--workload ` on the command line. var ByName = map[string]Workload{ NameTransfer: transfer{}, } diff --git a/go/oasis-test-runner/scenario/e2e/txsource.go b/go/oasis-test-runner/scenario/e2e/txsource.go index 354c9282a6d..63d64693105 100644 --- a/go/oasis-test-runner/scenario/e2e/txsource.go +++ b/go/oasis-test-runner/scenario/e2e/txsource.go @@ -8,6 +8,7 @@ import ( "github.com/oasislabs/oasis-core/go/oasis-test-runner/scenario" ) +// TxSource is a network with the txsource program as a client. var TxSource scenario.Scenario = &txSourceImpl{basicImpl{ name: "txsource", clientBinary: "txsource-wrapper.sh", diff --git a/tests/fixture-data/txsource/README.md b/tests/fixture-data/txsource/README.md new file mode 100644 index 00000000000..b494a3d3441 --- /dev/null +++ b/tests/fixture-data/txsource/README.md @@ -0,0 +1,5 @@ +# Fixture data for txsource +This data is parameterized for the default seed `seeeeeeeeeeeeeeeeeeeeeeeeeeeeeed` (UTF-8). + +## Inventory of configurations +- Funded accounts for the transfer workload From 9226ba1a20b0b21a5df9fabbcda49bd35114520f Mon Sep 17 00:00:00 2001 From: Warren He Date: Mon, 23 Dec 2019 14:34:40 -0800 Subject: [PATCH 08/12] add changelog --- .changelog/2478.feature.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/2478.feature.md diff --git a/.changelog/2478.feature.md b/.changelog/2478.feature.md new file mode 100644 index 00000000000..5c7dc948bed --- /dev/null +++ b/.changelog/2478.feature.md @@ -0,0 +1,7 @@ +Add txsource + +The so-called "txsource" utility introduced in this PR is a starting point for something like a client that sends +transactions for a long period of time, for the purpose of creating long-running tests. + +With this change is a preliminary sample "workload"--a DRBG-backed schedule of transactions--which transfers staking +tokens around among a set of test accounts. From 2b1d408c0d5cde9f5af05cfb2d24461d0a7e5114 Mon Sep 17 00:00:00 2001 From: pro-wh Date: Thu, 26 Dec 2019 12:20:57 -0800 Subject: [PATCH 09/12] changelog: summary dot Co-Authored-By: Jernej Kos --- .changelog/2478.feature.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/2478.feature.md b/.changelog/2478.feature.md index 5c7dc948bed..3a3642f82bb 100644 --- a/.changelog/2478.feature.md +++ b/.changelog/2478.feature.md @@ -1,4 +1,4 @@ -Add txsource +Add txsource. The so-called "txsource" utility introduced in this PR is a starting point for something like a client that sends transactions for a long period of time, for the purpose of creating long-running tests. From 5c533d943886a789c341c5a0434eb0831952d2e3 Mon Sep 17 00:00:00 2001 From: Warren He Date: Fri, 20 Dec 2019 15:50:31 -0800 Subject: [PATCH 10/12] ci: run txsource --- .buildkite/longtests.pipeline.yml | 48 +++++++++++++++++++++++++++++++ scripts/run-e2e-txsource.sh | 1 - 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 .buildkite/longtests.pipeline.yml diff --git a/.buildkite/longtests.pipeline.yml b/.buildkite/longtests.pipeline.yml new file mode 100644 index 00000000000..2d29055c702 --- /dev/null +++ b/.buildkite/longtests.pipeline.yml @@ -0,0 +1,48 @@ +# Copied from pipeline.yml. +docker_plugin_default_config: &docker_plugin_default_config + image: "oasislabs/testing:0.3.0" + always_pull: true + workdir: /workdir + volumes: + - /var/lib/buildkite-agent/.coveralls:/root/.coveralls + - /var/lib/buildkite-agent/.codecov:/root/.codecov + # Shared Rust incremental compile caches. + - /tmp/cargo_ic/debug:/tmp/artifacts/debug/incremental + - /tmp/cargo_ic/debug_sgx:/tmp/artifacts/x86_64-unknown-linux-sgx/debug/incremental + # Shared Rust package checkouts directory. + - /tmp/cargo_pkg/git:/root/.cargo/git + - /tmp/cargo_pkg/registry:/root/.cargo/registry + # Shared Rust SGX standard library artifacts cache. + - /tmp/xargo_cache:/root/.xargo + # Shared Go package checkouts directory. + - /tmp/go_pkg:/root/go/pkg + # Intel SGX Application Enclave Services Manager (AESM) daemon running on + # the Buildkite host. + - /var/run/aesmd/aesm.socket:/var/run/aesmd/aesm.socket + # NOTE: When changing the environment variables below, also copy the changes + # to the docker_plugin_sgx_config. + environment: + - "LC_ALL=C.UTF-8" + - "LANG=C.UTF-8" + - "CARGO_TARGET_DIR=/tmp/artifacts" + - "CARGO_INSTALL_ROOT=/root/.cargo" + - "GOPROXY=https://proxy.golang.org/" + propagate-environment: true + unconfined: true + +docker_plugin: &docker_plugin + oasislabs/docker#v3.0.1-oasis1: + <<: *docker_plugin_default_config + +steps: + - label: Transaction source test + timeout_in_minutes: 480 + command: + - make + - ./scripts/run-e2e-txsource.sh + env: + TEST_BASE_DIR: e2e + agents: + buildkite_agent_size: large + plugins: + <<: *docker_plugin diff --git a/scripts/run-e2e-txsource.sh b/scripts/run-e2e-txsource.sh index 3f75b15c138..8eacc72d7d7 100755 --- a/scripts/run-e2e-txsource.sh +++ b/scripts/run-e2e-txsource.sh @@ -1,5 +1,4 @@ #!/bin/sh -# (no merge) ./go/oasis-test-runner/oasis-test-runner \ --basedir.no_cleanup \ --e2e.node.binary go/oasis-node/oasis-node \ From cea6bba9c7e032dfeb700615913dc16d0a5372f8 Mon Sep 17 00:00:00 2001 From: Warren He Date: Thu, 26 Dec 2019 14:50:51 -0800 Subject: [PATCH 11/12] go txsource: add time limit --- go/oasis-node/cmd/debug/txsource/txsource.go | 17 ++++++++++++++--- .../cmd/debug/txsource/workload/junk.go | 2 +- .../cmd/debug/txsource/workload/transfer.go | 9 ++++++++- .../cmd/debug/txsource/workload/workload.go | 7 ++++++- go/oasis-test-runner/scenario/e2e/txsource.go | 1 + scripts/txsource-wrapper.sh | 10 +++++++++- 6 files changed, 39 insertions(+), 7 deletions(-) diff --git a/go/oasis-node/cmd/debug/txsource/txsource.go b/go/oasis-node/cmd/debug/txsource/txsource.go index 7f2e3d54a4f..b3ca274d50b 100644 --- a/go/oasis-node/cmd/debug/txsource/txsource.go +++ b/go/oasis-node/cmd/debug/txsource/txsource.go @@ -24,8 +24,9 @@ import ( ) const ( - CfgWorkload = "workload" - CfgSeed = "seed" + CfgWorkload = "workload" + CfgSeed = "seed" + CfgTimeLimit = "time_limit" ) var ( @@ -44,6 +45,15 @@ func doRun(cmd *cobra.Command, args []string) error { common.EarlyLogAndExit(err) } + // Set up the time limit. + ctx := context.Background() + timeLimit := viper.GetDuration(CfgTimeLimit) + if timeLimit != 0 { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, timeLimit) + defer cancel() + } + // Set up the genesis system for the signature system's chain context. genesis, err := genesisFile.DefaultFileProvider() if err != nil { @@ -95,7 +105,7 @@ func doRun(cmd *cobra.Command, args []string) error { logger.Debug("node synced") logger.Debug("entering workload", "name", name) - if err = w.Run(rng, conn, cnsc, rtc); err != nil { + if err = w.Run(ctx, rng, conn, cnsc, rtc); err != nil { return fmt.Errorf("workload %s: %w", name, err) } logger.Debug("workload returned", "name", name) @@ -112,6 +122,7 @@ func init() { fs := flag.NewFlagSet("", flag.ContinueOnError) fs.String(CfgWorkload, workload.NameTransfer, "Name of the workload to run (see source for listing)") fs.String(CfgSeed, "seeeeeeeeeeeeeeeeeeeeeeeeeeeeeed", "Seed to use for randomized workloads") + fs.Duration(CfgTimeLimit, 0, "Exit successfully after this long, or 0 to run forever") _ = viper.BindPFlags(fs) txsourceCmd.Flags().AddFlagSet(fs) diff --git a/go/oasis-node/cmd/debug/txsource/workload/junk.go b/go/oasis-node/cmd/debug/txsource/workload/junk.go index 9f007bb75b7..145d56ff315 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/junk.go +++ b/go/oasis-node/cmd/debug/txsource/workload/junk.go @@ -15,7 +15,7 @@ var _ Workload = runtimePlaceholder{} type runtimePlaceholder struct{} -func (runtimePlaceholder) Run(_ *rand.Rand, _ *grpc.ClientConn, _ consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error { +func (runtimePlaceholder) Run(_ context.Context, _ *rand.Rand, _ *grpc.ClientConn, _ consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error { ctx := context.Background() var tx *runtimeClient.SubmitTxRequest // Placeholder for sending a runtime transaction from a workload. diff --git a/go/oasis-node/cmd/debug/txsource/workload/transfer.go b/go/oasis-node/cmd/debug/txsource/workload/transfer.go index d2f088960c0..12e94e3037a 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/transfer.go +++ b/go/oasis-node/cmd/debug/txsource/workload/transfer.go @@ -27,7 +27,7 @@ var logger = logging.GetLogger("cmd/txsource/workload/transfer") type transfer struct{} -func (transfer) Run(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, _ runtimeClient.RuntimeClient) error { +func (transfer) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error { // Load all the keys up front. Like, how annoyed would you be if down the line one of them turned out to be // corrupted or something, ya know? accounts := make([]struct { @@ -118,5 +118,12 @@ func (transfer) Run(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.Client if err = to.reckonedBalance.Add(&transfer.Tokens); err != nil { return fmt.Errorf("to reckoned balance %v Add transfer tokens %v: %w", to.reckonedBalance, transfer.Tokens, err) } + + select { + case <-gracefulExit.Done(): + logger.Debug("time's up") + return nil + default: + } } } diff --git a/go/oasis-node/cmd/debug/txsource/workload/workload.go b/go/oasis-node/cmd/debug/txsource/workload/workload.go index c21a6763cbe..fd56c8c6ec7 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/workload.go +++ b/go/oasis-node/cmd/debug/txsource/workload/workload.go @@ -1,6 +1,7 @@ package workload import ( + "context" "math/rand" "google.golang.org/grpc" @@ -10,7 +11,11 @@ import ( ) type Workload interface { - Run(rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error + // Run executes the workload. + // If `gracefulExit`'s deadline passes, it is not an error. + // Return `nil` after any short-ish amount of time in that case. + // Prefer to do at least one "iteration" even so. + Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error } // ByName is the registry of workloads that you can access with `--workload ` on the command line. diff --git a/go/oasis-test-runner/scenario/e2e/txsource.go b/go/oasis-test-runner/scenario/e2e/txsource.go index 63d64693105..01d1ef9dbff 100644 --- a/go/oasis-test-runner/scenario/e2e/txsource.go +++ b/go/oasis-test-runner/scenario/e2e/txsource.go @@ -40,6 +40,7 @@ func (sc *txSourceImpl) Run(childEnv *env.Env) error { cmd, err := startClient(childEnv, sc.net, sc.clientBinary, append([]string{ "--genesis-path", sc.net.GenesisPath(), + "--time-limit", "2m", // %%% low value for validation (: }, sc.clientArgs...)) if err != nil { return fmt.Errorf("startClient: %w", err) diff --git a/scripts/txsource-wrapper.sh b/scripts/txsource-wrapper.sh index e0998af06b6..ef67e1c3015 100755 --- a/scripts/txsource-wrapper.sh +++ b/scripts/txsource-wrapper.sh @@ -1,7 +1,8 @@ #!/bin/sh -eu usage() { - echo >&2 "usage: $0 --node-address --runtime-id --genesis-path " + echo >&2 "usage: $0 --node-address --runtime-id --genesis-path --time-limit " + # 0 1 2 3 4 5 6 7 8 exit 1 } @@ -16,8 +17,15 @@ else usage fi +if [ "$7" = "--time-limit" ]; then + time_limit=$8 +else + usage +fi + exec ./go/oasis-node/oasis-node debug txsource \ --workload transfer \ + --time_limit "$time_limit" \ --address "$node_address" \ --debug.allow_test_keys \ --debug.dont_blame_oasis \ From bc02252db4f93fb40bbe44ecd21028e94ec83c2a Mon Sep 17 00:00:00 2001 From: Warren He Date: Mon, 30 Dec 2019 10:52:51 -0800 Subject: [PATCH 12/12] go txsource: address minor review comments Squashed from go txsource: switch to HeightLatest go txsource: add doc to Workload go txsource: only one thing in junk.go anyway go txsource: separate workloads' log tags --- .../workload/{junk.go => runtimeplaceholder.go} | 9 +++++++-- go/oasis-node/cmd/debug/txsource/workload/transfer.go | 10 +++++----- go/oasis-node/cmd/debug/txsource/workload/workload.go | 1 + 3 files changed, 13 insertions(+), 7 deletions(-) rename go/oasis-node/cmd/debug/txsource/workload/{junk.go => runtimeplaceholder.go} (73%) diff --git a/go/oasis-node/cmd/debug/txsource/workload/junk.go b/go/oasis-node/cmd/debug/txsource/workload/runtimeplaceholder.go similarity index 73% rename from go/oasis-node/cmd/debug/txsource/workload/junk.go rename to go/oasis-node/cmd/debug/txsource/workload/runtimeplaceholder.go index 145d56ff315..f3fefde54f5 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/junk.go +++ b/go/oasis-node/cmd/debug/txsource/workload/runtimeplaceholder.go @@ -7,11 +7,16 @@ import ( "google.golang.org/grpc" + "github.com/oasislabs/oasis-core/go/common/logging" consensus "github.com/oasislabs/oasis-core/go/consensus/api" runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" ) -var _ Workload = runtimePlaceholder{} +var ( + _ Workload = runtimePlaceholder{} + + runtimePlaceholderLogger = logging.GetLogger("cmd/txsource/workload/runtimeplaceholder") +) type runtimePlaceholder struct{} @@ -23,6 +28,6 @@ func (runtimePlaceholder) Run(_ context.Context, _ *rand.Rand, _ *grpc.ClientCon if err != nil { return fmt.Errorf("rtc.SubmitTx: %w", err) } - logger.Debug("output", "out", out) + runtimePlaceholderLogger.Debug("output", "out", out) return nil } diff --git a/go/oasis-node/cmd/debug/txsource/workload/transfer.go b/go/oasis-node/cmd/debug/txsource/workload/transfer.go index 12e94e3037a..41b9935fe88 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/transfer.go +++ b/go/oasis-node/cmd/debug/txsource/workload/transfer.go @@ -23,7 +23,7 @@ const ( TransferAmount = 1 ) -var logger = logging.GetLogger("cmd/txsource/workload/transfer") +var transferLogger = logging.GetLogger("cmd/txsource/workload/transfer") type transfer struct{} @@ -50,13 +50,13 @@ func (transfer) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.Cli for i := range accounts { var account *staking.Account account, err = stakingClient.AccountInfo(ctx, &staking.OwnerQuery{ - Height: 0, + Height: consensus.HeightLatest, Owner: accounts[i].signer.Public(), }) if err != nil { return fmt.Errorf("stakingClient.AccountInfo %s: %w", accounts[i].signer.Public(), err) } - logger.Debug("account info", + transferLogger.Debug("account info", "i", i, "pub", accounts[i].signer.Public(), "info", account, @@ -101,7 +101,7 @@ func (transfer) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.Cli if err != nil { return fmt.Errorf("transaction.Sign: %w", err) } - logger.Debug("submitting transfer", + transferLogger.Debug("submitting transfer", "from", from.signer.Public(), "to", to.signer.Public(), ) @@ -121,7 +121,7 @@ func (transfer) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.Cli select { case <-gracefulExit.Done(): - logger.Debug("time's up") + transferLogger.Debug("time's up") return nil default: } diff --git a/go/oasis-node/cmd/debug/txsource/workload/workload.go b/go/oasis-node/cmd/debug/txsource/workload/workload.go index fd56c8c6ec7..cf0b22c2520 100644 --- a/go/oasis-node/cmd/debug/txsource/workload/workload.go +++ b/go/oasis-node/cmd/debug/txsource/workload/workload.go @@ -10,6 +10,7 @@ import ( runtimeClient "github.com/oasislabs/oasis-core/go/runtime/client/api" ) +// Workload is a DRBG-backed schedule of transactions. type Workload interface { // Run executes the workload. // If `gracefulExit`'s deadline passes, it is not an error.