Skip to content

Commit 747a7f0

Browse files
committed
Add estimation logic
1 parent 77db5d4 commit 747a7f0

File tree

8 files changed

+97
-15
lines changed

8 files changed

+97
-15
lines changed

internal/common/common.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,13 @@ import "github.com/gnolang/gno/tm2/pkg/std"
44

55
const Denomination = "ugnot"
66

7-
// TODO support estimating gas params
8-
// These are constants for now,
9-
// but should be fetched as estimations
10-
// from the Tendermint node once this functionality
11-
// is available.
12-
//
13-
// Each package call / deployment
14-
// costs a fixed 1 GNOT
15-
// https://github.com/gnolang/gno/issues/649
167
var (
178
DefaultGasFee = std.Coin{
189
Denom: Denomination,
19-
Amount: 1,
10+
Amount: 5,
2011
}
2112

13+
// TODO remove
2214
InitialTxCost = std.Coin{
2315
Denom: Denomination,
2416
Amount: 1000000, // 1 GNOT

internal/distributor/distributor.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ var errInsufficientFunds = errors.New("insufficient distributor funds")
1919
type Client interface {
2020
GetAccount(address string) (*gnoland.GnoAccount, error)
2121
BroadcastTransaction(tx *std.Tx) error
22+
EstimateGas(tx *std.Tx) (int64, error)
2223
}
2324

2425
// Distributor is the process
@@ -66,7 +67,7 @@ func calculateRuntimeCosts(totalTx int64) std.Coin {
6667
// NOTE: Since there is no gas estimation support yet, this value
6768
// is fixed, but it will change in the future once pricing estimations
6869
// are added
69-
baseTxCost := common.DefaultGasFee.Add(common.InitialTxCost)
70+
baseTxCost := common.DefaultGasFee
7071

7172
// Each account should have enough funds
7273
// to execute the entire run

internal/pipeline.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ func (p *Pipeline) Execute() error {
110110
runAccounts,
111111
p.cfg.Transactions,
112112
p.cfg.ChainID,
113+
p.cli.EstimateGas,
113114
)
114115
if err != nil {
115116
return fmt.Errorf("unable to construct transactions, %w", err)
@@ -205,7 +206,12 @@ func prepareRuntime(
205206
}
206207

207208
// Get the predeploy transactions
208-
predeployTxs, err := txRuntime.Initialize(deployer, deployerKey, chainID)
209+
predeployTxs, err := txRuntime.Initialize(
210+
deployer,
211+
deployerKey,
212+
chainID,
213+
cli.EstimateGas,
214+
)
209215
if err != nil {
210216
return fmt.Errorf("unable to initialize runtime, %w", err)
211217
}

internal/runtime/helper.go

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func constructTransactions(
2020
transactions uint64,
2121
chainID string,
2222
getMsg msgFn,
23+
estimateFn EstimateGasFn,
2324
) ([]*std.Tx, error) {
2425
var (
2526
txs = make([]*std.Tx, transactions)
@@ -30,6 +31,50 @@ func constructTransactions(
3031
nonceMap = make(map[uint64]uint64) // accountNumber -> nonce
3132
)
3233

34+
fmt.Printf("\n🔨 Estimating Gas 🔨\n\n")
35+
36+
// Estimate the fee for the transaction batch
37+
txFee := defaultDeployTxFee
38+
39+
// Construct the first tx
40+
// Generate the transaction
41+
var (
42+
creator = accounts[0]
43+
creatorKey = keys[0]
44+
)
45+
46+
tx := &std.Tx{
47+
Msgs: []std.Msg{getMsg(creator, 0)},
48+
Fee: txFee,
49+
}
50+
51+
// Sign the transaction
52+
cfg := signer.SignCfg{
53+
ChainID: chainID,
54+
AccountNumber: creator.GetAccountNumber(),
55+
Sequence: creator.GetSequence(),
56+
}
57+
58+
if err := signer.SignTx(tx, creatorKey, cfg); err != nil {
59+
return nil, fmt.Errorf("unable to sign transaction, %w", err)
60+
}
61+
62+
gasWanted, err := estimateFn(tx)
63+
if err != nil {
64+
return nil, fmt.Errorf("unable to estimate gas, %w", err)
65+
}
66+
67+
// Clear the old signatures, because they need
68+
// to be regenerated
69+
clear(tx.Signatures)
70+
71+
// Use the estimated gas limit
72+
txFee.GasWanted = gasWanted + 10_000 // 10k gas buffer
73+
74+
if err = signer.SignTx(tx, creatorKey, cfg); err != nil {
75+
return nil, fmt.Errorf("unable to sign transaction, %w", err)
76+
}
77+
3378
fmt.Printf("\n🔨 Constructing Transactions 🔨\n\n")
3479

3580
bar := progressbar.Default(int64(transactions), "constructing txs")
@@ -44,7 +89,7 @@ func constructTransactions(
4489

4590
tx := &std.Tx{
4691
Msgs: []std.Msg{getMsg(creator, i)},
47-
Fee: defaultDeployTxFee,
92+
Fee: txFee,
4893
}
4994

5095
// Fetch the next account nonce

internal/runtime/package_deployment.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func (c *packageDeployment) Initialize(
2020
_ std.Account,
2121
_ crypto.PrivKey,
2222
_ string,
23+
_ EstimateGasFn,
2324
) ([]*std.Tx, error) {
2425
// No extra setup needed for this runtime type
2526
return nil, nil
@@ -30,6 +31,7 @@ func (c *packageDeployment) ConstructTransactions(
3031
accounts []std.Account,
3132
transactions uint64,
3233
chainID string,
34+
estimateFn EstimateGasFn,
3335
) ([]*std.Tx, error) {
3436
var (
3537
timestamp = time.Now().Unix()
@@ -65,5 +67,6 @@ func (c *packageDeployment) ConstructTransactions(
6567
transactions,
6668
chainID,
6769
getMsgFn,
70+
estimateFn,
6871
)
6972
}

internal/runtime/realm_call.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/gnolang/gno/gnovm"
99
"github.com/gnolang/gno/tm2/pkg/crypto"
1010
"github.com/gnolang/gno/tm2/pkg/std"
11+
"github.com/gnolang/supernova/internal/common"
1112
"github.com/gnolang/supernova/internal/signer"
1213
)
1314

@@ -21,7 +22,12 @@ func newRealmCall() *realmCall {
2122
return &realmCall{}
2223
}
2324

24-
func (r *realmCall) Initialize(account std.Account, key crypto.PrivKey, chainID string) ([]*std.Tx, error) {
25+
func (r *realmCall) Initialize(
26+
account std.Account,
27+
key crypto.PrivKey,
28+
chainID string,
29+
estimateFn EstimateGasFn,
30+
) ([]*std.Tx, error) {
2531
// The Realm needs to be deployed before
2632
// it can be interacted with
2733
r.realmPath = fmt.Sprintf(
@@ -62,6 +68,25 @@ func (r *realmCall) Initialize(account std.Account, key crypto.PrivKey, chainID
6268
return nil, fmt.Errorf("unable to sign initialize transaction, %w", err)
6369
}
6470

71+
// Estimate the gas for the initial tx
72+
gasWanted, err := estimateFn(tx)
73+
if err != nil {
74+
return nil, fmt.Errorf("unable to estimate gas: %w", err)
75+
}
76+
77+
// Wipe the signatures, because we will change the fee,
78+
// and cause the previous ones to be invalid
79+
clear(tx.Signatures)
80+
81+
tx.Fee = std.NewFee(
82+
gasWanted+10_000, // buffer with 10k gas
83+
common.DefaultGasFee,
84+
)
85+
86+
if err = signer.SignTx(tx, key, cfg); err != nil {
87+
return nil, fmt.Errorf("unable to sign initialize transaction, %w", err)
88+
}
89+
6590
return []*std.Tx{tx}, nil
6691
}
6792

@@ -70,6 +95,7 @@ func (r *realmCall) ConstructTransactions(
7095
accounts []std.Account,
7196
transactions uint64,
7297
chainID string,
98+
estimateFn EstimateGasFn,
7399
) ([]*std.Tx, error) {
74100
getMsgFn := func(creator std.Account, index int) std.Msg {
75101
return vm.MsgCall{
@@ -86,5 +112,6 @@ func (r *realmCall) ConstructTransactions(
86112
transactions,
87113
chainID,
88114
getMsgFn,
115+
estimateFn,
89116
)
90117
}

internal/runtime/realm_deployment.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func (c *realmDeployment) Initialize(
2020
_ std.Account,
2121
_ crypto.PrivKey,
2222
_ string,
23+
_ EstimateGasFn,
2324
) ([]*std.Tx, error) {
2425
// No extra setup needed for this runtime type
2526
return nil, nil
@@ -30,6 +31,7 @@ func (c *realmDeployment) ConstructTransactions(
3031
accounts []std.Account,
3132
transactions uint64,
3233
chainID string,
34+
estimateFn EstimateGasFn,
3335
) ([]*std.Tx, error) {
3436
var (
3537
timestamp = time.Now().Unix()
@@ -65,5 +67,6 @@ func (c *realmDeployment) ConstructTransactions(
6567
transactions,
6668
chainID,
6769
getMsgFn,
70+
estimateFn,
6871
)
6972
}

internal/runtime/runtime.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ const (
1111
packagePathPrefix = "gno.land/p"
1212
)
1313

14-
var defaultDeployTxFee = std.NewFee(500000, common.DefaultGasFee)
14+
var defaultDeployTxFee = std.NewFee(1_000_000_000, common.DefaultGasFee)
15+
16+
// EstimateGasFn is the gas estimation callback
17+
type EstimateGasFn func(tx *std.Tx) (int64, error)
1518

1619
// Runtime is the base interface for all runtime
1720
// implementations.
@@ -25,6 +28,7 @@ type Runtime interface {
2528
account std.Account,
2629
key crypto.PrivKey,
2730
chainID string,
31+
estimateFn EstimateGasFn,
2832
) ([]*std.Tx, error)
2933

3034
// ConstructTransactions generates and signs the required transactions
@@ -34,6 +38,7 @@ type Runtime interface {
3438
accounts []std.Account,
3539
transactions uint64,
3640
chainID string,
41+
estimateFn EstimateGasFn,
3742
) ([]*std.Tx, error)
3843
}
3944

0 commit comments

Comments
 (0)