Skip to content

Commit

Permalink
Merge pull request #2874 from filecoin-project/feat/dyn-base-fee
Browse files Browse the repository at this point in the history
Introduce dynamic network fee
  • Loading branch information
magik6k authored Aug 7, 2020
2 parents 20e49e9 + bab7b80 commit b7695f9
Show file tree
Hide file tree
Showing 61 changed files with 774 additions and 383 deletions.
11 changes: 5 additions & 6 deletions api/api_full.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,17 @@ type FullNode interface {
// becomes available
BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error)

// GasEstimateFeeCap estimates gas fee cap
GasEstimateFeeCap(context.Context, int64, types.TipSetKey) (types.BigInt, error)

// GasEstimateGasLimit estimates gas used by the message and returns it.
// It fails if message fails to execute.
GasEstimateGasLimit(context.Context, *types.Message, types.TipSetKey) (int64, error)

// GasEstimateGasPrice estimates what gas price should be used for a
// GasEsitmateGasPremium estimates what gas price should be used for a
// message to have high likelihood of inclusion in `nblocksincl` epochs.

GasEstimateGasPrice(_ context.Context, nblocksincl uint64,
GasEsitmateGasPremium(_ context.Context, nblocksincl uint64,
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)

// MethodGroup: Sync
Expand Down Expand Up @@ -170,10 +173,6 @@ type FullNode interface {
MpoolGetNonce(context.Context, address.Address) (uint64, error)
MpoolSub(context.Context) (<-chan MpoolUpdate, error)

// MpoolEstimateGasPrice is depracated
// Deprecated: use GasEstimateGasPrice instead
MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)

// MethodGroup: Miner

MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*MiningBaseInfo, error)
Expand Down
17 changes: 9 additions & 8 deletions api/apistruct/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ type FullNodeStruct struct {

BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"`

GasEstimateGasPrice func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
GasEstimateGasLimit func(context.Context, *types.Message, types.TipSetKey) (int64, error) `perm:"read"`
GasEsitmateGasPremium func(context.Context, uint64, address.Address, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`
GasEstimateGasLimit func(context.Context, *types.Message, types.TipSetKey) (int64, error) `perm:"read"`
GasEstimateFeeCap func(context.Context, int64, types.TipSetKey) (types.BigInt, error) `perm:"read"`

SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
Expand Down Expand Up @@ -430,9 +431,13 @@ func (c *FullNodeStruct) ClientDealSize(ctx context.Context, root cid.Cid) (api.
return c.Internal.ClientDealSize(ctx, root)
}

func (c *FullNodeStruct) GasEstimateGasPrice(ctx context.Context, nblocksincl uint64,
func (c *FullNodeStruct) GasEsitmateGasPremium(ctx context.Context, nblocksincl uint64,
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.GasEstimateGasPrice(ctx, nblocksincl, sender, gaslimit, tsk)
return c.Internal.GasEsitmateGasPremium(ctx, nblocksincl, sender, gaslimit, tsk)
}
func (c *FullNodeStruct) GasEstimateFeeCap(ctx context.Context, maxqueueblks int64,
tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.GasEstimateFeeCap(ctx, maxqueueblks, tsk)
}

func (c *FullNodeStruct) GasEstimateGasLimit(ctx context.Context, msg *types.Message,
Expand Down Expand Up @@ -460,10 +465,6 @@ func (c *FullNodeStruct) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate,
return c.Internal.MpoolSub(ctx)
}

func (c *FullNodeStruct) MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, limit int64, tsk types.TipSetKey) (types.BigInt, error) {
return c.Internal.GasEstimateGasPrice(ctx, nblocksincl, sender, limit, tsk)
}

func (c *FullNodeStruct) MinerGetBaseInfo(ctx context.Context, maddr address.Address, epoch abi.ChainEpoch, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
return c.Internal.MinerGetBaseInfo(ctx, maddr, epoch, tsk)
}
Expand Down
17 changes: 7 additions & 10 deletions api/test/paych.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
t.Fatal(err)
}

sendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e10))
sendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))

// setup the payment channel
createrAddr, err := paymentCreator.WalletDefaultAddress(ctx)
Expand Down Expand Up @@ -218,10 +218,9 @@ func waitForBlocks(ctx context.Context, t *testing.T, bm *blockMiner, paymentRec

// Add a real block
m, err := paymentReceiver.MpoolPushMessage(ctx, &types.Message{
To: builtin.BurntFundsActorAddr,
From: receiverAddr,
Value: types.NewInt(0),
GasPrice: big.Zero(),
To: builtin.BurntFundsActorAddr,
From: receiverAddr,
Value: types.NewInt(0),
})
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -303,11 +302,9 @@ func sendFunds(ctx context.Context, t *testing.T, sender TestNode, addr address.
}

msg := &types.Message{
From: senderAddr,
To: addr,
Value: amount,
GasLimit: 0,
GasPrice: abi.NewTokenAmount(0),
From: senderAddr,
To: addr,
Value: amount,
}

sm, err := sender.MpoolPushMessage(ctx, msg)
Expand Down
8 changes: 6 additions & 2 deletions build/params_shared_vals.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,12 @@ const VerifSigCacheSize = 32000
// Limits

// TODO: If this is gonna stay, it should move to specs-actors
const BlockMessageLimit = 512
const BlockGasLimit = 7_500_000_000
const BlockMessageLimit = 10000
const BlockGasLimit = 10_000_000_000
const BlockGasTarget = BlockGasLimit / 2
const BaseFeeMaxChangeDenom = 8 // 12.5%
const InitialBaseFee = 100e6
const MinimumBaseFee = 100

// Actor consts
// TODO: Pull from actors when its made not private
Expand Down
2 changes: 1 addition & 1 deletion build/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
}

// APIVersion is a semver version of the rpc api exposed
var APIVersion Version = newVer(0, 8, 1)
var APIVersion Version = newVer(0, 9, 0)

//nolint:varcheck,deadcode
const (
Expand Down
2 changes: 1 addition & 1 deletion chain/blocksync/cbor_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions chain/gen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,8 +489,9 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {

Method: 0,

GasLimit: 100_000_000,
GasPrice: types.NewInt(0),
GasLimit: 100_000_000,
GasFeeCap: types.NewInt(0),
GasPremium: types.NewInt(0),
}

sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes())
Expand Down
13 changes: 12 additions & 1 deletion chain/gen/genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/util/adt"

"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types"
Expand Down Expand Up @@ -321,7 +322,16 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
verifNeeds := make(map[address.Address]abi.PaddedPieceSize)
var sum abi.PaddedPieceSize

vm, err := vm.NewVM(stateroot, 0, &fakeRand{}, cs.Blockstore(), mkFakedSigSyscalls(cs.VMSys()), nil)
vmopt := vm.VMOpts{
StateBase: stateroot,
Epoch: 0,
Rand: &fakeRand{},
Bstore: cs.Blockstore(),
Syscalls: mkFakedSigSyscalls(cs.VMSys()),
VestedCalc: nil,
BaseFee: types.NewInt(0),
}
vm, err := vm.NewVM(&vmopt)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
}
Expand Down Expand Up @@ -443,6 +453,7 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB
Data: make([]byte, 32),
},
},
ParentBaseFee: abi.NewTokenAmount(build.InitialBaseFee),
}

sb, err := b.ToStorageBlock()
Expand Down
15 changes: 13 additions & 2 deletions chain/gen/genesis/miners.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import (
"bytes"
"context"
"fmt"
"github.com/filecoin-project/lotus/chain/state"
"math/rand"

"github.com/filecoin-project/lotus/chain/state"

"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen"
Expand Down Expand Up @@ -60,7 +61,17 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
return big.Zero(), nil
}

vm, err := vm.NewVM(sroot, 0, &fakeRand{}, cs.Blockstore(), mkFakedSigSyscalls(cs.VMSys()), vc)
vmopt := &vm.VMOpts{
StateBase: sroot,
Epoch: 0,
Rand: &fakeRand{},
Bstore: cs.Blockstore(),
Syscalls: mkFakedSigSyscalls(cs.VMSys()),
VestedCalc: vc,
BaseFee: types.NewInt(0),
}

vm, err := vm.NewVM(vmopt)
if err != nil {
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
}
Expand Down
1 change: 0 additions & 1 deletion chain/gen/genesis/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value
Method: method,
Params: params,
GasLimit: 1_000_000_000_000_000,
GasPrice: types.NewInt(0),
Value: value,
Nonce: act.Nonce,
})
Expand Down
6 changes: 6 additions & 0 deletions chain/gen/mining.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
}
next.ParentWeight = pweight

baseFee, err := sm.ChainStore().ComputeBaseFee(ctx, pts)
if err != nil {
return nil, xerrors.Errorf("computing base fee: %w", err)
}
next.ParentBaseFee = baseFee

cst := cbor.NewCborStore(sm.ChainStore().Blockstore())
tree, err := state.LoadStateTree(cst, st)
if err != nil {
Expand Down
23 changes: 16 additions & 7 deletions chain/messagepool/messagepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,17 +126,17 @@ func (ms *msgSet) add(m *types.SignedMessage) (bool, error) {
if has {
if m.Cid() != exms.Cid() {
// check if RBF passes
minPrice := exms.Message.GasPrice
minPrice := exms.Message.GasPremium
minPrice = types.BigAdd(minPrice, types.BigDiv(types.BigMul(minPrice, rbfNum), rbfDenom))
minPrice = types.BigAdd(minPrice, types.NewInt(1))
if types.BigCmp(m.Message.GasPrice, minPrice) >= 0 {
log.Infow("add with RBF", "oldprice", exms.Message.GasPrice,
"newprice", m.Message.GasPrice, "addr", m.Message.From, "nonce", m.Message.Nonce)
if types.BigCmp(m.Message.GasPremium, minPrice) >= 0 {
log.Infow("add with RBF", "oldpremium", exms.Message.GasPremium,
"newpremium", m.Message.GasPremium, "addr", m.Message.From, "nonce", m.Message.Nonce)
} else {
log.Info("add with duplicate nonce")
return false, xerrors.Errorf("message from %s with nonce %d already in mpool,"+
" increase GasPrice to %s from %s to trigger replace by fee",
m.Message.From, m.Message.Nonce, minPrice, m.Message.GasPrice)
" increase GasPremium to %s from %s to trigger replace by fee",
m.Message.From, m.Message.Nonce, minPrice, m.Message.GasPremium)
}
}
}
Expand All @@ -154,6 +154,7 @@ type Provider interface {
MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error)
MessagesForTipset(*types.TipSet) ([]types.ChainMsg, error)
LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error)
}

type mpoolProvider struct {
Expand All @@ -162,7 +163,7 @@ type mpoolProvider struct {
}

func NewProvider(sm *stmgr.StateManager, ps *pubsub.PubSub) Provider {
return &mpoolProvider{sm, ps}
return &mpoolProvider{sm: sm, ps: ps}
}

func (mpp *mpoolProvider) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
Expand Down Expand Up @@ -199,6 +200,14 @@ func (mpp *mpoolProvider) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
return mpp.sm.ChainStore().LoadTipSet(tsk)
}

func (mpp *mpoolProvider) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
baseFee, err := mpp.sm.ChainStore().ComputeBaseFee(ctx, ts)
if err != nil {
return types.NewInt(0), xerrors.Errorf("computing base fee at %s: %w", ts, err)
}
return baseFee, nil
}

func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*MessagePool, error) {
cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
verifcache, _ := lru.New2Q(build.VerifSigCacheSize)
Expand Down
6 changes: 5 additions & 1 deletion chain/messagepool/messagepool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (tma *testMpoolAPI) PubSubPublish(string, []byte) error {
func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
balance, ok := tma.balance[addr]
if !ok {
balance = types.NewInt(90000000)
balance = types.NewInt(1000e6)
tma.balance[addr] = balance
}
return &types.Actor{
Expand Down Expand Up @@ -140,6 +140,10 @@ func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
return nil, fmt.Errorf("tipset not found")
}

func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
return types.NewInt(100), nil
}

func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) {
t.Helper()
n, err := mp.GetNonce(addr)
Expand Down
8 changes: 7 additions & 1 deletion chain/messagepool/pruning.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
)

func (mp *MessagePool) pruneExcessMessages() error {
Expand All @@ -30,6 +31,11 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro
log.Infof("message pruning took %s", time.Since(start))
}()

baseFee, err := mp.api.ChainComputeBaseFee(ctx, ts)
if err != nil {
return xerrors.Errorf("computing basefee: %w", err)
}

pending, _ := mp.getPendingMessages(ts, ts)

// Collect all messages to track which ones to remove and create chains for block inclusion
Expand All @@ -39,7 +45,7 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro
for _, m := range mset {
pruneMsgs[m.Message.Cid()] = m
}
actorChains := mp.createMessageChains(actor, mset, ts)
actorChains := mp.createMessageChains(actor, mset, baseFee, ts)
chains = append(chains, actorChains...)
}

Expand Down
Loading

0 comments on commit b7695f9

Please sign in to comment.