/
oversized.go
137 lines (118 loc) · 3.71 KB
/
oversized.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package workload
import (
"context"
"fmt"
"math/rand"
"time"
"google.golang.org/grpc"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
memorySigner "github.com/oasisprotocol/oasis-core/go/common/crypto/signature/signers/memory"
consensus "github.com/oasisprotocol/oasis-core/go/consensus/api"
"github.com/oasisprotocol/oasis-core/go/consensus/api/transaction"
consensusGenesis "github.com/oasisprotocol/oasis-core/go/consensus/genesis"
staking "github.com/oasisprotocol/oasis-core/go/staking/api"
)
// NameOversized is the name of the oversized workload.
const NameOversized = "oversized"
// Oversized is the oversized workload.
var Oversized = &oversized{
BaseWorkload: NewBaseWorkload(NameOversized),
}
const (
oversizedTxGasAmount = 10000
)
type oversized struct {
BaseWorkload
}
// Implements Workload.
func (*oversized) NeedsFunds() bool {
return true
}
// Implements Workload.
func (o *oversized) Run(
gracefulExit context.Context,
rng *rand.Rand,
conn *grpc.ClientConn,
cnsc consensus.ClientBackend,
sm consensus.SubmissionManager,
fundingAccount signature.Signer,
validatorEntities []signature.Signer,
) error {
// Initialize base workload.
o.BaseWorkload.Init(cnsc, sm, fundingAccount)
txSignerFactory := memorySigner.NewFactory()
txSigner, err := txSignerFactory.Generate(signature.SignerEntity, rng)
if err != nil {
return fmt.Errorf("failed to generate signer key: %w", err)
}
txSignerAddr := staking.NewAddress(txSigner.Public())
ctx := context.Background()
params, err := cnsc.GetParameters(ctx, consensus.HeightLatest)
if err != nil {
return fmt.Errorf("failed to query consensus parameters: %w", err)
}
gasPrice, err := sm.PriceDiscovery().GasPrice(ctx)
if err != nil {
return fmt.Errorf("failed to get gas price: %w", err)
}
var nonce uint64
fee := transaction.Fee{
Gas: oversizedTxGasAmount +
transaction.Gas(params.Parameters.MaxTxSize)*
params.Parameters.GasCosts[consensusGenesis.GasOpTxByte],
}
_ = fee.Amount.FromInt64(oversizedTxGasAmount)
_ = fee.Amount.Mul(gasPrice)
for {
// Generate a big transfer transaction which is valid, but oversized.
type customTransfer struct {
To staking.Address `json:"to"`
Data []byte `json:"data"`
}
xfer := customTransfer{
// Send zero stake to self, so the transaction will be valid.
To: txSignerAddr,
// Include some extra random data so we are over the MaxTxSize limit.
Data: make([]byte, params.Parameters.MaxTxSize),
}
if _, err = rng.Read(xfer.Data); err != nil {
return fmt.Errorf("failed to generate bogus transaction: %w", err)
}
if err = o.TransferFundsQty(
ctx,
fundingAccount,
txSignerAddr,
&fee.Amount,
); 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 {
return fmt.Errorf("transaction.Sign: %w", err)
}
o.Logger.Debug("submitting oversized transaction",
"payload_size", len(xfer.Data),
)
// Wait for a maximum of 5 seconds.
submitCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
err = cnsc.SubmitTx(submitCtx, signedTx)
cancel()
switch err {
case nil:
// This should never happen.
return fmt.Errorf("successfully submitted an oversized transaction")
case consensus.ErrOversizedTx:
// Submitting an oversized transaction is an error, so we expect this to fail.
o.Logger.Info("transaction rejected due to ErrOversizedTx")
default:
return fmt.Errorf("failed to submit oversized transaction: %w", err)
}
select {
case <-time.After(1 * time.Second):
case <-gracefulExit.Done():
o.Logger.Debug("time's up")
return nil
}
}
}