Skip to content

Commit

Permalink
txsource: use TestEntity for funding instead of hardcoding addresses
Browse files Browse the repository at this point in the history
  • Loading branch information
ptrus committed Mar 4, 2020
1 parent 0dee03d commit d13e108
Show file tree
Hide file tree
Showing 12 changed files with 261 additions and 56 deletions.
4 changes: 4 additions & 0 deletions .buildkite/scripts/daily_txsource.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ else
-X POST \
--data "{\"text\": \"Daily transaction source tests failure\"}" \
"$SLACK_WEBHOOK_URL"

# Exit with non-zero exit code, so that the buildkite build will be
# marked as failed.
exit 1
fi
3 changes: 3 additions & 0 deletions .changelog/2744.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
txsource: use TestEntity for funding instead of hardcoding addresses

Aditionally fees and non-zero gas prices are now used in workloads.
17 changes: 16 additions & 1 deletion go/oasis-node/cmd/debug/txsource/txsource.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (

"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/crypto/signature"
memorySigner "github.com/oasislabs/oasis-core/go/common/crypto/signature/signers/memory"
"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"
Expand Down Expand Up @@ -104,8 +106,21 @@ func doRun(cmd *cobra.Command, args []string) error {
}
logger.Debug("node synced")

// Generate and fund the account that will be used for funding accounts
// during the workload.
// NOTE: we don't use Test Entity account directly in the workloads
// as using the same account in all runs would lead to a lot of
// contention and nonce mismatches.
fundingAccount, err := memorySigner.NewFactory().Generate(signature.SignerEntity, rng)
if err != nil {
return fmt.Errorf("memory signer factory generate funding account %w", err)
}
if err = workload.FundAccountFromTestEntity(ctx, logger, cnsc, fundingAccount.Public()); err != nil {
return fmt.Errorf("test entity account funding failure: %w", err)
}

logger.Debug("entering workload", "name", name)
if err = w.Run(ctx, rng, conn, cnsc, rtc); err != nil {
if err = w.Run(ctx, rng, conn, cnsc, rtc, fundingAccount); err != nil {
logger.Error("workload error", "err", err)
return fmt.Errorf("workload %s: %w", name, err)
}
Expand Down
11 changes: 10 additions & 1 deletion go/oasis-node/cmd/debug/txsource/workload/oversized.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
)

const (
// NameOversized is the name of the oversized workload.
NameOversized = "oversized"

oversizedTxGasAmount = 10000
Expand All @@ -27,7 +28,7 @@ var oversizedLogger = logging.GetLogger("cmd/txsource/workload/oversized")

type oversized struct{}

func (oversized) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error {
func (oversized) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient, fundingAccount signature.Signer) error {
txSignerFactory := memorySigner.NewFactory()
txSigner, err := txSignerFactory.Generate(signature.SignerEntity, rng)
if err != nil {
Expand All @@ -47,6 +48,10 @@ func (oversized) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.Cl
fee := transaction.Fee{
Gas: oversizedTxGasAmount,
}
if err = fee.Amount.FromInt64(oversizedTxGasAmount * gasPrice); err != nil {
return fmt.Errorf("Fee amount error: %w", err)
}

for {
// Generate a big transfer transaction which is valid, but oversized.
type customTransfer struct {
Expand All @@ -63,6 +68,10 @@ func (oversized) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.Cl
return fmt.Errorf("failed to generate bogus transaction: %w", err)
}

if err = transferFunds(ctx, oversizedLogger, cnsc, fundingAccount, txSigner.Public(), int64(oversizedTxGasAmount*gasPrice)); err != nil {
return fmt.Errorf("workload/oversized: account funding failure: %w", err)
}

tx := transaction.NewTransaction(nonce, &fee, staking.MethodTransfer, &xfer)
signedTx, err := transaction.Sign(txSigner, tx)
if err != nil {
Expand Down
47 changes: 37 additions & 10 deletions go/oasis-node/cmd/debug/txsource/workload/parallel.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,39 @@ import (
)

const (
// NameParallel is the name of the parallel workload.
NameParallel = "parallel"

parallelSendWaitTimeoutInterval = 30 * time.Second
parallelSendTimeoutInterval = 60 * time.Second
parallelConcurency = 200
parallelTxGasAmount = 10
parallelTxTransferAmount = 100
parallelTxFundInterval = 10
)

var parallelLogger = logging.GetLogger("cmd/txsource/workload/parallel")

type parallel struct{}

func (parallel) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error {
func (parallel) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient, fundingAccount signature.Signer) error {
ctx := context.Background()
var err error

accounts := make([]signature.Signer, parallelConcurency)
var err error
fac := memorySigner.NewFactory()
for i := range accounts {
// NOTE: no balances are needed for now
accounts[i], err = fac.Generate(signature.SignerEntity, rng)
if err != nil {
return fmt.Errorf("memory signer factory Generate account %d: %w", i, err)
}

// Initial funding of accounts.
fundAmount := parallelTxTransferAmount + // self transfer amount
parallelTxFundInterval*parallelTxGasAmount*gasPrice // gas for `parallelTxFundInterval` transfers.
if err = transferFunds(ctx, parallelLogger, cnsc, fundingAccount, accounts[i].Public(), int64(fundAmount)); err != nil {
return fmt.Errorf("account funding failure: %w", err)
}
}

// A single global nonce is enough as we wait for all submissions to
Expand All @@ -51,23 +60,31 @@ func (parallel) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.Cli
fee := transaction.Fee{
Gas: parallelTxGasAmount,
}
if err = fee.Amount.FromInt64(parallelTxGasAmount); err != nil {
return fmt.Errorf("Fee amount error: %w", err)
}

for i := uint64(1); ; i++ {

for {
errCh := make(chan error, parallelConcurency)
var wg sync.WaitGroup
wg.Add(parallelConcurency)

for i := 0; i < parallelConcurency; i++ {
for c := 0; c < parallelConcurency; c++ {
go func(txSigner signature.Signer, nonce uint64) {
defer wg.Done()

// Transfer tx.
transfer := staking.Transfer{
To: txSigner.Public(),
}
tx := staking.NewTransferTx(nonce, &fee, &transfer)
if err = transfer.Tokens.FromInt64(parallelTxTransferAmount); err != nil {
errCh <- fmt.Errorf("transfer tokens FromInt64 %d: %w", parallelTxTransferAmount, err)
return
}

signedTx, err := transaction.Sign(txSigner, tx)
tx := staking.NewTransferTx(nonce, &fee, &transfer)
var signedTx *transaction.SignedTransaction
signedTx, err = transaction.Sign(txSigner, tx)
if err != nil {
parallelLogger.Error("transaction.Sign error", "err", err)
errCh <- fmt.Errorf("transaction.Sign: %w", err)
Expand All @@ -83,7 +100,7 @@ func (parallel) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.Cli
return
}

}(accounts[i], nonce)
}(accounts[c], nonce)
}

// Wait for transactions.
Expand All @@ -99,7 +116,7 @@ func (parallel) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.Cli
parallelLogger.Error("transactions not completed within timeout")
return fmt.Errorf("workload parallel: transactions not completed within timeout")

case err := <-errCh:
case err = <-errCh:
parallelLogger.Error("error subimit transaction",
"err", err,
)
Expand All @@ -111,6 +128,16 @@ func (parallel) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.Cli
)
}

if i%parallelTxFundInterval == 0 {
// Re-fund accounts for next `parallelTxFundInterval` transfers.
for i := range accounts {
fundAmount := parallelTxFundInterval * parallelTxGasAmount * gasPrice // gas for `parallelTxFundInterval` transfers.
if err = transferFunds(ctx, parallelLogger, cnsc, fundingAccount, accounts[i].Public(), int64(fundAmount)); err != nil {
return fmt.Errorf("account funding failure: %w", err)
}
}
}

select {
case <-time.After(parallelSendTimeoutInterval):
case <-gracefulExit.Done():
Expand Down
37 changes: 32 additions & 5 deletions go/oasis-node/cmd/debug/txsource/workload/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
)

const (
// NameRegistration is the name of the registration workload.
NameRegistration = "registration"

registryNumEntities = 10
Expand Down Expand Up @@ -150,7 +151,7 @@ func signNode(identity *identity.Identity, nodeDesc *node.Node) (*node.MultiSign
return sigNode, nil
}

func (r *registration) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error {
func (r *registration) Run(gracefulExit context.Context, rng *rand.Rand, conn *grpc.ClientConn, cnsc consensus.ClientBackend, rtc runtimeClient.RuntimeClient, fundingAccount signature.Signer) error { // nolint: gocyclo
ctx := context.Background()
var err error

Expand Down Expand Up @@ -242,6 +243,15 @@ func (r *registration) Run(gracefulExit context.Context, rng *rand.Rand, conn *g
return fmt.Errorf("failed to estimate gas: %w", err)
}
tx.Fee.Gas = gas
feeAmount := int64(gas) * gasPrice
if err = tx.Fee.Amount.FromInt64(feeAmount); err != nil {
return fmt.Errorf("fee amount from int64: %w", err)
}

// Fund entity account to cover registration fees.
if err = transferFunds(ctx, registryLogger, cnsc, fundingAccount, entityAccs[i].signer.Public(), feeAmount); err != nil {
return fmt.Errorf("account funding failure: %w", err)
}

signedTx, err := transaction.Sign(entityAccs[i].signer, tx)
if err != nil {
Expand Down Expand Up @@ -270,8 +280,17 @@ func (r *registration) Run(gracefulExit context.Context, rng *rand.Rand, conn *g
return fmt.Errorf("failed to estimate gas: %w", err)
}
tx.Fee.Gas = gas
entityAccs[i].reckonedNonce++
feeAmount := int64(gas) * gasPrice
if err = tx.Fee.Amount.FromInt64(feeAmount); err != nil {
return fmt.Errorf("fee amount from uint64: %w", err)
}

// Fund entity account to cover entity registration fees.
if err = transferFunds(ctx, registryLogger, cnsc, fundingAccount, entityAccs[i].signer.Public(), feeAmount); err != nil {
return fmt.Errorf("account funding failure: %w", err)
}

entityAccs[i].reckonedNonce++
signedTx, err := transaction.Sign(entityAccs[i].signer, tx)
if err != nil {
return fmt.Errorf("transaction.Sign: %w", err)
Expand Down Expand Up @@ -312,26 +331,34 @@ func (r *registration) Run(gracefulExit context.Context, rng *rand.Rand, conn *g
return fmt.Errorf("failed to estimate gas: %w", err)
}
tx.Fee.Gas = gas
feeAmount := gas * gasPrice
if err = tx.Fee.Amount.FromUint64(uint64(feeAmount)); err != nil {
return fmt.Errorf("fee amount from uint64: %w", err)
}

// Fund node account to cover registration fees.
if err = transferFunds(ctx, registryLogger, cnsc, fundingAccount, selectedNode.id.NodeSigner.Public(), int64(feeAmount)); err != nil {
return fmt.Errorf("account funding failure: %w", err)
}
selectedNode.reckonedNonce++

signedTx, err := transaction.Sign(selectedNode.id.NodeSigner, tx)
if err != nil {
return fmt.Errorf("transaction.Sign: %w", err)
}
transferLogger.Debug("submitting registration",
registryLogger.Debug("submitting registration",
"node", selectedNode.nodeDesc,
)
if err = cnsc.SubmitTx(ctx, signedTx); err != nil {
return fmt.Errorf("cnsc.SubmitTx: %w", err)
}
transferLogger.Debug("registered node",
registryLogger.Debug("registered node",
"node", selectedNode.nodeDesc,
)

select {
case <-gracefulExit.Done():
transferLogger.Debug("time's up")
registryLogger.Debug("time's up")
return nil
default:
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"google.golang.org/grpc"

"github.com/oasislabs/oasis-core/go/common/crypto/signature"
"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"
Expand All @@ -20,7 +21,7 @@ var (

type runtimePlaceholder struct{}

func (runtimePlaceholder) Run(_ context.Context, _ *rand.Rand, _ *grpc.ClientConn, _ consensus.ClientBackend, rtc runtimeClient.RuntimeClient) error {
func (runtimePlaceholder) Run(_ context.Context, _ *rand.Rand, _ *grpc.ClientConn, _ consensus.ClientBackend, rtc runtimeClient.RuntimeClient, fundingAccount signature.Signer) error {
ctx := context.Background()
var tx *runtimeClient.SubmitTxRequest
// Placeholder for sending a runtime transaction from a workload.
Expand Down
Loading

0 comments on commit d13e108

Please sign in to comment.