Merge pull request #2874 from filecoin-project/feat/dyn-base-fee

Introduce dynamic network fee
This commit is contained in:
Łukasz Magiera 2020-08-07 04:49:36 +02:00 committed by GitHub
commit b7695f9408
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 777 additions and 386 deletions

View File

@ -115,14 +115,17 @@ type FullNode interface {
// becomes available // becomes available
BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) 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. // GasEstimateGasLimit estimates gas used by the message and returns it.
// It fails if message fails to execute. // It fails if message fails to execute.
GasEstimateGasLimit(context.Context, *types.Message, types.TipSetKey) (int64, error) 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. // 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) sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error)
// MethodGroup: Sync // MethodGroup: Sync
@ -170,10 +173,6 @@ type FullNode interface {
MpoolGetNonce(context.Context, address.Address) (uint64, error) MpoolGetNonce(context.Context, address.Address) (uint64, error)
MpoolSub(context.Context) (<-chan MpoolUpdate, 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 // MethodGroup: Miner
MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*MiningBaseInfo, error) MinerGetBaseInfo(context.Context, address.Address, abi.ChainEpoch, types.TipSetKey) (*MiningBaseInfo, error)

View File

@ -87,8 +87,9 @@ type FullNodeStruct struct {
BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"` 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"` 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"` 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"` SyncState func(context.Context) (*api.SyncState, error) `perm:"read"`
SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"` SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"`
@ -430,9 +431,13 @@ func (c *FullNodeStruct) ClientDealSize(ctx context.Context, root cid.Cid) (api.
return c.Internal.ClientDealSize(ctx, root) 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) { 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, func (c *FullNodeStruct) GasEstimateGasLimit(ctx context.Context, msg *types.Message,
@ -460,10 +465,6 @@ func (c *FullNodeStruct) MpoolSub(ctx context.Context) (<-chan api.MpoolUpdate,
return c.Internal.MpoolSub(ctx) 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) { 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) return c.Internal.MinerGetBaseInfo(ctx, maddr, epoch, tsk)
} }

View File

@ -60,7 +60,7 @@ func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) {
t.Fatal(err) t.Fatal(err)
} }
sendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e10)) sendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
// setup the payment channel // setup the payment channel
createrAddr, err := paymentCreator.WalletDefaultAddress(ctx) createrAddr, err := paymentCreator.WalletDefaultAddress(ctx)
@ -218,10 +218,9 @@ func waitForBlocks(ctx context.Context, t *testing.T, bm *blockMiner, paymentRec
// Add a real block // Add a real block
m, err := paymentReceiver.MpoolPushMessage(ctx, &types.Message{ m, err := paymentReceiver.MpoolPushMessage(ctx, &types.Message{
To: builtin.BurntFundsActorAddr, To: builtin.BurntFundsActorAddr,
From: receiverAddr, From: receiverAddr,
Value: types.NewInt(0), Value: types.NewInt(0),
GasPrice: big.Zero(),
}) })
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -303,11 +302,9 @@ func sendFunds(ctx context.Context, t *testing.T, sender TestNode, addr address.
} }
msg := &types.Message{ msg := &types.Message{
From: senderAddr, From: senderAddr,
To: addr, To: addr,
Value: amount, Value: amount,
GasLimit: 0,
GasPrice: abi.NewTokenAmount(0),
} }
sm, err := sender.MpoolPushMessage(ctx, msg) sm, err := sender.MpoolPushMessage(ctx, msg)

View File

@ -88,8 +88,12 @@ const VerifSigCacheSize = 32000
// Limits // Limits
// TODO: If this is gonna stay, it should move to specs-actors // TODO: If this is gonna stay, it should move to specs-actors
const BlockMessageLimit = 512 const BlockMessageLimit = 10000
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 // Actor consts
// TODO: Pull from actors when its made not private // TODO: Pull from actors when its made not private

View File

@ -53,7 +53,7 @@ func (ve Version) EqMajorMinor(v2 Version) bool {
} }
// APIVersion is a semver version of the rpc api exposed // 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 //nolint:varcheck,deadcode
const ( const (

View File

@ -7,7 +7,7 @@ import (
"io" "io"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors" xerrors "golang.org/x/xerrors"
) )

View File

@ -489,8 +489,9 @@ func getRandomMessages(cg *ChainGen) ([]*types.SignedMessage, error) {
Method: 0, Method: 0,
GasLimit: 100_000_000, GasLimit: 100_000_000,
GasPrice: types.NewInt(0), GasFeeCap: types.NewInt(0),
GasPremium: types.NewInt(0),
} }
sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes()) sig, err := cg.w.Sign(context.TODO(), cg.banker, msg.Cid().Bytes())

View File

@ -21,6 +21,7 @@ import (
"github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/util/adt" "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/state"
"github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
@ -321,7 +322,16 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci
verifNeeds := make(map[address.Address]abi.PaddedPieceSize) verifNeeds := make(map[address.Address]abi.PaddedPieceSize)
var sum 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 { if err != nil {
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
} }
@ -443,6 +453,7 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallB
Data: make([]byte, 32), Data: make([]byte, 32),
}, },
}, },
ParentBaseFee: abi.NewTokenAmount(build.InitialBaseFee),
} }
sb, err := b.ToStorageBlock() sb, err := b.ToStorageBlock()

View File

@ -4,9 +4,10 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"github.com/filecoin-project/lotus/chain/state"
"math/rand" "math/rand"
"github.com/filecoin-project/lotus/chain/state"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
@ -60,7 +61,17 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
return big.Zero(), nil 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 { if err != nil {
return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err)
} }

View File

@ -37,7 +37,6 @@ func doExecValue(ctx context.Context, vm *vm.VM, to, from address.Address, value
Method: method, Method: method,
Params: params, Params: params,
GasLimit: 1_000_000_000_000_000, GasLimit: 1_000_000_000_000_000,
GasPrice: types.NewInt(0),
Value: value, Value: value,
Nonce: act.Nonce, Nonce: act.Nonce,
}) })

View File

@ -109,6 +109,12 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
} }
next.ParentWeight = pweight 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()) cst := cbor.NewCborStore(sm.ChainStore().Blockstore())
tree, err := state.LoadStateTree(cst, st) tree, err := state.LoadStateTree(cst, st)
if err != nil { if err != nil {

View File

@ -126,17 +126,17 @@ func (ms *msgSet) add(m *types.SignedMessage) (bool, error) {
if has { if has {
if m.Cid() != exms.Cid() { if m.Cid() != exms.Cid() {
// check if RBF passes // 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.BigDiv(types.BigMul(minPrice, rbfNum), rbfDenom))
minPrice = types.BigAdd(minPrice, types.NewInt(1)) minPrice = types.BigAdd(minPrice, types.NewInt(1))
if types.BigCmp(m.Message.GasPrice, minPrice) >= 0 { if types.BigCmp(m.Message.GasPremium, minPrice) >= 0 {
log.Infow("add with RBF", "oldprice", exms.Message.GasPrice, log.Infow("add with RBF", "oldpremium", exms.Message.GasPremium,
"newprice", m.Message.GasPrice, "addr", m.Message.From, "nonce", m.Message.Nonce) "newpremium", m.Message.GasPremium, "addr", m.Message.From, "nonce", m.Message.Nonce)
} else { } else {
log.Info("add with duplicate nonce") log.Info("add with duplicate nonce")
return false, xerrors.Errorf("message from %s with nonce %d already in mpool,"+ return false, xerrors.Errorf("message from %s with nonce %d already in mpool,"+
" increase GasPrice to %s from %s to trigger replace by fee", " increase GasPremium to %s from %s to trigger replace by fee",
m.Message.From, m.Message.Nonce, minPrice, m.Message.GasPrice) m.Message.From, m.Message.Nonce, minPrice, m.Message.GasPremium)
} }
} }
} }
@ -154,6 +154,7 @@ type Provider interface {
MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) MessagesForBlock(*types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error)
MessagesForTipset(*types.TipSet) ([]types.ChainMsg, error) MessagesForTipset(*types.TipSet) ([]types.ChainMsg, error)
LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error)
} }
type mpoolProvider struct { type mpoolProvider struct {
@ -162,7 +163,7 @@ type mpoolProvider struct {
} }
func NewProvider(sm *stmgr.StateManager, ps *pubsub.PubSub) Provider { 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 { func (mpp *mpoolProvider) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
@ -199,6 +200,14 @@ func (mpp *mpoolProvider) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
return mpp.sm.ChainStore().LoadTipSet(tsk) 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) { func New(api Provider, ds dtypes.MetadataDS, netName dtypes.NetworkName) (*MessagePool, error) {
cache, _ := lru.New2Q(build.BlsSignatureCacheSize) cache, _ := lru.New2Q(build.BlsSignatureCacheSize)
verifcache, _ := lru.New2Q(build.VerifSigCacheSize) verifcache, _ := lru.New2Q(build.VerifSigCacheSize)

View File

@ -87,7 +87,7 @@ func (tma *testMpoolAPI) PubSubPublish(string, []byte) error {
func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) { func (tma *testMpoolAPI) StateGetActor(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
balance, ok := tma.balance[addr] balance, ok := tma.balance[addr]
if !ok { if !ok {
balance = types.NewInt(90000000) balance = types.NewInt(1000e6)
tma.balance[addr] = balance tma.balance[addr] = balance
} }
return &types.Actor{ return &types.Actor{
@ -140,6 +140,10 @@ func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error)
return nil, fmt.Errorf("tipset not found") 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) { func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) {
t.Helper() t.Helper()
n, err := mp.GetNonce(addr) n, err := mp.GetNonce(addr)

View File

@ -7,6 +7,7 @@ import (
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"golang.org/x/xerrors"
) )
func (mp *MessagePool) pruneExcessMessages() error { func (mp *MessagePool) pruneExcessMessages() error {
@ -30,6 +31,11 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro
log.Infof("message pruning took %s", time.Since(start)) 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) pending, _ := mp.getPendingMessages(ts, ts)
// Collect all messages to track which ones to remove and create chains for block inclusion // Collect all messages to track which ones to remove and create chains for block inclusion
@ -39,7 +45,7 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro
for _, m := range mset { for _, m := range mset {
pruneMsgs[m.Message.Cid()] = m pruneMsgs[m.Message.Cid()] = m
} }
actorChains := mp.createMessageChains(actor, mset, ts) actorChains := mp.createMessageChains(actor, mset, baseFee, ts)
chains = append(chains, actorChains...) chains = append(chains, actorChains...)
} }

View File

@ -30,20 +30,21 @@ type msgChain struct {
func (mp *MessagePool) SelectMessages(ts *types.TipSet) ([]*types.SignedMessage, error) { func (mp *MessagePool) SelectMessages(ts *types.TipSet) ([]*types.SignedMessage, error) {
mp.curTsLk.Lock() mp.curTsLk.Lock()
curTs := mp.curTs defer mp.curTsLk.Unlock()
mp.curTsLk.Unlock()
mp.lk.Lock() mp.lk.Lock()
defer mp.lk.Unlock() defer mp.lk.Unlock()
return mp.selectMessages(curTs, ts) return mp.selectMessages(mp.curTs, ts)
} }
func (mp *MessagePool) selectMessages(curTs, ts *types.TipSet) ([]*types.SignedMessage, error) { func (mp *MessagePool) selectMessages(curTs, ts *types.TipSet) ([]*types.SignedMessage, error) {
start := time.Now() start := time.Now()
defer func() {
log.Infof("message selection took %s", time.Since(start)) baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), ts)
}() if err != nil {
return nil, xerrors.Errorf("computing basefee: %w", err)
}
// 0. Load messages for the target tipset; if it is the same as the current tipset in the mpool // 0. Load messages for the target tipset; if it is the same as the current tipset in the mpool
// then this is just the pending messages // then this is just the pending messages
@ -51,11 +52,19 @@ func (mp *MessagePool) selectMessages(curTs, ts *types.TipSet) ([]*types.SignedM
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(pending) == 0 {
return nil, nil
}
// defer only here so if we have no pending messages we don't spam
defer func() {
log.Infof("message selection took %s", time.Since(start))
}()
// 1. Create a list of dependent message chains with maximal gas reward per limit consumed // 1. Create a list of dependent message chains with maximal gas reward per limit consumed
var chains []*msgChain var chains []*msgChain
for actor, mset := range pending { for actor, mset := range pending {
next := mp.createMessageChains(actor, mset, ts) next := mp.createMessageChains(actor, mset, baseFee, ts)
chains = append(chains, next...) chains = append(chains, next...)
} }
@ -63,6 +72,13 @@ func (mp *MessagePool) selectMessages(curTs, ts *types.TipSet) ([]*types.SignedM
sort.Slice(chains, func(i, j int) bool { sort.Slice(chains, func(i, j int) bool {
return chains[i].Before(chains[j]) return chains[i].Before(chains[j])
}) })
if len(chains) != 0 && chains[0].gasPerf < 0 {
log.Warnw("all messages in mpool have negative has performance", "bestGasPerf", chains[0].gasPerf)
//for i, m := range chains[0].msgs {
//log.Warnf("msg %d %+v", i, m.Message)
//}
return nil, nil
}
// 3. Merge the head chains to produce the list of messages selected for inclusion, subject to // 3. Merge the head chains to produce the list of messages selected for inclusion, subject to
// the block gas limit. // the block gas limit.
@ -72,7 +88,7 @@ func (mp *MessagePool) selectMessages(curTs, ts *types.TipSet) ([]*types.SignedM
last := len(chains) last := len(chains)
for i, chain := range chains { for i, chain := range chains {
// does it fit in the block? // does it fit in the block?
if chain.gasLimit <= gasLimit { if chain.gasLimit <= gasLimit && chain.gasPerf > 0 {
gasLimit -= chain.gasLimit gasLimit -= chain.gasLimit
result = append(result, chain.msgs...) result = append(result, chain.msgs...)
continue continue
@ -92,7 +108,7 @@ func (mp *MessagePool) selectMessages(curTs, ts *types.TipSet) ([]*types.SignedM
tailLoop: tailLoop:
for gasLimit >= minGas && last < len(chains) { for gasLimit >= minGas && last < len(chains) {
// trim // trim
chains[last].Trim(gasLimit, mp, ts) chains[last].Trim(gasLimit, mp, baseFee, ts)
// push down if it hasn't been invalidated // push down if it hasn't been invalidated
if chains[last].valid { if chains[last].valid {
@ -111,7 +127,7 @@ tailLoop:
continue continue
} }
// does it fit in the bock? // does it fit in the bock?
if chain.gasLimit <= gasLimit { if chain.gasLimit <= gasLimit && chain.gasPerf > 0 {
gasLimit -= chain.gasLimit gasLimit -= chain.gasLimit
result = append(result, chain.msgs...) result = append(result, chain.msgs...)
continue continue
@ -208,7 +224,7 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address.
if dupNonce { if dupNonce {
// duplicate nonce, selfishly keep the message with the highest GasPrice // duplicate nonce, selfishly keep the message with the highest GasPrice
// if the gas prices are the same, keep the one with the highest GasLimit // if the gas prices are the same, keep the one with the highest GasLimit
switch m.Message.GasPrice.Int.Cmp(other.Message.GasPrice.Int) { switch m.Message.GasPremium.Int.Cmp(other.Message.GasPremium.Int) {
case 0: case 0:
if m.Message.GasLimit > other.Message.GasLimit { if m.Message.GasLimit > other.Message.GasLimit {
mset[m.Message.Nonce] = m mset[m.Message.Nonce] = m
@ -232,20 +248,12 @@ func (mp *MessagePool) getPendingMessages(curTs, ts *types.TipSet) (map[address.
} }
} }
func (mp *MessagePool) getGasReward(msg *types.SignedMessage, ts *types.TipSet) *big.Int { func (mp *MessagePool) getGasReward(msg *types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) *big.Int {
al := func(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error) { gasReward := abig.Mul(msg.Message.GasPremium, types.NewInt(uint64(msg.Message.GasLimit)))
return mp.api.StateGetActor(addr, ts) maxReward := types.BigSub(msg.Message.GasFeeCap, baseFee)
if types.BigCmp(maxReward, gasReward) < 0 {
gasReward = maxReward
} }
gasUsed, err := gasguess.GuessGasUsed(context.TODO(), types.EmptyTSK, msg, al)
if err != nil {
gasUsed = int64(gasguess.MaxGas)
if gasUsed > msg.Message.GasLimit/2 {
gasUsed = msg.Message.GasLimit / 2
}
// if we start seeing this warning we may have a problem with spammers!
log.Warnf("Cannot guess gas usage for message: %s; using %d", err, gasUsed)
}
gasReward := abig.Mul(msg.Message.GasPrice, types.NewInt(uint64(gasUsed)))
return gasReward.Int return gasReward.Int
} }
@ -258,7 +266,7 @@ func (mp *MessagePool) getGasPerf(gasReward *big.Int, gasLimit int64) float64 {
return r return r
} }
func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint64]*types.SignedMessage, ts *types.TipSet) []*msgChain { func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint64]*types.SignedMessage, baseFee types.BigInt, ts *types.TipSet) []*msgChain {
// collect all messages // collect all messages
msgs := make([]*types.SignedMessage, 0, len(mset)) msgs := make([]*types.SignedMessage, 0, len(mset))
for _, m := range mset { for _, m := range mset {
@ -320,7 +328,7 @@ func (mp *MessagePool) createMessageChains(actor address.Address, mset map[uint6
balance = new(big.Int).Sub(balance, value) balance = new(big.Int).Sub(balance, value)
} }
gasReward := mp.getGasReward(m, ts) gasReward := mp.getGasReward(m, baseFee, ts)
rewards = append(rewards, gasReward) rewards = append(rewards, gasReward)
} }
@ -417,11 +425,11 @@ func (mc *msgChain) Before(other *msgChain) bool {
(mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0) (mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0)
} }
func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, ts *types.TipSet) { func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, ts *types.TipSet) {
i := len(mc.msgs) - 1 i := len(mc.msgs) - 1
for i >= 0 && mc.gasLimit > gasLimit { for i >= 0 && mc.gasLimit > gasLimit {
gasLimit -= mc.msgs[i].Message.GasLimit gasLimit -= mc.msgs[i].Message.GasLimit
gasReward := mp.getGasReward(mc.msgs[i], ts) gasReward := mp.getGasReward(mc.msgs[i], baseFee, ts)
mc.gasReward = new(big.Int).Sub(mc.gasReward, gasReward) mc.gasReward = new(big.Int).Sub(mc.gasReward, gasReward)
mc.gasLimit -= mc.msgs[i].Message.GasLimit mc.gasLimit -= mc.msgs[i].Message.GasLimit
if mc.gasLimit > 0 { if mc.gasLimit > 0 {

View File

@ -20,13 +20,14 @@ import (
func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage { func makeTestMessage(w *wallet.Wallet, from, to address.Address, nonce uint64, gasLimit int64, gasPrice uint64) *types.SignedMessage {
msg := &types.Message{ msg := &types.Message{
From: from, From: from,
To: to, To: to,
Method: 2, Method: 2,
Value: types.FromFil(0), Value: types.FromFil(0),
Nonce: nonce, Nonce: nonce,
GasLimit: gasLimit, GasLimit: gasLimit,
GasPrice: types.NewInt(gasPrice), GasFeeCap: types.NewInt(100 + gasPrice),
GasPremium: types.NewInt(gasPrice),
} }
sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes()) sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes())
if err != nil { if err != nil {
@ -89,8 +90,9 @@ func TestMessageChains(t *testing.T) {
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1)) m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
mset[uint64(i)] = m mset[uint64(i)] = m
} }
baseFee := types.NewInt(0)
chains := mp.createMessageChains(a1, mset, ts) chains := mp.createMessageChains(a1, mset, baseFee, ts)
if len(chains) != 1 { if len(chains) != 1 {
t.Fatal("expected a single chain") t.Fatal("expected a single chain")
} }
@ -111,7 +113,7 @@ func TestMessageChains(t *testing.T) {
mset[uint64(i)] = m mset[uint64(i)] = m
} }
chains = mp.createMessageChains(a1, mset, ts) chains = mp.createMessageChains(a1, mset, baseFee, ts)
if len(chains) != 10 { if len(chains) != 10 {
t.Fatal("expected 10 chains") t.Fatal("expected 10 chains")
} }
@ -135,7 +137,7 @@ func TestMessageChains(t *testing.T) {
mset[uint64(i)] = m mset[uint64(i)] = m
} }
chains = mp.createMessageChains(a1, mset, ts) chains = mp.createMessageChains(a1, mset, baseFee, ts)
if len(chains) != 2 { if len(chains) != 2 {
t.Fatal("expected 1 chain") t.Fatal("expected 1 chain")
} }
@ -166,7 +168,7 @@ func TestMessageChains(t *testing.T) {
mset[uint64(i)] = m mset[uint64(i)] = m
} }
chains = mp.createMessageChains(a1, mset, ts) chains = mp.createMessageChains(a1, mset, baseFee, ts)
if len(chains) != 4 { if len(chains) != 4 {
t.Fatal("expected 4 chains") t.Fatal("expected 4 chains")
} }
@ -199,7 +201,7 @@ func TestMessageChains(t *testing.T) {
mset[uint64(i)] = m mset[uint64(i)] = m
} }
chains = mp.createMessageChains(a1, mset, ts) chains = mp.createMessageChains(a1, mset, baseFee, ts)
if len(chains) != 1 { if len(chains) != 1 {
t.Fatal("expected a single chain") t.Fatal("expected a single chain")
} }
@ -225,7 +227,7 @@ func TestMessageChains(t *testing.T) {
mset[uint64(i)] = m mset[uint64(i)] = m
} }
chains = mp.createMessageChains(a1, mset, ts) chains = mp.createMessageChains(a1, mset, baseFee, ts)
if len(chains) != 1 { if len(chains) != 1 {
t.Fatal("expected a single chain") t.Fatal("expected a single chain")
} }
@ -248,7 +250,7 @@ func TestMessageChains(t *testing.T) {
mset[uint64(i)] = makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1)) mset[uint64(i)] = makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
} }
chains = mp.createMessageChains(a1, mset, ts) chains = mp.createMessageChains(a1, mset, baseFee, ts)
if len(chains) != 1 { if len(chains) != 1 {
t.Fatal("expected a single chain") t.Fatal("expected a single chain")
} }
@ -262,16 +264,16 @@ func TestMessageChains(t *testing.T) {
} }
// test5: insufficient balance for all messages // test5: insufficient balance for all messages
tma.setBalanceRaw(a1, types.NewInt(uint64(3*gasLimit+1))) tma.setBalanceRaw(a1, types.NewInt(uint64((300)*gasLimit+1)))
mset = make(map[uint64]*types.SignedMessage) mset = make(map[uint64]*types.SignedMessage)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
mset[uint64(i)] = makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1)) mset[uint64(i)] = makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
} }
chains = mp.createMessageChains(a1, mset, ts) chains = mp.createMessageChains(a1, mset, baseFee, ts)
if len(chains) != 1 { if len(chains) != 1 {
t.Fatal("expected a single chain") t.Fatalf("expected a single chain: got %d", len(chains))
} }
if len(chains[0].msgs) != 2 { if len(chains[0].msgs) != 2 {
t.Fatalf("expected %d message in the chain but got %d", 2, len(chains[0].msgs)) t.Fatalf("expected %d message in the chain but got %d", 2, len(chains[0].msgs))

View File

@ -22,7 +22,17 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
ctx, span := trace.StartSpan(ctx, "statemanager.CallRaw") ctx, span := trace.StartSpan(ctx, "statemanager.CallRaw")
defer span.End() defer span.End()
vmi, err := vm.NewVM(bstate, bheight, r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds) vmopt := &vm.VMOpts{
StateBase: bstate,
Epoch: bheight,
Rand: r,
Bstore: sm.cs.Blockstore(),
Syscalls: sm.cs.VMSys(),
VestedCalc: sm.GetVestedFunds,
BaseFee: types.NewInt(0),
}
vmi, err := vm.NewVM(vmopt)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err) return nil, xerrors.Errorf("failed to set up vm: %w", err)
} }
@ -30,9 +40,13 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
if msg.GasLimit == 0 { if msg.GasLimit == 0 {
msg.GasLimit = build.BlockGasLimit msg.GasLimit = build.BlockGasLimit
} }
if msg.GasPrice == types.EmptyInt { if msg.GasFeeCap == types.EmptyInt {
msg.GasPrice = types.NewInt(0) msg.GasFeeCap = types.NewInt(0)
} }
if msg.GasPremium == types.EmptyInt {
msg.GasPremium = types.NewInt(0)
}
if msg.Value == types.EmptyInt { if msg.Value == types.EmptyInt {
msg.Value = types.NewInt(0) msg.Value = types.NewInt(0)
} }
@ -40,7 +54,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate
if span.IsRecordingEvents() { if span.IsRecordingEvents() {
span.AddAttributes( span.AddAttributes(
trace.Int64Attribute("gas_limit", msg.GasLimit), trace.Int64Attribute("gas_limit", msg.GasLimit),
trace.Int64Attribute("gas_price", int64(msg.GasPrice.Uint64())), trace.StringAttribute("gas_feecap", msg.GasFeeCap.String()),
trace.StringAttribute("value", msg.Value.String()), trace.StringAttribute("value", msg.Value.String()),
) )
} }
@ -101,12 +115,21 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri
if span.IsRecordingEvents() { if span.IsRecordingEvents() {
span.AddAttributes( span.AddAttributes(
trace.Int64Attribute("gas_limit", msg.GasLimit), trace.Int64Attribute("gas_limit", msg.GasLimit),
trace.Int64Attribute("gas_price", int64(msg.GasPrice.Uint64())), trace.StringAttribute("gas_feecap", msg.GasFeeCap.String()),
trace.StringAttribute("value", msg.Value.String()), trace.StringAttribute("value", msg.Value.String()),
) )
} }
vmi, err := vm.NewVM(state, ts.Height(), r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds) vmopt := &vm.VMOpts{
StateBase: state,
Epoch: ts.Height(),
Rand: r,
Bstore: sm.cs.Blockstore(),
Syscalls: sm.cs.VMSys(),
VestedCalc: sm.GetVestedFunds,
BaseFee: ts.Blocks()[0].ParentBaseFee,
}
vmi, err := vm.NewVM(vmopt)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to set up vm: %w", err) return nil, xerrors.Errorf("failed to set up vm: %w", err)
} }

View File

@ -25,11 +25,9 @@ import (
. "github.com/filecoin-project/lotus/chain/stmgr" . "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/lib/blockstore"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/bls"
_ "github.com/filecoin-project/lotus/lib/sigs/secp" _ "github.com/filecoin-project/lotus/lib/sigs/secp"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log" logging "github.com/ipfs/go-log"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
@ -151,8 +149,8 @@ func TestForkHeightTriggers(t *testing.T) {
} }
inv.Register(builtin.PaymentChannelActorCodeID, &testActor{}, &testActorState{}) inv.Register(builtin.PaymentChannelActorCodeID, &testActor{}, &testActorState{})
sm.SetVMConstructor(func(c cid.Cid, h abi.ChainEpoch, r vm.Rand, b blockstore.Blockstore, s vm.SyscallBuilder, vc vm.VestedCalculator) (*vm.VM, error) { sm.SetVMConstructor(func(vmopt *vm.VMOpts) (*vm.VM, error) {
nvm, err := vm.NewVM(c, h, r, b, s, sm.GetVestedFunds) nvm, err := vm.NewVM(vmopt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -175,7 +173,6 @@ func TestForkHeightTriggers(t *testing.T) {
Method: builtin.MethodsInit.Exec, Method: builtin.MethodsInit.Exec,
Params: enc, Params: enc,
GasLimit: types.TestGasLimit, GasLimit: types.TestGasLimit,
GasPrice: types.NewInt(0),
} }
sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes()) sig, err := cg.Wallet().Sign(ctx, cg.Banker(), m.Cid().Bytes())
if err != nil { if err != nil {
@ -202,7 +199,6 @@ func TestForkHeightTriggers(t *testing.T) {
Params: nil, Params: nil,
Nonce: nonce, Nonce: nonce,
GasLimit: types.TestGasLimit, GasLimit: types.TestGasLimit,
GasPrice: types.NewInt(0),
} }
nonce++ nonce++

View File

@ -3,9 +3,10 @@ package stmgr
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
"sync" "sync"
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
@ -14,7 +15,6 @@ import (
"github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/lib/blockstore"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/abi/big"
@ -41,7 +41,7 @@ type StateManager struct {
compWait map[string]chan struct{} compWait map[string]chan struct{}
stlk sync.Mutex stlk sync.Mutex
genesisMsigLk sync.Mutex genesisMsigLk sync.Mutex
newVM func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, vm.SyscallBuilder, vm.VestedCalculator) (*vm.VM, error) newVM func(*vm.VMOpts) (*vm.VM, error)
genesisMsigs []multisig.State genesisMsigs []multisig.State
} }
@ -150,8 +150,19 @@ type BlockMessages struct {
type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error
func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback) (cid.Cid, cid.Cid, error) { func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount) (cid.Cid, cid.Cid, error) {
vmi, err := sm.newVM(pstate, epoch, r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds)
vmopt := &vm.VMOpts{
StateBase: pstate,
Epoch: epoch,
Rand: r,
Bstore: sm.cs.Blockstore(),
Syscalls: sm.cs.VMSys(),
VestedCalc: sm.GetVestedFunds,
BaseFee: baseFee,
}
vmi, err := sm.newVM(vmopt)
if err != nil { if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err) return cid.Undef, cid.Undef, xerrors.Errorf("instantiating VM failed: %w", err)
} }
@ -164,14 +175,15 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
} }
cronMsg := &types.Message{ cronMsg := &types.Message{
To: builtin.CronActorAddr, To: builtin.CronActorAddr,
From: builtin.SystemActorAddr, From: builtin.SystemActorAddr,
Nonce: ca.Nonce, Nonce: ca.Nonce,
Value: types.NewInt(0), Value: types.NewInt(0),
GasPrice: types.NewInt(0), GasFeeCap: types.NewInt(0),
GasLimit: build.BlockGasLimit * 10000, // Make super sure this is never too little GasPremium: types.NewInt(0),
Method: builtin.MethodsCron.EpochTick, GasLimit: build.BlockGasLimit * 10000, // Make super sure this is never too little
Params: nil, Method: builtin.MethodsCron.EpochTick,
Params: nil,
} }
ret, err := vmi.ApplyImplicitMessage(ctx, cronMsg) ret, err := vmi.ApplyImplicitMessage(ctx, cronMsg)
if err != nil { if err != nil {
@ -223,7 +235,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
} }
receipts = append(receipts, &r.MessageReceipt) receipts = append(receipts, &r.MessageReceipt)
gasReward = big.Add(gasReward, big.Mul(m.GasPrice, big.NewInt(r.GasUsed))) gasReward = big.Add(gasReward, r.MinerTip)
penalty = big.Add(penalty, r.Penalty) penalty = big.Add(penalty, r.Penalty)
if cb != nil { if cb != nil {
@ -251,14 +263,15 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp
} }
rwMsg := &types.Message{ rwMsg := &types.Message{
From: builtin.SystemActorAddr, From: builtin.SystemActorAddr,
To: builtin.RewardActorAddr, To: builtin.RewardActorAddr,
Nonce: sysAct.Nonce, Nonce: sysAct.Nonce,
Value: types.NewInt(0), Value: types.NewInt(0),
GasPrice: types.NewInt(0), GasFeeCap: types.NewInt(0),
GasLimit: 1 << 30, GasPremium: types.NewInt(0),
Method: builtin.MethodsReward.AwardBlockReward, GasLimit: 1 << 30,
Params: params, Method: builtin.MethodsReward.AwardBlockReward,
Params: params,
} }
ret, err := vmi.ApplyImplicitMessage(ctx, rwMsg) ret, err := vmi.ApplyImplicitMessage(ctx, rwMsg)
if err != nil { if err != nil {
@ -354,8 +367,9 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, blks []*types.Bl
blkmsgs = append(blkmsgs, bm) blkmsgs = append(blkmsgs, bm)
} }
baseFee := blks[0].ParentBaseFee
return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb) return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee)
} }
func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid { func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid {
@ -764,7 +778,7 @@ func (sm *StateManager) ValidateChain(ctx context.Context, ts *types.TipSet) err
return nil return nil
} }
func (sm *StateManager) SetVMConstructor(nvm func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, vm.SyscallBuilder, vm.VestedCalculator) (*vm.VM, error)) { func (sm *StateManager) SetVMConstructor(nvm func(*vm.VMOpts) (*vm.VM, error)) {
sm.newVM = nvm sm.newVM = nvm
} }

View File

@ -440,7 +440,16 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
} }
r := store.NewChainRand(sm.cs, ts.Cids(), height) r := store.NewChainRand(sm.cs, ts.Cids(), height)
vmi, err := vm.NewVM(base, height, r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds) vmopt := &vm.VMOpts{
StateBase: base,
Epoch: height,
Rand: r,
Bstore: sm.cs.Blockstore(),
Syscalls: sm.cs.VMSys(),
VestedCalc: sm.GetVestedFunds,
BaseFee: ts.Blocks()[0].ParentBaseFee,
}
vmi, err := vm.NewVM(vmopt)
if err != nil { if err != nil {
return cid.Undef, nil, err return cid.Undef, nil, err
} }
@ -595,7 +604,16 @@ func (sm *StateManager) CirculatingSupply(ctx context.Context, ts *types.TipSet)
} }
r := store.NewChainRand(sm.cs, ts.Cids(), ts.Height()) r := store.NewChainRand(sm.cs, ts.Cids(), ts.Height())
vmi, err := vm.NewVM(st, ts.Height(), r, sm.cs.Blockstore(), sm.cs.VMSys(), sm.GetVestedFunds) vmopt := &vm.VMOpts{
StateBase: st,
Epoch: ts.Height(),
Rand: r,
Bstore: sm.cs.Blockstore(),
Syscalls: sm.cs.VMSys(),
VestedCalc: sm.GetVestedFunds,
BaseFee: ts.Blocks()[0].ParentBaseFee,
}
vmi, err := vm.NewVM(vmopt)
if err != nil { if err != nil {
return big.Zero(), err return big.Zero(), err
} }

45
chain/store/basefee.go Normal file
View File

@ -0,0 +1,45 @@
package store
import (
"context"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"golang.org/x/xerrors"
)
func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int) types.BigInt {
delta := gasLimitUsed/int64(noOfBlocks) - build.BlockGasTarget
change := big.Mul(baseFee, big.NewInt(delta))
change = big.Div(change, big.NewInt(build.BlockGasTarget))
change = big.Div(change, big.NewInt(build.BaseFeeMaxChangeDenom))
nextBaseFee := big.Add(baseFee, change)
if big.Cmp(nextBaseFee, big.NewInt(build.MinimumBaseFee)) < 0 {
nextBaseFee = big.NewInt(build.MinimumBaseFee)
}
return nextBaseFee
}
func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) {
zero := abi.NewTokenAmount(0)
totalLimit := int64(0)
for _, b := range ts.Blocks() {
msg1, msg2, err := cs.MessagesForBlock(b)
if err != nil {
return zero, xerrors.Errorf("error getting messages for: %s: %w", b.Cid(), err)
}
for _, m := range msg1 {
totalLimit += m.GasLimit
}
for _, m := range msg2 {
totalLimit += m.Message.GasLimit
}
}
parentBaseFee := ts.Blocks()[0].ParentBaseFee
return computeNextBaseFee(parentBaseFee, totalLimit, len(ts.Blocks())), nil
}

View File

@ -0,0 +1,34 @@
package store
import (
"fmt"
"testing"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types"
"github.com/stretchr/testify/assert"
)
func TestBaseFee(t *testing.T) {
tests := []struct {
basefee uint64
limitUsed int64
noOfBlocks int
output uint64
}{
{100e6, 0, 1, 87.5e6},
{100e6, 0, 5, 87.5e6},
{100e6, build.BlockGasTarget, 1, 100e6},
{100e6, build.BlockGasTarget * 2, 2, 100e6},
{100e6, build.BlockGasLimit * 2, 2, 112.5e6},
{100e6, build.BlockGasLimit * 1.5, 2, 106.25e6},
}
for _, test := range tests {
test := test
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
output := computeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks)
assert.Equal(t, fmt.Sprintf("%d", test.output), output.String())
})
}
}

View File

@ -22,7 +22,7 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn
} }
// >>> w[r] <<< + wFunction(totalPowerAtTipset(ts)) * 2^8 + (wFunction(totalPowerAtTipset(ts)) * sum(ts.blocks[].ElectionProof.WinCount) * wRatio_num * 2^8) / (e * wRatio_den) // >>> w[r] <<< + wFunction(totalPowerAtTipset(ts)) * 2^8 + (wFunction(totalPowerAtTipset(ts)) * sum(ts.blocks[].ElectionProof.WinCount) * wRatio_num * 2^8) / (e * wRatio_den)
var out = new(big.Int).Set(ts.Blocks()[0].ParentWeight.Int) var out = new(big.Int).Set(ts.ParentWeight().Int)
// >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * sum(ts.blocks[].ElectionProof.WinCount) * wRatio_num * 2^8) / (e * wRatio_den) // >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * sum(ts.blocks[].ElectionProof.WinCount) * wRatio_num * 2^8) / (e * wRatio_den)

View File

@ -199,8 +199,8 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
syncer.Bsync.AddPeer(from) syncer.Bsync.AddPeer(from)
bestPweight := syncer.store.GetHeaviestTipSet().Blocks()[0].ParentWeight bestPweight := syncer.store.GetHeaviestTipSet().ParentWeight()
targetWeight := fts.TipSet().Blocks()[0].ParentWeight targetWeight := fts.TipSet().ParentWeight()
if targetWeight.LessThan(bestPweight) { if targetWeight.LessThan(bestPweight) {
var miners []string var miners []string
for _, blk := range fts.TipSet().Blocks() { for _, blk := range fts.TipSet().Blocks() {
@ -671,8 +671,6 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
return xerrors.Errorf("failed to get latest beacon entry: %w", err) return xerrors.Errorf("failed to get latest beacon entry: %w", err)
} }
//nulls := h.Height - (baseTs.Height() + 1)
// fast checks first // fast checks first
nulls := h.Height - (baseTs.Height() + 1) nulls := h.Height - (baseTs.Height() + 1)
if tgtTs := baseTs.MinTimestamp() + build.BlockDelaySecs*uint64(nulls+1); h.Timestamp != tgtTs { if tgtTs := baseTs.MinTimestamp() + build.BlockDelaySecs*uint64(nulls+1); h.Timestamp != tgtTs {
@ -701,6 +699,27 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
return nil return nil
}) })
baseFeeCheck := async.Err(func() error {
baseFee, err := syncer.store.ComputeBaseFee(ctx, baseTs)
if err != nil {
return xerrors.Errorf("computing base fee: %w", err)
}
if types.BigCmp(baseFee, b.Header.ParentBaseFee) != 0 {
return xerrors.Errorf("base fee doesn't match: %s (header) != %s (computed)",
b.Header.ParentBaseFee, baseFee)
}
return nil
})
pweight, err := syncer.store.Weight(ctx, baseTs)
if err != nil {
return xerrors.Errorf("getting parent weight: %w", err)
}
if types.BigCmp(pweight, b.Header.ParentWeight) != 0 {
return xerrors.Errorf("parrent weight different: %s (header) != %s (computed)",
b.Header.ParentWeight, pweight)
}
// Stuff that needs stateroot / worker address // Stuff that needs stateroot / worker address
stateroot, precp, err := syncer.sm.TipSetState(ctx, baseTs) stateroot, precp, err := syncer.sm.TipSetState(ctx, baseTs)
if err != nil { if err != nil {
@ -843,6 +862,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er
wproofCheck, wproofCheck,
winnerCheck, winnerCheck,
msgsCheck, msgsCheck,
baseFeeCheck,
} }
var merr error var merr error
@ -994,7 +1014,6 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock
return xerrors.Errorf("failed to get actor: %w", err) return xerrors.Errorf("failed to get actor: %w", err)
} }
// redundant check
if !act.IsAccountActor() { if !act.IsAccountActor() {
return xerrors.New("Sender must be an account actor") return xerrors.New("Sender must be an account actor")
} }

View File

@ -65,6 +65,9 @@ type BlockHeader struct {
ForkSignaling uint64 // 14 ForkSignaling uint64 // 14
// ParentBaseFee is the base fee after executing parent tipset
ParentBaseFee abi.TokenAmount // 15
// internal // internal
validated bool // true if the signature has been validated validated bool // true if the signature has been validated
} }

View File

@ -44,6 +44,7 @@ func testBlockHeader(t testing.TB) *BlockHeader {
Height: 85919298723, Height: 85919298723,
ParentStateRoot: c, ParentStateRoot: c,
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")}, BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")},
ParentBaseFee: NewInt(3432432843291),
} }
} }
@ -107,7 +108,8 @@ func TestInteropBH(t *testing.T) {
Type: crypto.SigTypeBLS, Type: crypto.SigTypeBLS,
Data: []byte{0x3}, Data: []byte{0x3},
}, },
BLSAggregate: &crypto.Signature{}, BLSAggregate: &crypto.Signature{},
ParentBaseFee: NewInt(1000000000),
} }
bhsb, err := bh.SigningBytes() bhsb, err := bh.SigningBytes()
@ -116,7 +118,7 @@ func TestInteropBH(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
gfc := "8f5501d04cb15021bf6bd003073d79e2238d4e61f1ad2281430102038200420a0b818205410c818200410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f603" gfc := "905501d04cb15021bf6bd003073d79e2238d4e61f1ad2281430102038200420a0b818205410c818200410781d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc430003e802d82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619ccd82a5827000171a0e402202f84fef0d7cc2d7f9f00d22445f7bf7539fdd685fd9f284aa37f3822b57619cc410001f60345003b9aca00"
require.Equal(t, gfc, hex.EncodeToString(bhsb)) require.Equal(t, gfc, hex.EncodeToString(bhsb))
} }

View File

@ -9,14 +9,14 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/crypto"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors" xerrors "golang.org/x/xerrors"
) )
var _ = xerrors.Errorf var _ = xerrors.Errorf
var lengthBufBlockHeader = []byte{143} var lengthBufBlockHeader = []byte{144}
func (t *BlockHeader) MarshalCBOR(w io.Writer) error { func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
if t == nil { if t == nil {
@ -142,6 +142,10 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error {
return err return err
} }
// t.ParentBaseFee (big.Int) (struct)
if err := t.ParentBaseFee.MarshalCBOR(w); err != nil {
return err
}
return nil return nil
} }
@ -159,7 +163,7 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input should be of type array") return fmt.Errorf("cbor input should be of type array")
} }
if extra != 15 { if extra != 16 {
return fmt.Errorf("cbor input had wrong number of fields") return fmt.Errorf("cbor input had wrong number of fields")
} }
@ -439,6 +443,15 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error {
} }
t.ForkSignaling = uint64(extra) t.ForkSignaling = uint64(extra)
}
// t.ParentBaseFee (big.Int) (struct)
{
if err := t.ParentBaseFee.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.ParentBaseFee: %w", err)
}
} }
return nil return nil
} }
@ -619,7 +632,7 @@ func (t *ElectionProof) UnmarshalCBOR(r io.Reader) error {
return nil return nil
} }
var lengthBufMessage = []byte{137} var lengthBufMessage = []byte{138}
func (t *Message) MarshalCBOR(w io.Writer) error { func (t *Message) MarshalCBOR(w io.Writer) error {
if t == nil { if t == nil {
@ -664,11 +677,6 @@ func (t *Message) MarshalCBOR(w io.Writer) error {
return err return err
} }
// t.GasPrice (big.Int) (struct)
if err := t.GasPrice.MarshalCBOR(w); err != nil {
return err
}
// t.GasLimit (int64) (int64) // t.GasLimit (int64) (int64)
if t.GasLimit >= 0 { if t.GasLimit >= 0 {
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.GasLimit)); err != nil { if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.GasLimit)); err != nil {
@ -680,6 +688,16 @@ func (t *Message) MarshalCBOR(w io.Writer) error {
} }
} }
// t.GasFeeCap (big.Int) (struct)
if err := t.GasFeeCap.MarshalCBOR(w); err != nil {
return err
}
// t.GasPremium (big.Int) (struct)
if err := t.GasPremium.MarshalCBOR(w); err != nil {
return err
}
// t.Method (abi.MethodNum) (uint64) // t.Method (abi.MethodNum) (uint64)
if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Method)); err != nil { if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Method)); err != nil {
@ -715,7 +733,7 @@ func (t *Message) UnmarshalCBOR(r io.Reader) error {
return fmt.Errorf("cbor input should be of type array") return fmt.Errorf("cbor input should be of type array")
} }
if extra != 9 { if extra != 10 {
return fmt.Errorf("cbor input had wrong number of fields") return fmt.Errorf("cbor input had wrong number of fields")
} }
@ -784,15 +802,6 @@ func (t *Message) UnmarshalCBOR(r io.Reader) error {
return xerrors.Errorf("unmarshaling t.Value: %w", err) return xerrors.Errorf("unmarshaling t.Value: %w", err)
} }
}
// t.GasPrice (big.Int) (struct)
{
if err := t.GasPrice.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.GasPrice: %w", err)
}
} }
// t.GasLimit (int64) (int64) // t.GasLimit (int64) (int64)
{ {
@ -819,6 +828,24 @@ func (t *Message) UnmarshalCBOR(r io.Reader) error {
t.GasLimit = int64(extraI) t.GasLimit = int64(extraI)
} }
// t.GasFeeCap (big.Int) (struct)
{
if err := t.GasFeeCap.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.GasFeeCap: %w", err)
}
}
// t.GasPremium (big.Int) (struct)
{
if err := t.GasPremium.UnmarshalCBOR(br); err != nil {
return xerrors.Errorf("unmarshaling t.GasPremium: %w", err)
}
}
// t.Method (abi.MethodNum) (uint64) // t.Method (abi.MethodNum) (uint64)
{ {

View File

@ -32,10 +32,11 @@ type Message struct {
Nonce uint64 Nonce uint64
Value BigInt Value abi.TokenAmount
GasPrice BigInt GasLimit int64
GasLimit int64 GasFeeCap abi.TokenAmount
GasPremium abi.TokenAmount
Method abi.MethodNum Method abi.MethodNum
Params []byte Params []byte
@ -106,7 +107,7 @@ func (m *Message) Cid() cid.Cid {
} }
func (m *Message) RequiredFunds() BigInt { func (m *Message) RequiredFunds() BigInt {
return BigMul(m.GasPrice, NewInt(uint64(m.GasLimit))) return BigMul(m.GasFeeCap, NewInt(uint64(m.GasLimit)))
} }
func (m *Message) VMMessage() *Message { func (m *Message) VMMessage() *Message {
@ -138,8 +139,12 @@ func (m *Message) ValidForBlockInclusion(minGas int64) error {
return xerrors.New("'Value' field cannot be greater than total filecoin supply") return xerrors.New("'Value' field cannot be greater than total filecoin supply")
} }
if m.GasPrice.LessThan(big.Zero()) { if m.GasFeeCap.LessThan(big.Zero()) {
return xerrors.New("'GasPrice' field cannot be negative") return xerrors.New("'GasFeeCap' field cannot be negative")
}
if m.GasPremium.LessThan(big.Zero()) {
return xerrors.New("'GasPremium' field cannot be negative")
} }
if m.GasLimit > build.BlockGasLimit { if m.GasLimit > build.BlockGasLimit {

View File

@ -23,12 +23,13 @@ func Address(i uint64) address.Address {
func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.SignedMessage { func MkMessage(from, to address.Address, nonce uint64, w *wallet.Wallet) *types.SignedMessage {
msg := &types.Message{ msg := &types.Message{
To: to, To: to,
From: from, From: from,
Value: types.NewInt(1), Value: types.NewInt(1),
Nonce: nonce, Nonce: nonce,
GasLimit: 1000000, GasLimit: 1000000,
GasPrice: types.NewInt(0), GasFeeCap: types.NewInt(100),
GasPremium: types.NewInt(1),
} }
sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes()) sig, err := w.Sign(context.TODO(), from, msg.Cid().Bytes())

View File

@ -22,13 +22,14 @@ func blsaddr(n int64) address.Address {
func BenchmarkSerializeMessage(b *testing.B) { func BenchmarkSerializeMessage(b *testing.B) {
m := &Message{ m := &Message{
To: blsaddr(1), To: blsaddr(1),
From: blsaddr(2), From: blsaddr(2),
Nonce: 197, Nonce: 197,
Method: 1231254, Method: 1231254,
Params: []byte("some bytes, idk. probably at least ten of them"), Params: []byte("some bytes, idk. probably at least ten of them"),
GasLimit: 126723, GasLimit: 126723,
GasPrice: NewInt(1776234), GasPremium: NewInt(1245667),
GasFeeCap: NewInt(1245667),
} }
b.ReportAllocs() b.ReportAllocs()

View File

@ -13,14 +13,15 @@ func TestSignedMessageJsonRoundtrip(t *testing.T) {
from, _ := address.NewIDAddress(603911192) from, _ := address.NewIDAddress(603911192)
smsg := &types.SignedMessage{ smsg := &types.SignedMessage{
Message: types.Message{ Message: types.Message{
To: to, To: to,
From: from, From: from,
Params: []byte("some bytes, idk"), Params: []byte("some bytes, idk"),
Method: 1235126, Method: 1235126,
Value: types.NewInt(123123), Value: types.NewInt(123123),
GasPrice: types.NewInt(1234), GasFeeCap: types.NewInt(1234),
GasLimit: 100_000_000, GasPremium: types.NewInt(132414234),
Nonce: 123123, GasLimit: 100_000_000,
Nonce: 123123,
}, },
} }

View File

@ -2,6 +2,7 @@ package validation
import ( import (
"context" "context"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
@ -89,6 +90,7 @@ func (a *Applier) ApplyTipSetMessages(epoch abi.ChainEpoch, blocks []vtypes.Bloc
} }
var receipts []vtypes.MessageReceipt var receipts []vtypes.MessageReceipt
// TODO: base fee
sroot, _, err := sm.ApplyBlocks(context.TODO(), epoch-1, a.stateWrapper.Root(), bms, epoch, &randWrapper{rnd}, func(c cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { sroot, _, err := sm.ApplyBlocks(context.TODO(), epoch-1, a.stateWrapper.Root(), bms, epoch, &randWrapper{rnd}, func(c cid.Cid, msg *types.Message, ret *vm.ApplyRet) error {
if msg.From == builtin.SystemActorAddr { if msg.From == builtin.SystemActorAddr {
return nil // ignore reward and cron calls return nil // ignore reward and cron calls
@ -104,7 +106,7 @@ func (a *Applier) ApplyTipSetMessages(epoch abi.ChainEpoch, blocks []vtypes.Bloc
GasUsed: vtypes.GasUnits(ret.GasUsed), GasUsed: vtypes.GasUnits(ret.GasUsed),
}) })
return nil return nil
}) }, abi.NewTokenAmount(100))
if err != nil { if err != nil {
return vtypes.ApplyTipSetResult{}, err return vtypes.ApplyTipSetResult{}, err
} }
@ -136,7 +138,17 @@ func (a *Applier) applyMessage(epoch abi.ChainEpoch, lm types.ChainMsg) (vtypes.
ctx := context.TODO() ctx := context.TODO()
base := a.stateWrapper.Root() base := a.stateWrapper.Root()
lotusVM, err := vm.NewVM(base, epoch, &vmRand{}, a.stateWrapper.bs, a.syscalls, nil) vmopt := &vm.VMOpts{
StateBase: base,
Epoch: epoch,
Rand: &vmRand{},
Bstore: a.stateWrapper.bs,
Syscalls: a.syscalls,
VestedCalc: nil,
BaseFee: abi.NewTokenAmount(100),
}
lotusVM, err := vm.NewVM(vmopt)
// need to modify the VM invoker to add the puppet actor // need to modify the VM invoker to add the puppet actor
chainValInvoker := vm.NewInvoker() chainValInvoker := vm.NewInvoker()
chainValInvoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{}) chainValInvoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{})
@ -177,9 +189,10 @@ func toLotusMsg(msg *vtypes.Message) *types.Message {
Nonce: msg.CallSeqNum, Nonce: msg.CallSeqNum,
Method: msg.Method, Method: msg.Method,
Value: msg.Value, Value: msg.Value,
GasPrice: msg.GasPrice, GasLimit: msg.GasLimit,
GasLimit: msg.GasLimit, GasFeeCap: msg.GasFeeCap,
GasPremium: msg.GasPremium,
Params: msg.Params, Params: msg.Params,
} }

View File

@ -17,6 +17,7 @@ import (
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/power"
"github.com/filecoin-project/specs-actors/actors/builtin/verifreg"
"github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/crypto"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/bls"
@ -24,6 +25,7 @@ import (
) )
func init() { func init() {
verifreg.MinVerifiedDealSize = big.NewInt(2048)
power.ConsensusMinerMinPower = big.NewInt(2048) power.ConsensusMinerMinPower = big.NewInt(2048)
} }
@ -137,7 +139,8 @@ func MakeUnsignedMessageVectors() []vectors.UnsignedMessageVector {
if err != nil { if err != nil {
panic(err) panic(err)
} }
to, err := address.NewIDAddress(rand.Uint64()) uint63mask := uint64(1<<63 - 1)
to, err := address.NewIDAddress(rand.Uint64() & uint63mask)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -146,14 +149,15 @@ func MakeUnsignedMessageVectors() []vectors.UnsignedMessageVector {
rand.Read(params) rand.Read(params)
msg := &types.Message{ msg := &types.Message{
To: to, To: to,
From: from, From: from,
Value: types.NewInt(rand.Uint64()), Value: types.NewInt(rand.Uint64()),
Method: abi.MethodNum(rand.Uint64()), Method: abi.MethodNum(rand.Uint64()),
GasPrice: types.NewInt(rand.Uint64()), GasFeeCap: types.NewInt(rand.Uint64()),
GasLimit: rand.Int63(), GasPremium: types.NewInt(rand.Uint64()),
Nonce: rand.Uint64(), GasLimit: rand.Int63(),
Params: params, Nonce: rand.Uint64() & (1<<63 - 1),
Params: params,
} }
ser, err := msg.Serialize() ser, err := msg.Serialize()

View File

@ -1,7 +1,8 @@
package vm package vm
import ( import (
"math/big" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"
) )
const ( const (
@ -9,9 +10,21 @@ const (
gasOveruseDenom = 10 gasOveruseDenom = 10
) )
// ComputeGasOutputs computes amount of gas to be refunded and amount of gas to be burned type GasOutputs struct {
BaseFeeBurn abi.TokenAmount
OverEstimationBurn abi.TokenAmount
MinerPenalty abi.TokenAmount
MinerTip abi.TokenAmount
Refund abi.TokenAmount
GasRefund int64
GasBurned int64
}
// ComputeGasOverestimationBurn computes amount of gas to be refunded and amount of gas to be burned
// Result is (refund, burn) // Result is (refund, burn)
func ComputeGasOutputs(gasUsed, gasLimit int64) (int64, int64) { func ComputeGasOverestimationBurn(gasUsed, gasLimit int64) (int64, int64) {
if gasUsed == 0 { if gasUsed == 0 {
return 0, gasLimit return 0, gasLimit
} }
@ -37,8 +50,48 @@ func ComputeGasOutputs(gasUsed, gasLimit int64) (int64, int64) {
// needs bigint, as it overflows in pathological case gasLimit > 2^32 gasUsed = gasLimit / 2 // needs bigint, as it overflows in pathological case gasLimit > 2^32 gasUsed = gasLimit / 2
gasToBurn := big.NewInt(gasLimit - gasUsed) gasToBurn := big.NewInt(gasLimit - gasUsed)
gasToBurn = gasToBurn.Mul(gasToBurn, big.NewInt(over)) gasToBurn = big.Mul(gasToBurn, big.NewInt(over))
gasToBurn = gasToBurn.Div(gasToBurn, big.NewInt(gasUsed)) gasToBurn = big.Div(gasToBurn, big.NewInt(gasUsed))
return gasLimit - gasUsed - gasToBurn.Int64(), gasToBurn.Int64() return gasLimit - gasUsed - gasToBurn.Int64(), gasToBurn.Int64()
} }
func ComputeGasOutputs(gasUsed, gasLimit int64, baseFee, feeCap, gasPremium abi.TokenAmount) GasOutputs {
gasUsedBig := big.NewInt(gasUsed)
out := GasOutputs{
BaseFeeBurn: big.Zero(),
OverEstimationBurn: big.Zero(),
MinerPenalty: big.Zero(),
MinerTip: big.Zero(),
Refund: big.Zero(),
}
baseFeeToPay := baseFee
if baseFee.Cmp(feeCap.Int) > 0 {
baseFeeToPay = feeCap
out.MinerPenalty = big.Mul(big.Sub(baseFee, feeCap), gasUsedBig)
}
out.BaseFeeBurn = big.Mul(baseFeeToPay, gasUsedBig)
minerTip := gasPremium
if big.Cmp(big.Add(baseFeeToPay, minerTip), feeCap) > 0 {
minerTip = big.Sub(feeCap, baseFeeToPay)
}
out.MinerTip = big.Mul(minerTip, big.NewInt(gasLimit))
out.GasRefund, out.GasBurned = ComputeGasOverestimationBurn(gasUsed, gasLimit)
if out.GasBurned != 0 {
gasBurnedBig := big.NewInt(out.GasBurned)
out.OverEstimationBurn = big.Mul(baseFeeToPay, gasBurnedBig)
minerPenalty := big.Mul(big.Sub(baseFee, baseFeeToPay), gasBurnedBig)
out.MinerPenalty = big.Add(out.MinerPenalty, minerPenalty)
}
requiredFunds := big.Mul(big.NewInt(gasLimit), feeCap)
refund := big.Sub(requiredFunds, out.BaseFeeBurn)
refund = big.Sub(refund, out.MinerTip)
refund = big.Sub(refund, out.OverEstimationBurn)
out.Refund = refund
return out
}

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"testing" "testing"
"github.com/filecoin-project/lotus/chain/types"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -31,9 +32,47 @@ func TestGasBurn(t *testing.T) {
for _, test := range tests { for _, test := range tests {
test := test test := test
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) { t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
refund, toBurn := ComputeGasOutputs(test.used, test.limit) refund, toBurn := ComputeGasOverestimationBurn(test.used, test.limit)
assert.Equal(t, test.refund, refund, "refund") assert.Equal(t, test.refund, refund, "refund")
assert.Equal(t, test.burn, toBurn, "burned") assert.Equal(t, test.burn, toBurn, "burned")
}) })
} }
} }
func TestGasOutputs(t *testing.T) {
baseFee := types.NewInt(10)
tests := []struct {
used int64
limit int64
feeCap uint64
premium uint64
BaseFeeBurn uint64
OverEstimationBurn uint64
MinerPenalty uint64
MinerTip uint64
Refund uint64
}{
{100, 110, 11, 1, 1000, 0, 0, 110, 100},
{100, 130, 11, 1, 1000, 60, 0, 130, 240},
{100, 110, 10, 1, 1000, 0, 0, 0, 100},
{100, 110, 6, 1, 600, 0, 400, 0, 60},
}
for _, test := range tests {
test := test
t.Run(fmt.Sprintf("%v", test), func(t *testing.T) {
output := ComputeGasOutputs(test.used, test.limit, baseFee, types.NewInt(test.feeCap), types.NewInt(test.premium))
i2s := func(i uint64) string {
return fmt.Sprintf("%d", i)
}
assert.Equal(t, i2s(test.BaseFeeBurn), output.BaseFeeBurn.String(), "BaseFeeBurn")
assert.Equal(t, i2s(test.OverEstimationBurn), output.OverEstimationBurn.String(), "OverEstimationBurn")
assert.Equal(t, i2s(test.MinerPenalty), output.MinerPenalty.String(), "MinerPenalty")
assert.Equal(t, i2s(test.MinerTip), output.MinerTip.String(), "MinerTip")
assert.Equal(t, i2s(test.Refund), output.Refund.String(), "Refund")
})
}
}

View File

@ -7,6 +7,9 @@ import (
"reflect" "reflect"
"time" "time"
bstore "github.com/filecoin-project/lotus/lib/blockstore"
"github.com/filecoin-project/specs-actors/actors/abi/big"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
block "github.com/ipfs/go-block-format" block "github.com/ipfs/go-block-format"
@ -149,28 +152,40 @@ type VM struct {
inv *Invoker inv *Invoker
rand Rand rand Rand
vc VestedCalculator vc VestedCalculator
baseFee abi.TokenAmount
Syscalls SyscallBuilder Syscalls SyscallBuilder
} }
func NewVM(base cid.Cid, height abi.ChainEpoch, r Rand, cbs blockstore.Blockstore, syscalls SyscallBuilder, vestedCalc VestedCalculator) (*VM, error) { type VMOpts struct {
buf := bufbstore.NewBufferedBstore(cbs) StateBase cid.Cid
Epoch abi.ChainEpoch
Rand Rand
Bstore bstore.Blockstore
Syscalls SyscallBuilder
VestedCalc VestedCalculator
BaseFee abi.TokenAmount
}
func NewVM(opts *VMOpts) (*VM, error) {
buf := bufbstore.NewBufferedBstore(opts.Bstore)
cst := cbor.NewCborStore(buf) cst := cbor.NewCborStore(buf)
state, err := state.LoadStateTree(cst, base) state, err := state.LoadStateTree(cst, opts.StateBase)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &VM{ return &VM{
cstate: state, cstate: state,
base: base, base: opts.StateBase,
cst: cst, cst: cst,
buf: buf, buf: buf,
blockHeight: height, blockHeight: opts.Epoch,
inv: NewInvoker(), inv: NewInvoker(),
rand: r, // TODO: Probably should be a syscall rand: opts.Rand, // TODO: Probably should be a syscall
vc: vestedCalc, vc: opts.VestedCalc,
Syscalls: syscalls, Syscalls: opts.Syscalls,
baseFee: opts.BaseFee,
}, nil }, nil
} }
@ -182,6 +197,7 @@ type ApplyRet struct {
types.MessageReceipt types.MessageReceipt
ActorErr aerrors.ActorError ActorErr aerrors.ActorError
Penalty types.BigInt Penalty types.BigInt
MinerTip types.BigInt
ExecutionTrace types.ExecutionTrace ExecutionTrace types.ExecutionTrace
Duration time.Duration Duration time.Duration
} }
@ -277,8 +293,12 @@ func checkMessage(msg *types.Message) error {
return xerrors.Errorf("message has negative gas limit") return xerrors.Errorf("message has negative gas limit")
} }
if msg.GasPrice == types.EmptyInt { if msg.GasFeeCap == types.EmptyInt {
return xerrors.Errorf("message gas no gas price set") return xerrors.Errorf("message fee cap not set")
}
if msg.GasPremium == types.EmptyInt {
return xerrors.Errorf("message gas premium not set")
} }
if msg.Value == types.EmptyInt { if msg.Value == types.EmptyInt {
@ -301,6 +321,7 @@ func (vm *VM) ApplyImplicitMessage(ctx context.Context, msg *types.Message) (*Ap
ActorErr: actorErr, ActorErr: actorErr,
ExecutionTrace: rt.executionTrace, ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0), Penalty: types.NewInt(0),
MinerTip: types.NewInt(0),
Duration: time.Since(start), Duration: time.Since(start),
}, actorErr }, actorErr
} }
@ -333,14 +354,15 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
ExitCode: exitcode.SysErrOutOfGas, ExitCode: exitcode.SysErrOutOfGas,
GasUsed: 0, GasUsed: 0,
}, },
Penalty: types.BigMul(msg.GasPrice, types.NewInt(uint64(msgGasCost))), Penalty: types.BigMul(vm.baseFee, abi.NewTokenAmount(msgGasCost)),
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
st := vm.cstate st := vm.cstate
minerPenaltyAmount := types.BigMul(msg.GasPrice, types.NewInt(uint64(msgGasCost))) minerPenaltyAmount := types.BigMul(vm.baseFee, abi.NewTokenAmount(msg.GasLimit))
fromActor, err := st.GetActor(msg.From) fromActor, err := st.GetActor(msg.From)
// this should never happen, but is currently still exercised by some tests // this should never happen, but is currently still exercised by some tests
if err != nil { if err != nil {
@ -353,6 +375,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From), ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From),
Penalty: minerPenaltyAmount, Penalty: minerPenaltyAmount,
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
return nil, xerrors.Errorf("failed to look up from actor: %w", err) return nil, xerrors.Errorf("failed to look up from actor: %w", err)
@ -368,6 +391,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code), ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code),
Penalty: minerPenaltyAmount, Penalty: minerPenaltyAmount,
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
@ -381,10 +405,11 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
"actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce), "actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce),
Penalty: minerPenaltyAmount, Penalty: minerPenaltyAmount,
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasPrice) gascost := types.BigMul(types.NewInt(uint64(msg.GasLimit)), msg.GasFeeCap)
if fromActor.Balance.LessThan(gascost) { if fromActor.Balance.LessThan(gascost) {
return &ApplyRet{ return &ApplyRet{
MessageReceipt: types.MessageReceipt{ MessageReceipt: types.MessageReceipt{
@ -395,6 +420,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
"actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)), "actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(gascost)),
Penalty: minerPenaltyAmount, Penalty: minerPenaltyAmount,
Duration: time.Since(start), Duration: time.Since(start),
MinerTip: big.Zero(),
}, nil }, nil
} }
@ -454,25 +480,25 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
if gasUsed < 0 { if gasUsed < 0 {
gasUsed = 0 gasUsed = 0
} }
gasRefund, gasToBurn := ComputeGasOutputs(gasUsed, msg.GasLimit) gasOutputs := ComputeGasOutputs(gasUsed, msg.GasLimit, vm.baseFee, msg.GasFeeCap, msg.GasPremium)
if err := vm.transferFromGasHolder(builtin.BurntFundsActorAddr, gasHolder,
gasOutputs.BaseFeeBurn); err != nil {
return nil, xerrors.Errorf("failed to burn base fee: %w", err)
}
if err := vm.transferFromGasHolder(builtin.RewardActorAddr, gasHolder, gasOutputs.MinerTip); err != nil {
return nil, xerrors.Errorf("failed to give miner gas reward: %w", err)
}
if err := vm.transferFromGasHolder(builtin.BurntFundsActorAddr, gasHolder,
gasOutputs.OverEstimationBurn); err != nil {
return nil, xerrors.Errorf("failed to burn overestimation fee: %w", err)
}
// refund unused gas // refund unused gas
refund := types.BigMul(types.NewInt(uint64(gasRefund)), msg.GasPrice) if err := vm.transferFromGasHolder(msg.From, gasHolder, gasOutputs.Refund); err != nil {
if err := vm.transferFromGasHolder(msg.From, gasHolder, refund); err != nil { return nil, xerrors.Errorf("failed to refund gas: %w", err)
return nil, xerrors.Errorf("failed to refund gas")
}
if gasToBurn > 0 {
// burn overallocated gas
burn := types.BigMul(types.NewInt(uint64(gasToBurn)), msg.GasPrice)
if err := vm.transferFromGasHolder(builtin.BurntFundsActorAddr, gasHolder, burn); err != nil {
return nil, xerrors.Errorf("failed to burn over estimated gas")
}
}
gasReward := types.BigMul(msg.GasPrice, types.NewInt(uint64(gasUsed)))
if err := vm.transferFromGasHolder(builtin.RewardActorAddr, gasHolder, gasReward); err != nil {
return nil, xerrors.Errorf("failed to give miner gas reward: %w", err)
} }
if types.BigCmp(types.NewInt(0), gasHolder.Balance) != 0 { if types.BigCmp(types.NewInt(0), gasHolder.Balance) != 0 {
@ -487,7 +513,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet,
}, },
ActorErr: actorErr, ActorErr: actorErr,
ExecutionTrace: rt.executionTrace, ExecutionTrace: rt.executionTrace,
Penalty: types.NewInt(0), Penalty: gasOutputs.MinerPenalty,
MinerTip: gasOutputs.MinerTip,
Duration: time.Since(start), Duration: time.Since(start),
}, nil }, nil
} }
@ -766,6 +793,10 @@ func (vm *VM) transferFromGasHolder(addr address.Address, gasHolder *types.Actor
return xerrors.Errorf("attempted to transfer negative value from gas holder") return xerrors.Errorf("attempted to transfer negative value from gas holder")
} }
if amt.Equals(big.NewInt(0)) {
return nil
}
return vm.cstate.MutateActor(addr, func(a *types.Actor) error { return vm.cstate.MutateActor(addr, func(a *types.Actor) error {
if err := deductFunds(gasHolder, amt); err != nil { if err := deductFunds(gasHolder, amt); err != nil {
return err return err

View File

@ -430,22 +430,22 @@ var chainListCmd = &cli.Command{
psum := big.NewInt(0) psum := big.NewInt(0)
for _, m := range msgs.BlsMessages { for _, m := range msgs.BlsMessages {
limitSum += m.GasLimit limitSum += m.GasLimit
psum = big.Add(psum, m.GasPrice) psum = big.Add(psum, m.GasPremium)
} }
for _, m := range msgs.SecpkMessages { for _, m := range msgs.SecpkMessages {
limitSum += m.Message.GasLimit limitSum += m.Message.GasLimit
psum = big.Add(psum, m.Message.GasPrice) psum = big.Add(psum, m.Message.GasPremium)
} }
lenmsgs := len(msgs.BlsMessages) + len(msgs.SecpkMessages) lenmsgs := len(msgs.BlsMessages) + len(msgs.SecpkMessages)
avgprice := big.Zero() avgpremium := big.Zero()
if lenmsgs > 0 { if lenmsgs > 0 {
avgprice = big.Div(psum, big.NewInt(int64(lenmsgs))) avgpremium = big.Div(psum, big.NewInt(int64(lenmsgs)))
} }
fmt.Printf("\t%s: \t%d msgs, gasLimit: %d / %d (%0.2f%%), avgPrice: %s\n", b.Miner, len(msgs.BlsMessages)+len(msgs.SecpkMessages), limitSum, build.BlockGasLimit, 100*float64(limitSum)/float64(build.BlockGasLimit), avgprice) fmt.Printf("\t%s: \t%d msgs, gasLimit: %d / %d (%0.2f%%), avgPrice: %s\n", b.Miner, len(msgs.BlsMessages)+len(msgs.SecpkMessages), limitSum, build.BlockGasLimit, 100*float64(limitSum)/float64(build.BlockGasLimit), avgpremium)
} }
if i < len(tss)-1 { if i < len(tss)-1 {
msgs, err := api.ChainGetParentMessages(ctx, tss[i+1].Blocks()[0].Cid()) msgs, err := api.ChainGetParentMessages(ctx, tss[i+1].Blocks()[0].Cid())
@ -1030,9 +1030,9 @@ var chainGasPriceCmd = &cli.Command{
nb := []int{1, 2, 3, 5, 10, 20, 50, 100, 300} nb := []int{1, 2, 3, 5, 10, 20, 50, 100, 300}
for _, nblocks := range nb { for _, nblocks := range nb {
addr := builtin.SystemActorAddr // TODO: make real when used in GasEstimateGasPrice addr := builtin.SystemActorAddr // TODO: make real when used in GasEsitmateGasPremium
est, err := api.GasEstimateGasPrice(ctx, uint64(nblocks), addr, 10000, types.EmptyTSK) est, err := api.GasEsitmateGasPremium(ctx, uint64(nblocks), addr, 10000, types.EmptyTSK)
if err != nil { if err != nil {
return err return err
} }

View File

@ -246,8 +246,12 @@ var mpoolReplaceCmd = &cli.Command{
Name: "replace", Name: "replace",
Usage: "replace a message in the mempool", Usage: "replace a message in the mempool",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.Int64Flag{ &cli.StringFlag{
Name: "gas-price", Name: "gas-feecap",
Usage: "gas feecap for new message",
},
&cli.StringFlag{
Name: "gas-premium",
Usage: "gas price for new message", Usage: "gas price for new message",
}, },
&cli.Int64Flag{ &cli.Int64Flag{
@ -304,7 +308,15 @@ var mpoolReplaceCmd = &cli.Command{
msg := found.Message msg := found.Message
msg.GasLimit = cctx.Int64("gas-limit") msg.GasLimit = cctx.Int64("gas-limit")
msg.GasPrice = types.NewInt(uint64(cctx.Int64("gas-price"))) msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium"))
if err != nil {
return fmt.Errorf("parsing gas-premium: %w", err)
}
// TODO: estiamte fee cap here
msg.GasFeeCap, err = types.BigFromString(cctx.String("gas-feecap"))
if err != nil {
return fmt.Errorf("parsing gas-feecap: %w", err)
}
smsg, err := api.WalletSignMessage(ctx, msg.From, &msg) smsg, err := api.WalletSignMessage(ctx, msg.From, &msg)
if err != nil { if err != nil {

View File

@ -27,10 +27,15 @@ var sendCmd = &cli.Command{
Usage: "optionally specify the account to send funds from", Usage: "optionally specify the account to send funds from",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "gas-price", Name: "gas-premium",
Usage: "specify gas price to use in AttoFIL", Usage: "specify gas price to use in AttoFIL",
Value: "0", Value: "0",
}, },
&cli.StringFlag{
Name: "gas-feecap",
Usage: "specify gas fee cap to use in AttoFIL",
Value: "0",
},
&cli.Int64Flag{ &cli.Int64Flag{
Name: "gas-limit", Name: "gas-limit",
Usage: "specify gas limit", Usage: "specify gas limit",
@ -99,6 +104,10 @@ var sendCmd = &cli.Command{
if err != nil { if err != nil {
return err return err
} }
gfc, err := types.BigFromString(cctx.String("gas-feecap"))
if err != nil {
return err
}
method := abi.MethodNum(cctx.Uint64("method")) method := abi.MethodNum(cctx.Uint64("method"))
@ -122,13 +131,14 @@ var sendCmd = &cli.Command{
} }
msg := &types.Message{ msg := &types.Message{
From: fromAddr, From: fromAddr,
To: toAddr, To: toAddr,
Value: types.BigInt(val), Value: types.BigInt(val),
GasPrice: gp, GasPremium: gp,
GasLimit: cctx.Int64("gas-limit"), GasFeeCap: gfc,
Method: method, GasLimit: cctx.Int64("gas-limit"),
Params: params, Method: method,
Params: params,
} }
if cctx.Int64("nonce") > 0 { if cctx.Int64("nonce") > 0 {

View File

@ -5,7 +5,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/multiformats/go-multiaddr"
"html/template" "html/template"
"io" "io"
"os" "os"
@ -15,6 +14,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/multiformats/go-multiaddr"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
"github.com/multiformats/go-multihash" "github.com/multiformats/go-multihash"
@ -1383,13 +1384,11 @@ var stateCallCmd = &cli.Command{
} }
ret, err := api.StateCall(ctx, &types.Message{ ret, err := api.StateCall(ctx, &types.Message{
From: froma, From: froma,
To: toa, To: toa,
Value: types.BigInt(value), Value: types.BigInt(value),
GasLimit: 10000000000, Method: abi.MethodNum(method),
GasPrice: types.NewInt(0), Params: params,
Method: abi.MethodNum(method),
Params: params,
}, ts.Key()) }, ts.Key())
if err != nil { if err != nil {
return fmt.Errorf("state call failed: %s", err) return fmt.Errorf("state call failed: %s", err)

View File

@ -74,11 +74,9 @@ func sendSmallFundsTxs(ctx context.Context, api api.FullNode, from address.Addre
select { select {
case <-tick.C: case <-tick.C:
msg := &types.Message{ msg := &types.Message{
From: from, From: from,
To: sendSet[rand.Intn(20)], To: sendSet[rand.Intn(20)],
Value: types.NewInt(1), Value: types.NewInt(1),
GasLimit: 0,
GasPrice: types.NewInt(0),
} }
smsg, err := api.MpoolPushMessage(ctx, msg) smsg, err := api.MpoolPushMessage(ctx, msg)

View File

@ -30,8 +30,9 @@ create table if not exists messages
"to" text not null, "to" text not null,
nonce bigint not null, nonce bigint not null,
value text not null, value text not null,
gasprice bigint not null, gas_fee_cap bigint not null,
gaslimit bigint not null, gas_premium bigint not null,
gas_limit bigint not null,
method bigint, method bigint,
params bytea params bytea
); );
@ -219,7 +220,7 @@ create temp table msgs (like messages excluding constraints) on commit drop;
return xerrors.Errorf("prep temp: %w", err) return xerrors.Errorf("prep temp: %w", err)
} }
stmt, err := tx.Prepare(`copy msgs (cid, "from", "to", nonce, "value", gasprice, gaslimit, method, params) from stdin `) stmt, err := tx.Prepare(`copy msgs (cid, "from", "to", nonce, "value", gas_premium, gas_fee_cap, gas_limit, method, params) from stdin `)
if err != nil { if err != nil {
return err return err
} }
@ -231,7 +232,8 @@ create temp table msgs (like messages excluding constraints) on commit drop;
m.To.String(), m.To.String(),
m.Nonce, m.Nonce,
m.Value.String(), m.Value.String(),
m.GasPrice.String(), m.GasPremium.String(),
m.GasFeeCap.String(),
m.GasLimit, m.GasLimit,
m.Method, m.Method,
m.Params, m.Params,

View File

@ -279,9 +279,6 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) {
Value: types.BigInt(h.sendPerRequest), Value: types.BigInt(h.sendPerRequest),
From: h.from, From: h.from,
To: to, To: to,
GasPrice: types.NewInt(0),
GasLimit: 0,
}) })
if err != nil { if err != nil {
w.WriteHeader(400) w.WriteHeader(400)
@ -353,9 +350,6 @@ func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) {
Value: types.BigInt(h.sendPerRequest), Value: types.BigInt(h.sendPerRequest),
From: h.from, From: h.from,
To: owner, To: owner,
GasPrice: types.NewInt(0),
GasLimit: 0,
}) })
if err != nil { if err != nil {
w.WriteHeader(400) w.WriteHeader(400)
@ -390,9 +384,6 @@ func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) {
Method: builtin.MethodsPower.CreateMiner, Method: builtin.MethodsPower.CreateMiner,
Params: params, Params: params,
GasLimit: 0,
GasPrice: types.NewInt(0),
} }
signed, err := h.api.MpoolPushMessage(r.Context(), createStorageMinerMsg) signed, err := h.api.MpoolPushMessage(r.Context(), createStorageMinerMsg)

View File

@ -51,7 +51,7 @@ var minerSelectMsgsCmd = &cli.Command{
to = "..." + to[len(to)-8:] to = "..." + to[len(to)-8:]
} }
fmt.Printf("%d: %s -> %s, method %d, gasPrice %s, gasLimit %d, val %s\n", i, from, to, f.Message.Method, f.Message.GasPrice, f.Message.GasLimit, types.FIL(f.Message.Value)) fmt.Printf("%d: %s -> %s, method %d, gasFeecap %s, gasPremium %s, gasLimit %d, val %s\n", i, from, to, f.Message.Method, f.Message.GasFeeCap, f.Message.GasPremium, f.Message.GasLimit, types.FIL(f.Message.Value))
totalGas += f.Message.GasLimit totalGas += f.Message.GasLimit
} }

View File

@ -143,12 +143,10 @@ var verifRegVerifyClientCmd = &cli.Command{
ctx := lcli.ReqContext(cctx) ctx := lcli.ReqContext(cctx)
msg := &types.Message{ msg := &types.Message{
To: builtin.VerifiedRegistryActorAddr, To: builtin.VerifiedRegistryActorAddr,
From: fromk, From: fromk,
Method: builtin.MethodsVerifiedRegistry.AddVerifiedClient, Method: builtin.MethodsVerifiedRegistry.AddVerifiedClient,
GasPrice: types.NewInt(1), Params: params,
GasLimit: 0,
Params: params,
} }
smsg, err := api.MpoolPushMessage(ctx, msg) smsg, err := api.MpoolPushMessage(ctx, msg)

View File

@ -102,8 +102,8 @@ var initCmd = &cli.Command{
Usage: "don't use storageminer repo for sector storage", Usage: "don't use storageminer repo for sector storage",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "gas-price", Name: "gas-premium",
Usage: "set gas price for initialization messages in AttoFIL", Usage: "set gas premium for initialization messages in AttoFIL",
Value: "0", Value: "0",
}, },
}, },
@ -116,7 +116,7 @@ var initCmd = &cli.Command{
} }
ssize := abi.SectorSize(sectorSizeInt) ssize := abi.SectorSize(sectorSizeInt)
gasPrice, err := types.BigFromString(cctx.String("gas-price")) gasPrice, err := types.BigFromString(cctx.String("gas-premium"))
if err != nil { if err != nil {
return xerrors.Errorf("failed to parse gas-price flag: %s", err) return xerrors.Errorf("failed to parse gas-price flag: %s", err)
} }
@ -552,13 +552,12 @@ func configureStorageMiner(ctx context.Context, api lapi.FullNode, addr address.
} }
msg := &types.Message{ msg := &types.Message{
To: addr, To: addr,
From: mi.Worker, From: mi.Worker,
Method: builtin.MethodsMiner.ChangePeerID, Method: builtin.MethodsMiner.ChangePeerID,
Params: enc, Params: enc,
Value: types.NewInt(0), Value: types.NewInt(0),
GasPrice: gasPrice, GasPremium: gasPrice,
GasLimit: 0,
} }
smsg, err := api.MpoolPushMessage(ctx, msg) smsg, err := api.MpoolPushMessage(ctx, msg)
@ -637,8 +636,8 @@ func createStorageMiner(ctx context.Context, api lapi.FullNode, peerid peer.ID,
Method: builtin.MethodsPower.CreateMiner, Method: builtin.MethodsPower.CreateMiner,
Params: params, Params: params,
GasLimit: 0, GasLimit: 0,
GasPrice: gasPrice, GasPremium: gasPrice,
} }
signed, err := api.MpoolPushMessage(ctx, createStorageMinerMsg) signed, err := api.MpoolPushMessage(ctx, createStorageMinerMsg)

@ -1 +1 @@
Subproject commit 0cef69d481950d24f0e26e2698e585a8bf203913 Subproject commit 5bfb928910b01ac8b940a693af2884f7f8276211

2
go.mod
View File

@ -18,7 +18,7 @@ require (
github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4 github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4
github.com/drand/kyber v1.1.1 github.com/drand/kyber v1.1.1
github.com/fatih/color v1.8.0 github.com/fatih/color v1.8.0
github.com/filecoin-project/chain-validation v0.0.6-0.20200805210314-9844c5869f53 github.com/filecoin-project/chain-validation v0.0.6-0.20200807023228-a084d8d9919e
github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d
github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef
github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 // indirect github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 // indirect

5
go.sum
View File

@ -215,8 +215,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY= github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY=
github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E=
github.com/filecoin-project/chain-validation v0.0.6-0.20200805210314-9844c5869f53 h1:XRrMct6lOMjVe11dOnurq6vsLayQQyotFJi0YW4Wp8E= github.com/filecoin-project/chain-validation v0.0.6-0.20200807023228-a084d8d9919e h1:qHdxD1Of7i6yyFezaKNWk36CBNWGRHszp44oTq4oDQ0=
github.com/filecoin-project/chain-validation v0.0.6-0.20200805210314-9844c5869f53/go.mod h1:JICNIbIEZ+qNJ/PQlHxjei6SaeBbW+yV2r4BcShsXfI= github.com/filecoin-project/chain-validation v0.0.6-0.20200807023228-a084d8d9919e/go.mod h1:jtOqSVob11urlSIM8Gw3XIrqmiqb+fBr7ZBIbOhzGPI=
github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=
github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=
github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef h1:Wi5E+P1QfHP8IF27eUiTx5vYfqQZwfPxzq3oFEq8w8U= github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef h1:Wi5E+P1QfHP8IF27eUiTx5vYfqQZwfPxzq3oFEq8w8U=
@ -270,7 +270,6 @@ github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVl
github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY=
github.com/filecoin-project/specs-actors v0.7.3-0.20200716231407-60a2ae96d2e6/go.mod h1:JOMUa7EijvpOO4ofD1yeHNmqohkmmnhTvz/IpB6so4c= github.com/filecoin-project/specs-actors v0.7.3-0.20200716231407-60a2ae96d2e6/go.mod h1:JOMUa7EijvpOO4ofD1yeHNmqohkmmnhTvz/IpB6so4c=
github.com/filecoin-project/specs-actors v0.8.2/go.mod h1:Q3ACV5kBLvqPaYbthc/J1lGMJ5OwogmD9pzdtPRMdCw= github.com/filecoin-project/specs-actors v0.8.2/go.mod h1:Q3ACV5kBLvqPaYbthc/J1lGMJ5OwogmD9pzdtPRMdCw=
github.com/filecoin-project/specs-actors v0.8.5/go.mod h1:Q3ACV5kBLvqPaYbthc/J1lGMJ5OwogmD9pzdtPRMdCw=
github.com/filecoin-project/specs-actors v0.8.7-0.20200805174427-9d42fb163883 h1:/LOix6EwCWshEuufhM8gAuCqP5jPWVMqPZn8HUQCw3Y= github.com/filecoin-project/specs-actors v0.8.7-0.20200805174427-9d42fb163883 h1:/LOix6EwCWshEuufhM8gAuCqP5jPWVMqPZn8HUQCw3Y=
github.com/filecoin-project/specs-actors v0.8.7-0.20200805174427-9d42fb163883/go.mod h1:QRihI/fadrhWzt7HH6mT32upOdDFpSYCFnr3JEI1L50= github.com/filecoin-project/specs-actors v0.8.7-0.20200805174427-9d42fb163883/go.mod h1:QRihI/fadrhWzt7HH6mT32upOdDFpSYCFnr3JEI1L50=
github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea h1:iixjULRQFPn7Q9KlIqfwLJnlAXO10bbkI+xy5GKGdLY= github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea h1:iixjULRQFPn7Q9KlIqfwLJnlAXO10bbkI+xy5GKGdLY=

View File

@ -123,12 +123,10 @@ func (c *ClientNodeAdapter) ListClientDeals(ctx context.Context, addr address.Ad
func (c *ClientNodeAdapter) AddFunds(ctx context.Context, addr address.Address, amount abi.TokenAmount) (cid.Cid, error) { func (c *ClientNodeAdapter) AddFunds(ctx context.Context, addr address.Address, amount abi.TokenAmount) (cid.Cid, error) {
// (Provider Node API) // (Provider Node API)
smsg, err := c.MpoolPushMessage(ctx, &types.Message{ smsg, err := c.MpoolPushMessage(ctx, &types.Message{
To: builtin.StorageMarketActorAddr, To: builtin.StorageMarketActorAddr,
From: addr, From: addr,
Value: amount, Value: amount,
GasPrice: types.NewInt(0), Method: builtin.MethodsMarket.AddBalance,
GasLimit: 0,
Method: builtin.MethodsMarket.AddBalance,
}) })
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, err

View File

@ -74,13 +74,11 @@ func (n *ProviderNodeAdapter) PublishDeals(ctx context.Context, deal storagemark
// TODO: We may want this to happen after fetching data // TODO: We may want this to happen after fetching data
smsg, err := n.MpoolPushMessage(ctx, &types.Message{ smsg, err := n.MpoolPushMessage(ctx, &types.Message{
To: builtin.StorageMarketActorAddr, To: builtin.StorageMarketActorAddr,
From: mi.Worker, From: mi.Worker,
Value: types.NewInt(0), Value: types.NewInt(0),
GasPrice: types.NewInt(0), Method: builtin.MethodsMarket.PublishStorageDeals,
GasLimit: 0, Params: params,
Method: builtin.MethodsMarket.PublishStorageDeals,
Params: params,
}) })
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, err
@ -175,12 +173,10 @@ func (n *ProviderNodeAdapter) EnsureFunds(ctx context.Context, addr, wallet addr
func (n *ProviderNodeAdapter) AddFunds(ctx context.Context, addr address.Address, amount abi.TokenAmount) (cid.Cid, error) { func (n *ProviderNodeAdapter) AddFunds(ctx context.Context, addr address.Address, amount abi.TokenAmount) (cid.Cid, error) {
// (Provider Node API) // (Provider Node API)
smsg, err := n.MpoolPushMessage(ctx, &types.Message{ smsg, err := n.MpoolPushMessage(ctx, &types.Message{
To: builtin.StorageMarketActorAddr, To: builtin.StorageMarketActorAddr,
From: addr, From: addr,
Value: amount, Value: amount,
GasPrice: types.NewInt(0), Method: builtin.MethodsMarket.AddBalance,
GasLimit: 0,
Method: builtin.MethodsMarket.AddBalance,
}) })
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, err

View File

@ -7,7 +7,7 @@ import (
"io" "io"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
"github.com/ipfs/go-cid" cid "github.com/ipfs/go-cid"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
xerrors "golang.org/x/xerrors" xerrors "golang.org/x/xerrors"
) )

View File

@ -1,13 +1,9 @@
package impl package impl
import ( import (
"context"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/impl/client" "github.com/filecoin-project/lotus/node/impl/client"
"github.com/filecoin-project/lotus/node/impl/common" "github.com/filecoin-project/lotus/node/impl/common"
"github.com/filecoin-project/lotus/node/impl/full" "github.com/filecoin-project/lotus/node/impl/full"
@ -32,10 +28,4 @@ type FullNodeAPI struct {
full.BeaconAPI full.BeaconAPI
} }
// MpoolEstimateGasPrice estimates gas price
// Deprecated: used GasEstimateGasPrice instead
func (fa *FullNodeAPI) MpoolEstimateGasPrice(ctx context.Context, nblocksincl uint64, sender address.Address, limit int64, tsk types.TipSetKey) (types.BigInt, error) {
return fa.GasEstimateGasPrice(ctx, nblocksincl, sender, limit, tsk)
}
var _ api.FullNode = &FullNodeAPI{} var _ api.FullNode = &FullNodeAPI{}

View File

@ -2,6 +2,7 @@ package full
import ( import (
"context" "context"
"math"
"sort" "sort"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
@ -26,9 +27,22 @@ type GasAPI struct {
} }
const MinGasPrice = 1 const MinGasPrice = 1
const BaseFeeEstimNBlocks = 20
func (a *GasAPI) GasEstimateGasPrice(ctx context.Context, nblocksincl uint64, func (a *GasAPI) GasEstimateFeeCap(ctx context.Context, maxqueueblks int64,
sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) { tsk types.TipSetKey) (types.BigInt, error) {
ts := a.Chain.GetHeaviestTipSet()
parentBaseFee := ts.Blocks()[0].ParentBaseFee
increaseFactor := math.Pow(1+float64(1/build.BaseFeeMaxChangeDenom), BaseFeeEstimNBlocks)
out := types.BigMul(parentBaseFee, types.NewInt(uint64(increaseFactor*(1<<8))))
out = types.BigDiv(out, types.NewInt(1<<8))
return out, nil
}
func (a *GasAPI) GasEsitmateGasPremium(ctx context.Context, nblocksincl uint64,
sender address.Address, gaslimit int64, _ types.TipSetKey) (types.BigInt, error) {
if nblocksincl == 0 { if nblocksincl == 0 {
nblocksincl = 1 nblocksincl = 1
@ -68,7 +82,7 @@ func (a *GasAPI) GasEstimateGasPrice(ctx context.Context, nblocksincl uint64,
} }
prices = append(prices, gasMeta{ prices = append(prices, gasMeta{
price: msg.VMMessage().GasPrice, price: msg.VMMessage().GasPremium,
used: r.GasUsed, used: r.GasUsed,
}) })
gasUsed += r.GasUsed gasUsed += r.GasUsed
@ -111,7 +125,8 @@ func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message,
msg := *msgIn msg := *msgIn
msg.GasLimit = build.BlockGasLimit msg.GasLimit = build.BlockGasLimit
msg.GasPrice = types.NewInt(1) msg.GasFeeCap = types.NewInt(build.MinimumBaseFee + 1)
msg.GasPremium = types.NewInt(1)
currTs := a.Chain.GetHeaviestTipSet() currTs := a.Chain.GetHeaviestTipSet()
fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msgIn.From, currTs) fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msgIn.From, currTs)

View File

@ -111,12 +111,20 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message) (*t
msg.GasLimit = int64(float64(gasLimit) * GasMargin) msg.GasLimit = int64(float64(gasLimit) * GasMargin)
} }
if msg.GasPrice == types.EmptyInt || types.BigCmp(msg.GasPrice, types.NewInt(0)) == 0 { if msg.GasPremium == types.EmptyInt || types.BigCmp(msg.GasPremium, types.NewInt(0)) == 0 {
gasPrice, err := a.GasEstimateGasPrice(ctx, 2, msg.From, msg.GasLimit, types.TipSetKey{}) gasPremium, err := a.GasEsitmateGasPremium(ctx, 2, msg.From, msg.GasLimit, types.TipSetKey{})
if err != nil { if err != nil {
return nil, xerrors.Errorf("estimating gas price: %w", err) return nil, xerrors.Errorf("estimating gas price: %w", err)
} }
msg.GasPrice = gasPrice msg.GasPremium = gasPremium
}
if msg.GasFeeCap == types.EmptyInt || types.BigCmp(msg.GasFeeCap, types.NewInt(0)) == 0 {
feeCap, err := a.GasEstimateFeeCap(ctx, 20, types.EmptyTSK)
if err != nil {
return nil, xerrors.Errorf("estimating fee cap: %w", err)
}
msg.GasFeeCap = feeCap
} }
return a.Mpool.PushWithNonce(ctx, msg.From, func(from address.Address, nonce uint64) (*types.SignedMessage, error) { return a.Mpool.PushWithNonce(ctx, msg.From, func(from address.Address, nonce uint64) (*types.SignedMessage, error) {

View File

@ -45,10 +45,6 @@ func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Ad
return cid.Undef, xerrors.Errorf("must provide source address") return cid.Undef, xerrors.Errorf("must provide source address")
} }
if gp == types.EmptyInt {
gp = types.NewInt(0)
}
// Set up constructor parameters for multisig // Set up constructor parameters for multisig
msigParams := &samsig.ConstructorParams{ msigParams := &samsig.ConstructorParams{
Signers: addrs, Signers: addrs,
@ -74,12 +70,11 @@ func (a *MsigAPI) MsigCreate(ctx context.Context, req uint64, addrs []address.Ad
// now we create the message to send this with // now we create the message to send this with
msg := types.Message{ msg := types.Message{
To: builtin.InitActorAddr, To: builtin.InitActorAddr,
From: src, From: src,
Method: builtin.MethodsInit.Exec, Method: builtin.MethodsInit.Exec,
Params: enc, Params: enc,
Value: val, Value: val,
GasPrice: gp,
} }
// send the message out to the network // send the message out to the network

View File

@ -968,12 +968,10 @@ func (a *StateAPI) StateMinerPreCommitDepositForPower(ctx context.Context, maddr
} }
ret, err := a.StateManager.Call(ctx, &types.Message{ ret, err := a.StateManager.Call(ctx, &types.Message{
From: maddr, From: maddr,
To: builtin.StorageMarketActorAddr, To: builtin.StorageMarketActorAddr,
Method: builtin.MethodsMarket.VerifyDealsForActivation, Method: builtin.MethodsMarket.VerifyDealsForActivation,
GasLimit: 0, Params: params,
GasPrice: types.NewInt(0),
Params: params,
}, ts) }, ts)
if err != nil { if err != nil {
return types.EmptyInt, err return types.EmptyInt, err
@ -1048,12 +1046,10 @@ func (a *StateAPI) StateMinerInitialPledgeCollateral(ctx context.Context, maddr
} }
ret, err := a.StateManager.Call(ctx, &types.Message{ ret, err := a.StateManager.Call(ctx, &types.Message{
From: maddr, From: maddr,
To: builtin.StorageMarketActorAddr, To: builtin.StorageMarketActorAddr,
Method: builtin.MethodsMarket.VerifyDealsForActivation, Method: builtin.MethodsMarket.VerifyDealsForActivation,
GasLimit: 0, Params: params,
GasPrice: types.NewInt(0),
Params: params,
}, ts) }, ts)
if err != nil { if err != nil {
return types.EmptyInt, err return types.EmptyInt, err

View File

@ -103,13 +103,11 @@ func testStorageNode(ctx context.Context, t *testing.T, waddr address.Address, a
require.NoError(t, err) require.NoError(t, err)
msg := &types.Message{ msg := &types.Message{
To: act, To: act,
From: waddr, From: waddr,
Method: builtin.MethodsMiner.ChangePeerID, Method: builtin.MethodsMiner.ChangePeerID,
Params: enc, Params: enc,
Value: types.NewInt(0), Value: types.NewInt(0),
GasPrice: types.NewInt(0),
GasLimit: 0,
} }
_, err = tnd.MpoolPushMessage(ctx, msg) _, err = tnd.MpoolPushMessage(ctx, msg)

View File

@ -241,13 +241,11 @@ func (ca *channelAccessor) createPaych(ctx context.Context, from, to address.Add
} }
msg := &types.Message{ msg := &types.Message{
To: builtin.InitActorAddr, To: builtin.InitActorAddr,
From: from, From: from,
Value: amt, Value: amt,
Method: builtin.MethodsInit.Exec, Method: builtin.MethodsInit.Exec,
Params: enc, Params: enc,
GasLimit: 0,
GasPrice: types.NewInt(0),
} }
smsg, err := ca.api.MpoolPushMessage(ctx, msg) smsg, err := ca.api.MpoolPushMessage(ctx, msg)
@ -323,12 +321,10 @@ func (ca *channelAccessor) waitPaychCreateMsg(channelID string, mcid cid.Cid) er
// addFunds sends a message to add funds to the channel and returns the message cid // addFunds sends a message to add funds to the channel and returns the message cid
func (ca *channelAccessor) addFunds(ctx context.Context, channelInfo *ChannelInfo, amt types.BigInt, cb onCompleteFn) (*cid.Cid, error) { func (ca *channelAccessor) addFunds(ctx context.Context, channelInfo *ChannelInfo, amt types.BigInt, cb onCompleteFn) (*cid.Cid, error) {
msg := &types.Message{ msg := &types.Message{
To: *channelInfo.Channel, To: *channelInfo.Channel,
From: channelInfo.Control, From: channelInfo.Control,
Value: amt, Value: amt,
Method: 0, Method: 0,
GasLimit: 0,
GasPrice: types.NewInt(0),
} }
smsg, err := ca.api.MpoolPushMessage(ctx, msg) smsg, err := ca.api.MpoolPushMessage(ctx, msg)

View File

@ -237,15 +237,16 @@ func (s SealingAPIAdapter) StateMarketStorageDeal(ctx context.Context, dealID ab
return deal.Proposal, nil return deal.Proposal, nil
} }
//TODO: rename/remove gasPrice and gasLimit
func (s SealingAPIAdapter) SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, gasPrice big.Int, gasLimit int64, params []byte) (cid.Cid, error) { func (s SealingAPIAdapter) SendMsg(ctx context.Context, from, to address.Address, method abi.MethodNum, value, gasPrice big.Int, gasLimit int64, params []byte) (cid.Cid, error) {
msg := types.Message{ msg := types.Message{
To: to, To: to,
From: from, From: from,
Value: value, Value: value,
GasPrice: gasPrice, GasPremium: gasPrice,
GasLimit: gasLimit, GasLimit: gasLimit,
Method: method, Method: method,
Params: params, Params: params,
} }
smsg, err := s.delegate.MpoolPushMessage(ctx, &msg) smsg, err := s.delegate.MpoolPushMessage(ctx, &msg)

View File

@ -281,7 +281,10 @@ func RecordTipsetMessagesPoints(ctx context.Context, api api.FullNode, pl *Point
msgn := make(map[msgTag][]cid.Cid) msgn := make(map[msgTag][]cid.Cid)
for i, msg := range msgs { for i, msg := range msgs {
p := NewPoint("chain.message_gasprice", msg.Message.GasPrice.Int64()) // FIXME: use float so this doesn't overflow
p := NewPoint("chain.message_gaspremium", msg.Message.GasPremium.Int64())
pl.AddPoint(p)
p = NewPoint("chain.message_gasfeecap", msg.Message.GasFeeCap.Int64())
pl.AddPoint(p) pl.AddPoint(p)
bs, err := msg.Message.Serialize() bs, err := msg.Message.Serialize()