Skip to content

Commit a13d169

Browse files
authoredOct 16, 2020
Merge pull request #43 from renproject/feat/gas-base-gas-price
Fix the use of gas price and gas cap
2 parents 30c3c99 + 005efce commit a13d169

File tree

13 files changed

+78
-58
lines changed

13 files changed

+78
-58
lines changed
 

‎.github/workflows/test.yml

+3
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ jobs:
2121
path: ~/go/pkg/mod
2222
key: ${{ runner.os }}-go-aw-${{ hashFiles('**/go.sum') }}
2323

24+
# Remove apt repos that are known to break from time to time
25+
# See https://github.com/actions/virtual-environments/issues/323
2426
- name: Install dependency packages
2527
run: |
28+
for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done
2629
sudo apt-get update
2730
sudo apt-get install -y build-essential
2831
sudo apt-get install -y jq mesa-opencl-icd ocl-icd-opencl-dev pkg-config

‎api/account/account.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ type Tx interface {
5656
// information, and this should be accepted during the construction of the
5757
// chain-specific transaction builder.
5858
type TxBuilder interface {
59-
BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasPrice pack.U256, payload pack.Bytes) (Tx, error)
59+
BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasPrice, gasCap pack.U256, payload pack.Bytes) (Tx, error)
6060
}
6161

6262
// The Client interface defines the functionality required to interact with a

‎api/gas/gas.go

+22-10
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,27 @@ import (
1111
)
1212

1313
// The Estimator interface defines the functionality required to know the
14-
// current recommended gas prices.
14+
// current recommended gas price per gas unit and gas cap per gas unit. Not all
15+
// chains have the concept of a gas cap, in which case it should be set to be
16+
// equal to the gas price.
1517
type Estimator interface {
16-
// EstimateGasPrice that should be used to get confirmation within a
17-
// reasonable amount of time. The precise definition of "reasonable amount
18-
// of time" varies from chain to chain, and so is left open to
19-
// interpretation by the implementation. For example, in Bitcoin, it would
20-
// be the recommended SATs-per-byte required to get a transaction into the
21-
// next block. In Ethereum, it would be the recommended GWEI-per-gas
22-
// required to get a transaction into one of the next few blocks (because
23-
// blocks happen a lot faster).
24-
EstimateGasPrice(context.Context) (pack.U256, pack.U256, error)
18+
// EstimateGas base/price that should be used in order to get a transaction
19+
// confirmed within a reasonable amount of time. The precise definition of
20+
// "reasonable amount of time" varies from chain to chain, and so is left
21+
// open to interpretation by the implementation.
22+
23+
// For example, in Bitcoin, the gas price (and gas cap) would be the
24+
// recommended SATs-per-byte required to get a transaction into the next
25+
// block.
26+
27+
// In Ethereum without EIP-1559, the gas price (and gas cap) would be the
28+
// recommended GWEI-per-gas required to get a transaction into one of the
29+
// next few blocks (because blocks happen a lot faster). In Ethereum with
30+
// EIP1559, the gas price and gas cap would be back calculated given the gas
31+
// cap and an estimate of the current gas base.
32+
//
33+
// The assumption is that the total gas cost will be gasLimit * gasPrice <
34+
// gasLimit * gasCap. If chain nodes give back values based on different
35+
// assumptions, then the values must be normalised as needed.
36+
EstimateGas(context.Context) (gasPrice, gasCap pack.U256, err error)
2537
}

‎chain/bitcoin/gas.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,20 @@ func NewGasEstimator(client Client, numBlocks int64) GasEstimator {
3030
}
3131
}
3232

33-
// EstimateGasPrice returns the number of SATs-per-byte that is needed in order
34-
// to confirm transactions with an estimated maximum delay of `numBlocks` block.
35-
// It is the responsibility of the caller to know the number of bytes in their
36-
// transaction. This method calls the `estimatesmartfee` RPC call to the node,
37-
// which based on a conservative (considering longer history) strategy returns
38-
// the estimated BTC per kilobyte of data in the transaction. An error will be
39-
// returned if the bitcoin node hasn't observed enough blocks to make an
40-
// estimate for the provided target `numBlocks`.
41-
func (gasEstimator GasEstimator) EstimateGasPrice(ctx context.Context) (pack.U256, pack.U256, error) {
33+
// EstimateGas returns the number of SATs-per-byte (for both price and cap) that
34+
// is needed in order to confirm transactions with an estimated maximum delay of
35+
// `numBlocks` block. It is the responsibility of the caller to know the number
36+
// of bytes in their transaction. This method calls the `estimatesmartfee` RPC
37+
// call to the node, which based on a conservative (considering longer history)
38+
// strategy returns the estimated BTC per kilobyte of data in the transaction.
39+
// An error will be returned if the bitcoin node hasn't observed enough blocks
40+
// to make an estimate for the provided target `numBlocks`.
41+
func (gasEstimator GasEstimator) EstimateGas(ctx context.Context) (pack.U256, pack.U256, error) {
4242
feeRate, err := gasEstimator.client.EstimateSmartFee(ctx, gasEstimator.numBlocks)
4343
if err != nil {
4444
return pack.NewU256([32]byte{}), pack.NewU256([32]byte{}), err
4545
}
4646

4747
satsPerByte := uint64(feeRate * btcToSatoshis / kilobyteToByte)
48-
return pack.NewU256FromU64(pack.NewU64(satsPerByte)), pack.NewU256([32]byte{}), nil
48+
return pack.NewU256FromU64(pack.NewU64(satsPerByte)), pack.NewU256FromU64(pack.NewU64(satsPerByte)), nil
4949
}

‎chain/bitcoin/gas_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ var _ = Describe("Gas", func() {
1919

2020
// estimate fee to include tx within 1 block.
2121
gasEstimator1 := bitcoin.NewGasEstimator(client, 1)
22-
gasPrice1, _, err := gasEstimator1.EstimateGasPrice(ctx)
22+
gasPrice1, _, err := gasEstimator1.EstimateGas(ctx)
2323
Expect(err).NotTo(HaveOccurred())
2424

2525
// estimate fee to include tx within 10 blocks.
2626
gasEstimator2 := bitcoin.NewGasEstimator(client, 10)
27-
gasPrice2, _, err := gasEstimator2.EstimateGasPrice(ctx)
27+
gasPrice2, _, err := gasEstimator2.EstimateGas(ctx)
2828
Expect(err).NotTo(HaveOccurred())
2929

3030
// estimate fee to include tx within 100 blocks.
3131
gasEstimator3 := bitcoin.NewGasEstimator(client, 100)
32-
gasPrice3, _, err := gasEstimator3.EstimateGasPrice(ctx)
32+
gasPrice3, _, err := gasEstimator3.EstimateGas(ctx)
3333
Expect(err).NotTo(HaveOccurred())
3434

3535
// expect fees in this order at the very least.

‎chain/cosmos/gas.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ func NewGasEstimator(gasPerByte pack.U256) gas.Estimator {
2424
}
2525
}
2626

27-
// EstimateGasPrice returns gas required per byte for Cosmos-compatible chains.
28-
func (gasEstimator *GasEstimator) EstimateGasPrice(ctx context.Context) (pack.U256, pack.U256, error) {
29-
return gasEstimator.gasPerByte, pack.NewU256([32]byte{}), nil
27+
// EstimateGas returns gas required per byte for Cosmos-compatible chains. This
28+
// value is used for both the price and cap, because Cosmos-compatible chains do
29+
// not have a distinct concept of cap.
30+
func (gasEstimator *GasEstimator) EstimateGas(ctx context.Context) (pack.U256, pack.U256, error) {
31+
return gasEstimator.gasPerByte, gasEstimator.gasPerByte, nil
3032
}

‎chain/cosmos/tx.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func NewTxBuilder(options TxBuilderOptions, client *Client) account.TxBuilder {
4949
// BuildTx consumes a list of MsgSend to build and return a cosmos transaction.
5050
// This transaction is unsigned, and must be signed before submitting to the
5151
// cosmos chain.
52-
func (builder txBuilder) BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasPrice pack.U256, payload pack.Bytes) (account.Tx, error) {
52+
func (builder txBuilder) BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasPrice, gasCap pack.U256, payload pack.Bytes) (account.Tx, error) {
5353
fromAddr, err := types.AccAddressFromBech32(string(from))
5454
if err != nil {
5555
return nil, err

‎chain/filecoin/account.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,15 @@ import (
2020
// broadcasted to the filecoin network. The TxBuilder is configured using a
2121
// gas price and gas limit.
2222
type TxBuilder struct {
23-
gasPremium pack.U256
2423
}
2524

2625
// NewTxBuilder creates a new transaction builder.
27-
func NewTxBuilder(gasPremium pack.U256) TxBuilder {
28-
return TxBuilder{gasPremium}
26+
func NewTxBuilder() TxBuilder {
27+
return TxBuilder{}
2928
}
3029

3130
// BuildTx receives transaction fields and constructs a new transaction.
32-
func (txBuilder TxBuilder) BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasFeeCap pack.U256, payload pack.Bytes) (account.Tx, error) {
31+
func (txBuilder TxBuilder) BuildTx(ctx context.Context, from, to address.Address, value, nonce, gasLimit, gasPrice, gasCap pack.U256, payload pack.Bytes) (account.Tx, error) {
3332
filfrom, err := filaddress.NewFromString(string(from))
3433
if err != nil {
3534
return nil, fmt.Errorf("bad from address '%v': %v", from, err)
@@ -46,9 +45,9 @@ func (txBuilder TxBuilder) BuildTx(ctx context.Context, from, to address.Address
4645
To: filto,
4746
Value: big.Int{Int: value.Int()},
4847
Nonce: nonce.Int().Uint64(),
49-
GasFeeCap: big.Int{Int: gasFeeCap.Int()},
48+
GasFeeCap: big.Int{Int: gasCap.Int()},
5049
GasLimit: gasLimit.Int().Int64(),
51-
GasPremium: big.Int{Int: txBuilder.gasPremium.Int()},
50+
GasPremium: big.Int{Int: gasPrice.Int()},
5251
Method: methodNum,
5352
Params: payload,
5453
},

‎chain/filecoin/filecoin_test.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ var _ = Describe("Filecoin", func() {
6969
// get good gas estimates
7070
gasLimit := uint64(2200000)
7171
gasEstimator := filecoin.NewGasEstimator(client, int64(gasLimit))
72-
gasFeeCap, gasPremium, err := gasEstimator.EstimateGasPrice(ctx)
72+
gasPremium, gasFeeCap, err := gasEstimator.EstimateGas(ctx)
7373
Expect(err).ToNot(HaveOccurred())
7474

7575
// construct the transaction builder
76-
filTxBuilder := filecoin.NewTxBuilder(gasPremium)
76+
filTxBuilder := filecoin.NewTxBuilder()
7777

7878
// build the transaction
7979
sender := multichain.Address(pack.String(senderFilAddr.String()))
@@ -88,7 +88,8 @@ var _ = Describe("Filecoin", func() {
8888
amount, // amount
8989
nonce, // nonce
9090
pack.NewU256FromU64(pack.NewU64(gasLimit)), // gasLimit
91-
gasFeeCap, // gasFeeCap
91+
gasPremium,
92+
gasFeeCap,
9293
pack.Bytes(nil), // payload
9394
)
9495
Expect(err).ToNot(HaveOccurred())

‎chain/filecoin/gas.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,10 @@ func NewGasEstimator(client *Client, gasLimit int64) *GasEstimator {
3232
}
3333
}
3434

35-
// EstimateGasPrice returns gas fee cap and gas premium values being accepted
36-
// in the filecoin chain at present. These numbers may vary as the chain's
37-
// congestion level increases. It is safe to say that by using the fetched
38-
// values, a transaction will be included in a block with minimal delay.
39-
func (gasEstimator *GasEstimator) EstimateGasPrice(ctx context.Context) (pack.U256, pack.U256, error) {
35+
// EstimateGas returns an estimate of the current gas price (also known as gas
36+
// premium) and gas cap. These numbers change with congestion. These estimates
37+
// are often a little bit off, and this should be considered when using them.
38+
func (gasEstimator *GasEstimator) EstimateGas(ctx context.Context) (pack.U256, pack.U256, error) {
4039
// Create a dummy "Send" message.
4140
msgIn := types.Message{
4241
Version: types.MessageVersion,
@@ -68,5 +67,5 @@ func (gasEstimator *GasEstimator) EstimateGasPrice(ctx context.Context) (pack.U2
6867
gasFeeCap := big.NewInt(0).SetBytes(gasFeeCapBytes)
6968
gasPremium := big.NewInt(0).SetBytes(gasPremiumBytes)
7069

71-
return pack.NewU256FromInt(gasFeeCap), pack.NewU256FromInt(gasPremium), nil
70+
return pack.NewU256FromInt(gasPremium), pack.NewU256FromInt(gasFeeCap), nil
7271
}

‎chain/filecoin/gas_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ var _ = Describe("Gas", func() {
3333
gasEstimator := filecoin.NewGasEstimator(client, 2000000)
3434

3535
// estimate gas price
36-
_, _, err = gasEstimator.EstimateGasPrice(ctx)
36+
_, _, err = gasEstimator.EstimateGas(ctx)
3737
Expect(err).ToNot(HaveOccurred())
3838
})
3939
})

‎chain/terra/terra_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ var _ = Describe("Terra", func() {
7272
recipient, // to
7373
amount, // amount
7474
nonce, // nonce
75-
pack.NewU256FromU64(pack.U64(200000)), // gas
75+
pack.NewU256FromU64(pack.U64(200000)), // gas limit
7676
pack.NewU256FromU64(pack.U64(1)), // gas price
77+
pack.NewU256FromU64(pack.U64(1)), // gas cap
7778
payload, // memo
7879
)
7980
Expect(err).NotTo(HaveOccurred())

‎multichain_test.go

+16-13
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ var _ = Describe("Multichain", func() {
304304
rpcURL pack.String
305305
randomRecipientAddr func() multichain.Address
306306
initialise func(pack.String) (multichain.AccountClient, multichain.AccountTxBuilder)
307-
txParams func() (pack.U256, pack.U256, pack.U256, pack.Bytes)
307+
txParams func(multichain.AccountClient) (pack.U256, pack.U256, pack.U256, pack.U256, pack.Bytes)
308308
chain multichain.Chain
309309
}{
310310
{
@@ -355,12 +355,13 @@ var _ = Describe("Multichain", func() {
355355

356356
return client, txBuilder
357357
},
358-
func() (pack.U256, pack.U256, pack.U256, pack.Bytes) {
358+
func(_ multichain.AccountClient) (pack.U256, pack.U256, pack.U256, pack.U256, pack.Bytes) {
359359
amount := pack.NewU256FromU64(pack.U64(2000000))
360360
gasLimit := pack.NewU256FromU64(pack.U64(100000))
361361
gasPrice := pack.NewU256FromU64(pack.U64(1))
362+
gasCap := pack.NewU256FromInt(gasPrice.Int())
362363
payload := pack.NewBytes([]byte("multichain"))
363-
return amount, gasLimit, gasPrice, payload
364+
return amount, gasLimit, gasPrice, gasCap, payload
364365
},
365366
multichain.Terra,
366367
},
@@ -419,20 +420,22 @@ var _ = Describe("Multichain", func() {
419420
)
420421
Expect(err).NotTo(HaveOccurred())
421422

422-
gasEstimator := filecoin.NewGasEstimator(client, 2189560)
423-
_, gasPremium, err := gasEstimator.EstimateGasPrice(context.Background())
424-
Expect(err).NotTo(HaveOccurred())
425-
426-
txBuilder := filecoin.NewTxBuilder(gasPremium)
423+
txBuilder := filecoin.NewTxBuilder()
427424

428425
return client, txBuilder
429426
},
430-
func() (pack.U256, pack.U256, pack.U256, pack.Bytes) {
427+
func(client multichain.AccountClient) (pack.U256, pack.U256, pack.U256, pack.U256, pack.Bytes) {
431428
amount := pack.NewU256FromU64(pack.NewU64(100000000))
432429
gasLimit := pack.NewU256FromU64(pack.NewU64(2189560))
433-
gasPrice := pack.NewU256FromU64(pack.NewU64(300000))
430+
431+
// Fetch gas price and gas cap using the gas estimator.
432+
filecoinClient := client.(*filecoin.Client)
433+
gasPrice, gasCap, err := filecoin.NewGasEstimator(filecoinClient, gasLimit.Int().Int64()).
434+
EstimateGas(context.Background())
435+
Expect(err).NotTo(HaveOccurred())
436+
434437
payload := pack.Bytes(nil)
435-
return amount, gasLimit, gasPrice, payload
438+
return amount, gasLimit, gasPrice, gasCap, payload
436439
},
437440
multichain.Filecoin,
438441
},
@@ -457,13 +460,13 @@ var _ = Describe("Multichain", func() {
457460
Expect(err).NotTo(HaveOccurred())
458461

459462
// Build a transaction.
460-
amount, gasLimit, gasPrice, payload := accountChain.txParams()
463+
amount, gasLimit, gasPrice, gasCap, payload := accountChain.txParams(accountClient)
461464

462465
accountTx, err := txBuilder.BuildTx(
463466
ctx,
464467
multichain.Address(senderAddr),
465468
recipientAddr,
466-
amount, nonce, gasLimit, gasPrice,
469+
amount, nonce, gasLimit, gasPrice, gasCap,
467470
payload,
468471
)
469472
Expect(err).NotTo(HaveOccurred())

0 commit comments

Comments
 (0)
Please sign in to comment.