Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce dynamic network fee #2874

Merged
merged 29 commits into from
Aug 7, 2020
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a625943
Fix Weight issue
Aug 6, 2020
722d6e8
Introduce base fee
Aug 6, 2020
b384ac6
Compute correct base burns, miner tip and so on
Aug 6, 2020
6562b7a
Fix some tests
Aug 6, 2020
d676584
Fix some messagepool tests
Aug 6, 2020
562a3f4
Fix GasEstimateGasLimit
Aug 6, 2020
c29dd72
add check for feecap and premium to vm.checkMessage
Aug 6, 2020
4004c65
Fix chain types tests
Aug 6, 2020
ab08858
Delete GasPrice from this world
Aug 6, 2020
94a38cd
Fix mpool test
Aug 6, 2020
5ef7328
Rerun cbor-gen
magik6k Aug 6, 2020
cb47f87
Add todo
Aug 6, 2020
6ecd831
Fix TestPaymentChannels
magik6k Aug 6, 2020
07bf155
Merge remote-tracking branch 'origin/next' into feat/dyn-base-fee
magik6k Aug 6, 2020
e1de0e3
Estimate FeeCap 20 blocks in the future
Aug 6, 2020
79b701d
fix(chainwatch): gas columns are snake_cased; fix SQL bugs
placer14 Aug 6, 2020
2b2b632
Make mpool select only profitable messages
Aug 6, 2020
f45970a
Fix FeeCap estimation
Aug 6, 2020
f55ed9e
Update serialization vectors
Aug 6, 2020
754d6cf
Update chain-val
arajasek Aug 6, 2020
aa17d2b
Add tests
Aug 6, 2020
927f355
Remove MpoolEstimateGasPrice
Aug 7, 2020
05c527b
Hold tipset lock while selecting messages
Aug 7, 2020
122ec8c
Add CalculateBaseFee tests
Aug 7, 2020
467172f
Accually add tests
Aug 7, 2020
884d03f
address feedback
Aug 7, 2020
0612c2e
Merge remote-tracking branch 'origin/next' into feat/dyn-base-fee
magik6k Aug 7, 2020
617046f
params: Bump block message limit
magik6k Aug 7, 2020
bab7b80
update chain-val again
arajasek Aug 7, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions api/api_full.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,17 @@ type FullNode interface {
// ChainExport returns a stream of bytes with CAR dump of chain data.
ChainExport(context.Context, types.TipSetKey) (<-chan []byte, 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 @@ -162,10 +165,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 @@ -85,8 +85,9 @@ type FullNodeStruct struct {
ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"`
ChainExport func(context.Context, types.TipSetKey) (<-chan []byte, 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 @@ -428,9 +429,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 @@ -458,10 +463,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
6 changes: 5 additions & 1 deletion build/params_shared_vals.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,11 @@ const VerifSigCacheSize = 32000

// TODO: If this is gonna stay, it should move to specs-actors
const BlockMessageLimit = 512
const BlockGasLimit = 7_500_000_000
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