Skip to content

Commit

Permalink
Add a multiplier for gas tip that is independent of the base fee mult…
Browse files Browse the repository at this point in the history
…iplier, since base fee multiplier doesn't adequately handle sudden fee spikes.
  • Loading branch information
Roberto Bayardo committed Jul 29, 2022
1 parent e5e916c commit 24f3c85
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 20 deletions.
85 changes: 69 additions & 16 deletions services/construction/construction_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,14 @@ var (
transferNonceHex = hexutil.EncodeUint64(transferNonce) // 0x43
transferNonceHex2 = "0x22"
transferData = "0xa9059cbb000000000000000000000000efd3dc58d60af3295b92ecd484caeb3a2f30b3e7000000000000000000000000000000000000000000000000000000000134653c" //nolint
transferGasCap = uint64(30000000000) // 30 gwei
// transferGasCapHex = hexutil.EncodeUint64(transferGasCap) // 0x6FC23AC00
transferGasTip = uint64(30000000000) // 30 gwei, accounts for floor
transferGasTipHex = hexutil.EncodeUint64(transferGasTip) // 0x6FC23AC00
transferGasTipEstimate = uint64(3000000000) // 3 gwei
// transferGasTipEstimateHex = hexutil.EncodeUint64(transferGasTip) // 0xB2D05E00
transferGasCapWithTip = transferGasCap + 2*transferGasTip // 90 gwei

transferGasCap = uint64(30000000000) // 30 gwei
transferGasTip = uint64(30000000000) // 30 gwei, accounts for floor
transferGasTipHex = hexutil.EncodeUint64(transferGasTip) // 0x6FC23AC00
transferGasTipEstimate = uint64(3000000000) // 3 gwei
transferGasCapWithTip = 2*transferGasCap + transferGasTip // 90 gwei
transferGasCapWithTipHex = hexutil.EncodeUint64(transferGasCapWithTip) // 0x14F46B0400
minGasCap = big.NewInt(30000000000)
// minGasCapHex = hexutil.EncodeUint64(minGasCap.Uint64())

header = EthTypes.Header{
ParentHash: common.Hash{},
Expand Down Expand Up @@ -124,6 +122,7 @@ func forceMarshalMap(t *testing.T, i interface{}) map[string]interface{} {
}

func TestConstructionFlowWithPendingNonce(t *testing.T) {
tipMultiplier = 1.0 // These tests were created before we introduced a tip multiplier
cfg := &configuration.Configuration{
Mode: configuration.Online,
Network: networkIdentifier,
Expand Down Expand Up @@ -174,10 +173,10 @@ func TestConstructionFlowWithPendingNonce(t *testing.T) {
}, preprocessResponse)

// Test Metadata
metadata := &metadata{
metadata1 := &metadata{
GasLimit: 21000,
GasTip: big.NewInt(int64(transferGasTip)),
GasCap: big.NewInt(int64(transferGasCapWithTip)), // math: gasCap = new(big.Int).Add(gasTip, new(big.Int).Mul(baseFee, multiplier))
GasCap: big.NewInt(int64(transferGasCapWithTip)),
Nonce: 0,
To: constructionToAddress,
Value: big.NewInt(1000),
Expand Down Expand Up @@ -213,7 +212,7 @@ func TestConstructionFlowWithPendingNonce(t *testing.T) {
})
assert.Nil(t, err)
assert.Equal(t, &types.ConstructionMetadataResponse{
Metadata: forceMarshalMap(t, metadata),
Metadata: forceMarshalMap(t, metadata1),
SuggestedFee: []*types.Amount{
{
Value: "1890000000000000",
Expand All @@ -227,7 +226,7 @@ func TestConstructionFlowWithPendingNonce(t *testing.T) {
payloadsResponse, err := servicer.ConstructionPayloads(ctx, &types.ConstructionPayloadsRequest{
NetworkIdentifier: networkIdentifier,
Operations: ops,
Metadata: forceMarshalMap(t, metadata),
Metadata: forceMarshalMap(t, metadata1),
})
assert.Nil(t, err)

Expand All @@ -252,10 +251,10 @@ func TestConstructionFlowWithPendingNonce(t *testing.T) {
})
assert.Nil(t, err)
parseMetadata := &parseMetadata{
Nonce: metadata.Nonce,
GasCap: metadata.GasCap,
GasTip: metadata.GasTip,
GasLimit: metadata.GasLimit,
Nonce: metadata1.Nonce,
GasCap: metadata1.GasCap,
GasTip: metadata1.GasTip,
GasLimit: metadata1.GasLimit,
ChainID: big.NewInt(80001),
}
assert.Equal(t, &types.ConstructionParseResponse{
Expand Down Expand Up @@ -328,9 +327,63 @@ func TestConstructionFlowWithPendingNonce(t *testing.T) {
}, submitResponse)

mockClient.AssertExpectations(t)

// Test with non-1.0 gas tip multiplier
tipMultiplier = 1.2
mockClient.On(
"BlockHeader",
ctx,
blockNum,
).Return(
&header,
nil,
).Once()
mockClient.On(
"SuggestGasTipCap",
ctx,
).Return(
big.NewInt(int64(transferGasTipEstimate)), // this value is to be overriden by the 30 gwei min
nil,
).Once()
mockClient.On(
"PendingNonceAt",
ctx,
common.HexToAddress(constructionFromAddress),
).Return(
uint64(0),
nil,
).Once()

gasTip := multiplyBigInt(big.NewInt(int64(transferGasTip)), tipMultiplier)
gasCap := new(big.Int).Add(gasTip, big.NewInt(60000000000)) // tip + baseFee*2

metadata2 := &metadata{
GasLimit: 21000,
GasTip: gasTip,
GasCap: gasCap,
Nonce: 0,
To: constructionToAddress,
Value: big.NewInt(1000),
}

metadataResponse, err = servicer.ConstructionMetadata(ctx, &types.ConstructionMetadataRequest{
NetworkIdentifier: networkIdentifier,
Options: forceMarshalMap(t, &options),
})
assert.Nil(t, err)
assert.Equal(t, &types.ConstructionMetadataResponse{
Metadata: forceMarshalMap(t, metadata2),
SuggestedFee: []*types.Amount{
{
Value: "2016000000000000", // (2*30gwei + 1.2*30gwei) * 21000
Currency: polygon.Currency,
},
},
}, metadataResponse)
}

func TestConstructionFlowWithInputNonce(t *testing.T) {
tipMultiplier = 1.0 // These tests were created before there was a tip multiplier
networkIdentifier = &types.NetworkIdentifier{
Network: polygon.TestnetNetwork,
Blockchain: polygon.Blockchain,
Expand Down
26 changes: 22 additions & 4 deletions services/construction/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,24 @@ import (
svcErrors "github.com/maticnetwork/polygon-rosetta/services/errors"
)

var (
// Multipliers used for setting tx fees to a value unlikely to be too low for current block
// inclusion. TODO: Add command-line params to set these to non-default values.
baseFeeMultiplier float64 = 2.0
tipMultiplier float64 = 1.2
)

// multiplyBigInt multiplies i and multiplier using a big.Float with the result rounded to the
// nearest big.Int. i is modified to contain the result and returned.
func multiplyBigInt(i *big.Int, multiplier float64) *big.Int {
f := new(big.Float).SetInt(i)
m := big.NewFloat(multiplier)
f.Mul(f, m)
f.Add(f, new(big.Float).SetFloat64(.5)) // force rounding assuming f is non-negative
f.Int(i)
return i
}

// ConstructionMetadata implements the /construction/metadata endpoint.
func (a *APIService) ConstructionMetadata(
ctx context.Context,
Expand Down Expand Up @@ -130,13 +148,13 @@ func (a *APIService) ConstructionMetadata(
if minTip.Cmp(gasTip) == 1 {
gasTip = minTip
}
multiplyBigInt(gasTip, tipMultiplier)

var gasCap *big.Int
if input.GasCap == nil {
// Set default max fee to double the last base fee plus multiplied priority tip
// to ensure tx is highly likely to go out in the next block.
multiplier := big.NewInt(2)
gasCap = new(big.Int).Add(gasTip, new(big.Int).Mul(header.BaseFee, multiplier))
baseFee := new(big.Int).Set(header.BaseFee)
multiplyBigInt(baseFee, baseFeeMultiplier)
gasCap = baseFee.Add(baseFee, gasTip)
} else {
gasCap = input.GasCap
}
Expand Down

0 comments on commit 24f3c85

Please sign in to comment.