feat:state:Ignore market balance after nv23 (#11976)
* Ignore market balance after nv23 * Review Response and failing test * Fixes * Test passing * Bump up threshold --------- Co-authored-by: zenground0 <ZenGround0@users.noreply.github.com>
This commit is contained in:
parent
f5dd7665f6
commit
84b08fc25f
@ -966,6 +966,12 @@ workflows:
|
||||
- build
|
||||
suite: itest-splitstore
|
||||
target: "./itests/splitstore_test.go"
|
||||
- test:
|
||||
name: test-itest-supply
|
||||
requires:
|
||||
- build
|
||||
suite: itest-supply
|
||||
target: "./itests/supply_test.go"
|
||||
- test:
|
||||
name: test-itest-verifreg
|
||||
requires:
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
msig0 "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
@ -303,7 +304,10 @@ func getFilPowerLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmoun
|
||||
return pst.TotalLocked()
|
||||
}
|
||||
|
||||
func GetFilLocked(ctx context.Context, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
func GetFilLocked(ctx context.Context, st *state.StateTree, nv network.Version) (abi.TokenAmount, error) {
|
||||
if nv >= network.Version23 {
|
||||
return getFilPowerLocked(ctx, st)
|
||||
}
|
||||
|
||||
filMarketLocked, err := getFilMarketLocked(ctx, st)
|
||||
if err != nil {
|
||||
@ -337,6 +341,7 @@ func (sm *StateManager) GetVMCirculatingSupply(ctx context.Context, height abi.C
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (api.CirculatingSupply, error) {
|
||||
nv := sm.GetNetworkVersion(ctx, height)
|
||||
filVested, err := sm.GetFilVested(ctx, height)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filVested: %w", err)
|
||||
@ -360,7 +365,7 @@ func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, heig
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filBurnt: %w", err)
|
||||
}
|
||||
|
||||
filLocked, err := GetFilLocked(ctx, st)
|
||||
filLocked, err := GetFilLocked(ctx, st, nv)
|
||||
if err != nil {
|
||||
return api.CirculatingSupply{}, xerrors.Errorf("failed to calculate filLocked: %w", err)
|
||||
}
|
||||
@ -387,6 +392,8 @@ func (sm *StateManager) GetVMCirculatingSupplyDetailed(ctx context.Context, heig
|
||||
func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.ChainEpoch, st *state.StateTree) (abi.TokenAmount, error) {
|
||||
circ := big.Zero()
|
||||
unCirc := big.Zero()
|
||||
nv := sm.GetNetworkVersion(ctx, height)
|
||||
|
||||
err := st.ForEach(func(a address.Address, actor *types.Actor) error {
|
||||
// this can be a lengthy operation, we need to cancel early when
|
||||
// the context is cancelled to avoid resource exhaustion
|
||||
@ -415,18 +422,22 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
|
||||
unCirc = big.Add(unCirc, actor.Balance)
|
||||
|
||||
case a == market.Address:
|
||||
mst, err := market.Load(sm.cs.ActorStore(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if nv >= network.Version23 {
|
||||
circ = big.Add(circ, actor.Balance)
|
||||
} else {
|
||||
mst, err := market.Load(sm.cs.ActorStore(ctx), actor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lb, err := mst.TotalLocked()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lb, err := mst.TotalLocked()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
circ = big.Add(circ, big.Sub(actor.Balance, lb))
|
||||
unCirc = big.Add(unCirc, lb)
|
||||
circ = big.Add(circ, big.Sub(actor.Balance, lb))
|
||||
unCirc = big.Add(unCirc, lb)
|
||||
}
|
||||
|
||||
case builtin.IsAccountActor(actor.Code) ||
|
||||
builtin.IsPaymentChannelActor(actor.Code) ||
|
||||
|
205
itests/supply_test.go
Normal file
205
itests/supply_test.go
Normal file
@ -0,0 +1,205 @@
|
||||
package itests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/builtin/v9/market"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/itests/kit"
|
||||
)
|
||||
|
||||
func TestCirciulationSupplyUpgrade(t *testing.T) {
|
||||
kit.QuietMiningLogs()
|
||||
ctx := context.Background()
|
||||
|
||||
// Choosing something divisible by epochs per day to remove error with simple deal duration
|
||||
lockedClientBalance := big.Mul(abi.NewTokenAmount(11_520_000), abi.NewTokenAmount(1e18))
|
||||
lockedProviderBalance := big.Mul(abi.NewTokenAmount(1_000_000), abi.NewTokenAmount(1e18))
|
||||
var height0 abi.ChainEpoch
|
||||
var height1 abi.ChainEpoch
|
||||
// Lock collateral in market on nv22 network
|
||||
fullNode0, blockMiner0, ens0 := kit.EnsembleMinimal(t,
|
||||
kit.GenesisNetworkVersion(network.Version22),
|
||||
kit.MockProofs(),
|
||||
)
|
||||
{
|
||||
|
||||
worker0 := blockMiner0.OwnerKey.Address
|
||||
ens0.InterconnectAll().BeginMining(50 * time.Millisecond)
|
||||
|
||||
// Lock collateral in market actor
|
||||
wallet0, err := fullNode0.WalletDefaultAddress(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add 1 FIL to cover provider collateral
|
||||
c00, err := fullNode0.MarketAddBalance(ctx, wallet0, wallet0, lockedClientBalance)
|
||||
require.NoError(t, err)
|
||||
fullNode0.WaitMsg(ctx, c00)
|
||||
c01, err := blockMiner0.FullNode.MarketAddBalance(ctx, worker0, blockMiner0.ActorAddr, lockedProviderBalance)
|
||||
require.NoError(t, err)
|
||||
fullNode0.WaitMsg(ctx, c01)
|
||||
|
||||
psd0, err := fullNode0.MpoolPushMessage(ctx,
|
||||
makePSDMessage(
|
||||
ctx,
|
||||
t,
|
||||
blockMiner0.ActorAddr,
|
||||
worker0,
|
||||
wallet0,
|
||||
lockedProviderBalance,
|
||||
lockedClientBalance,
|
||||
fullNode0.WalletSign,
|
||||
),
|
||||
nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
fullNode0.WaitMsg(ctx, psd0.Cid())
|
||||
head, err := fullNode0.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
height0 = head.Height()
|
||||
}
|
||||
|
||||
// Lock collateral in market on nv23 network
|
||||
fullNode1, blockMiner1, ens1 := kit.EnsembleMinimal(t,
|
||||
kit.GenesisNetworkVersion(network.Version23),
|
||||
kit.MockProofs(),
|
||||
)
|
||||
{
|
||||
worker1 := blockMiner1.OwnerKey.Address
|
||||
ens1.InterconnectAll().BeginMining(50 * time.Millisecond)
|
||||
|
||||
// Lock collateral in market actor
|
||||
wallet1, err := fullNode1.WalletDefaultAddress(ctx)
|
||||
require.NoError(t, err)
|
||||
c10, err := fullNode1.MarketAddBalance(ctx, wallet1, wallet1, lockedClientBalance)
|
||||
require.NoError(t, err)
|
||||
fullNode1.WaitMsg(ctx, c10)
|
||||
c11, err := blockMiner1.FullNode.MarketAddBalance(ctx, worker1, blockMiner1.ActorAddr, lockedProviderBalance)
|
||||
require.NoError(t, err)
|
||||
fullNode1.WaitMsg(ctx, c11)
|
||||
|
||||
psd1, err := fullNode1.MpoolPushMessage(ctx,
|
||||
makePSDMessage(
|
||||
ctx,
|
||||
t,
|
||||
blockMiner1.ActorAddr,
|
||||
worker1,
|
||||
wallet1,
|
||||
lockedProviderBalance,
|
||||
lockedClientBalance,
|
||||
fullNode1.WalletSign,
|
||||
),
|
||||
nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
fullNode1.WaitMsg(ctx, psd1.Cid())
|
||||
head, err := fullNode1.ChainHead(ctx)
|
||||
require.NoError(t, err)
|
||||
height1 = head.Height()
|
||||
}
|
||||
|
||||
// Measure each circulating supply at the latest height where market balance was locked
|
||||
// This allows us to normalize against fluctuations in circulating supply based on the underlying
|
||||
// dynamics irrelevant to this change
|
||||
|
||||
max := height0
|
||||
if height0 < height1 {
|
||||
max = height1
|
||||
}
|
||||
max = max + 1 // Measure supply at height after the deal locking funds was published
|
||||
|
||||
// Let both chains catch up
|
||||
fullNode0.WaitTillChain(ctx, func(ts *types.TipSet) bool {
|
||||
return ts.Height() >= max
|
||||
})
|
||||
fullNode1.WaitTillChain(ctx, func(ts *types.TipSet) bool {
|
||||
return ts.Height() >= max
|
||||
})
|
||||
|
||||
ts0, err := fullNode0.ChainGetTipSetByHeight(ctx, max, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
ts1, err := fullNode1.ChainGetTipSetByHeight(ctx, max, types.EmptyTSK)
|
||||
require.NoError(t, err)
|
||||
|
||||
nv22Supply, err := fullNode0.StateVMCirculatingSupplyInternal(ctx, ts0.Key())
|
||||
require.NoError(t, err, "Failed to fetch nv22 circulating supply")
|
||||
nv23Supply, err := fullNode1.StateVMCirculatingSupplyInternal(ctx, ts1.Key())
|
||||
require.NoError(t, err, "Failed to fetch nv23 circulating supply")
|
||||
|
||||
// Unfortunately there's still some non-determinism in supply dynamics so check for equality within a tolerance
|
||||
tolerance := big.Mul(abi.NewTokenAmount(1000), abi.NewTokenAmount(1e18))
|
||||
totalLocked := big.Sum(lockedClientBalance, lockedProviderBalance)
|
||||
diff := big.Sub(
|
||||
big.Sum(totalLocked, nv23Supply.FilLocked),
|
||||
nv22Supply.FilLocked,
|
||||
)
|
||||
assert.Equal(t, -1, big.Cmp(
|
||||
diff.Abs(),
|
||||
tolerance), "Difference from expected locked supply between versions exceeds tolerance")
|
||||
}
|
||||
|
||||
// Message will be valid and lock funds but the data is fake so the deal will never be activated
|
||||
func makePSDMessage(
|
||||
ctx context.Context,
|
||||
t *testing.T,
|
||||
provider,
|
||||
worker,
|
||||
client address.Address,
|
||||
providerLocked,
|
||||
clientLocked abi.TokenAmount,
|
||||
signFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error)) *types.Message {
|
||||
|
||||
dummyCid, err := cid.Parse("baga6ea4seaqflae5c3k2odz4sqfufmrmoegplhk5jbq3co4fgmmy56yc2qfh4aq")
|
||||
require.NoError(t, err)
|
||||
|
||||
duration := 2880 * 200 // 200 days
|
||||
ppe := big.Div(clientLocked, big.NewInt(2880*200))
|
||||
proposal := market.DealProposal{
|
||||
PieceCID: dummyCid,
|
||||
PieceSize: abi.PaddedPieceSize(128),
|
||||
VerifiedDeal: false,
|
||||
Client: client,
|
||||
Provider: provider,
|
||||
ClientCollateral: big.Zero(),
|
||||
ProviderCollateral: providerLocked,
|
||||
StartEpoch: 10000,
|
||||
EndEpoch: 10000 + abi.ChainEpoch(duration),
|
||||
StoragePricePerEpoch: ppe,
|
||||
}
|
||||
buf := bytes.NewBuffer(nil)
|
||||
require.NoError(t, proposal.MarshalCBOR(buf))
|
||||
sig, err := signFunc(ctx, client, buf.Bytes())
|
||||
require.NoError(t, err)
|
||||
// Publish storage deal
|
||||
params, err := actors.SerializeParams(&market.PublishStorageDealsParams{
|
||||
Deals: []market.ClientDealProposal{
|
||||
{
|
||||
Proposal: proposal,
|
||||
ClientSignature: *sig,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return &types.Message{
|
||||
To: builtin.StorageMarketActorAddr,
|
||||
From: worker,
|
||||
Value: types.NewInt(0),
|
||||
Method: builtin.MethodsMarket.PublishStorageDeals,
|
||||
Params: params,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user