From eb3ca82fa063bafecf90b27ab33807299d550455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 4 Sep 2020 13:37:32 +0200 Subject: [PATCH 001/199] net cli: Support miner addresses in net connect --- cli/net.go | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/cli/net.go b/cli/net.go index f3b5ae2e9..9c40c70c7 100644 --- a/cli/net.go +++ b/cli/net.go @@ -8,12 +8,17 @@ import ( "strings" "text/tabwriter" - "github.com/libp2p/go-libp2p-core/peer" - protocol "github.com/libp2p/go-libp2p-core/protocol" - "github.com/dustin/go-humanize" "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + "github.com/libp2p/go-libp2p-core/peer" + protocol "github.com/libp2p/go-libp2p-core/protocol" + "github.com/multiformats/go-multiaddr" + + "github.com/filecoin-project/go-address" + + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/addrutil" ) @@ -141,7 +146,7 @@ var NetListen = &cli.Command{ var netConnect = &cli.Command{ Name: "connect", Usage: "Connect to a peer", - ArgsUsage: "[peerMultiaddr]", + ArgsUsage: "[peerMultiaddr|minerActorAddress]", Action: func(cctx *cli.Context) error { api, closer, err := GetAPI(cctx) if err != nil { @@ -152,7 +157,43 @@ var netConnect = &cli.Command{ pis, err := addrutil.ParseAddresses(ctx, cctx.Args().Slice()) if err != nil { - return err + a, perr := address.NewFromString(cctx.Args().First()) + if perr != nil { + return err + } + + na, fc, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer fc() + + mi, err := na.StateMinerInfo(ctx, a, types.EmptyTSK) + if err != nil { + return xerrors.Errorf("getting miner info: %w", err) + } + + if mi.PeerId == nil { + return xerrors.Errorf("no PeerID for miner") + } + multiaddrs := make([]multiaddr.Multiaddr, 0, len(mi.Multiaddrs)) + for i, a := range mi.Multiaddrs { + maddr, err := multiaddr.NewMultiaddrBytes(a) + if err != nil { + log.Warnf("parsing multiaddr %d (%x): %s", i, a, err) + continue + } + multiaddrs = append(multiaddrs, maddr) + } + + pi := peer.AddrInfo{ + ID: *mi.PeerId, + Addrs: multiaddrs, + } + + fmt.Printf("%s -> %s\n", a, pi) + + pis = append(pis, pi) } for _, pi := range pis { From 51ef39592f049f8d16298a43ff0f840dbadec303 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Fri, 4 Sep 2020 13:44:09 +0200 Subject: [PATCH 002/199] feat: paych - get available funds by address or by from/to --- api/api_full.go | 8 ++- api/apistruct/struct.go | 41 +++++++------ cli/paych.go | 120 +++++++++++++++++++++++++------------- cli/paych_test.go | 16 ++--- node/impl/paych/paych.go | 8 ++- paychmgr/manager.go | 41 ++++++++++++- paychmgr/paych.go | 9 ++- paychmgr/paychget_test.go | 12 ++-- paychmgr/simple.go | 39 +++++-------- paychmgr/store.go | 14 +++++ 10 files changed, 204 insertions(+), 104 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index f913483b3..8ae857dfd 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -421,7 +421,8 @@ type FullNode interface { PaychGet(ctx context.Context, from, to address.Address, amt types.BigInt) (*ChannelInfo, error) PaychGetWaitReady(context.Context, cid.Cid) (address.Address, error) - PaychAvailableFunds(from, to address.Address) (*ChannelAvailableFunds, error) + PaychAvailableFunds(ch address.Address) (*ChannelAvailableFunds, error) + PaychAvailableFundsByFromTo(from, to address.Address) (*ChannelAvailableFunds, error) PaychList(context.Context) ([]address.Address, error) PaychStatus(context.Context, address.Address) (*PaychStatus, error) PaychSettle(context.Context, address.Address) (cid.Cid, error) @@ -540,7 +541,12 @@ type ChannelInfo struct { } type ChannelAvailableFunds struct { + // Channel is the address of the channel Channel *address.Address + // From is the from address of the channel (channel creator) + From address.Address + // To is the to address of the channel + To address.Address // ConfirmedAmt is the amount of funds that have been confirmed on-chain // for the channel ConfirmedAmt types.BigInt diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index dff614001..e2444f16b 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -207,22 +207,23 @@ type FullNodeStruct struct { MarketEnsureAvailable func(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"` - PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` - PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"` - PaychAvailableFunds func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` - PaychList func(context.Context) ([]address.Address, error) `perm:"read"` - PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"` - PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` - PaychCollect func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` - PaychAllocateLane func(context.Context, address.Address) (uint64, error) `perm:"sign"` - PaychNewPayment func(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"` - PaychVoucherCheck func(context.Context, *paych.SignedVoucher) error `perm:"read"` - PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"` - PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"` - PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"` - PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"` - PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` - PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"` + PaychGet func(ctx context.Context, from, to address.Address, amt types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` + PaychGetWaitReady func(context.Context, cid.Cid) (address.Address, error) `perm:"sign"` + PaychAvailableFunds func(address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` + PaychAvailableFundsByFromTo func(address.Address, address.Address) (*api.ChannelAvailableFunds, error) `perm:"sign"` + PaychList func(context.Context) ([]address.Address, error) `perm:"read"` + PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"` + PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` + PaychCollect func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` + PaychAllocateLane func(context.Context, address.Address) (uint64, error) `perm:"sign"` + PaychNewPayment func(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"` + PaychVoucherCheck func(context.Context, *paych.SignedVoucher) error `perm:"read"` + PaychVoucherCheckValid func(context.Context, address.Address, *paych.SignedVoucher) error `perm:"read"` + PaychVoucherCheckSpendable func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) `perm:"read"` + PaychVoucherAdd func(context.Context, address.Address, *paych.SignedVoucher, []byte, types.BigInt) (types.BigInt, error) `perm:"write"` + PaychVoucherCreate func(context.Context, address.Address, big.Int, uint64) (*api.VoucherCreateResult, error) `perm:"sign"` + PaychVoucherList func(context.Context, address.Address) ([]*paych.SignedVoucher, error) `perm:"write"` + PaychVoucherSubmit func(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (cid.Cid, error) `perm:"sign"` } } @@ -905,8 +906,12 @@ func (c *FullNodeStruct) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid return c.Internal.PaychGetWaitReady(ctx, sentinel) } -func (c *FullNodeStruct) PaychAvailableFunds(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) { - return c.Internal.PaychAvailableFunds(from, to) +func (c *FullNodeStruct) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) { + return c.Internal.PaychAvailableFunds(ch) +} + +func (c *FullNodeStruct) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) { + return c.Internal.PaychAvailableFundsByFromTo(from, to) } func (c *FullNodeStruct) PaychList(ctx context.Context) ([]address.Address, error) { diff --git a/cli/paych.go b/cli/paych.go index 11b550cc6..6e2104551 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -8,6 +8,8 @@ import ( "sort" "strings" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/paychmgr" "github.com/filecoin-project/go-address" @@ -80,13 +82,13 @@ var paychAddFundsCmd = &cli.Command{ }, } -var paychStatusCmd = &cli.Command{ - Name: "status", - Usage: "Show the status of an outbound payment channel between fromAddress and toAddress", +var paychStatusByFromToCmd = &cli.Command{ + Name: "status-by-from-to", + Usage: "Show the status of an active outbound payment channel by from/to addresses", ArgsUsage: "[fromAddress toAddress]", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 2 { - return ShowHelp(cctx, fmt.Errorf("must pass two arguments: ")) + return ShowHelp(cctx, fmt.Errorf("must pass two arguments: ")) } from, err := address.NewFromString(cctx.Args().Get(0)) @@ -105,52 +107,86 @@ var paychStatusCmd = &cli.Command{ } defer closer() - avail, err := api.PaychAvailableFunds(from, to) + avail, err := api.PaychAvailableFundsByFromTo(from, to) if err != nil { return err } - if avail.Channel == nil { - if avail.PendingWaitSentinel != nil { - fmt.Fprint(cctx.App.Writer, "Creating channel\n") - fmt.Fprintf(cctx.App.Writer, " From: %s\n", from) - fmt.Fprintf(cctx.App.Writer, " To: %s\n", to) - fmt.Fprintf(cctx.App.Writer, " Pending Amt: %d\n", avail.PendingAmt) - fmt.Fprintf(cctx.App.Writer, " Wait Sentinel: %s\n", avail.PendingWaitSentinel) - return nil - } - fmt.Fprint(cctx.App.Writer, "Channel does not exist\n") - fmt.Fprintf(cctx.App.Writer, " From: %s\n", from) - fmt.Fprintf(cctx.App.Writer, " To: %s\n", to) - return nil - } - - if avail.PendingWaitSentinel != nil { - fmt.Fprint(cctx.App.Writer, "Adding Funds to channel\n") - } else { - fmt.Fprint(cctx.App.Writer, "Channel exists\n") - } - - nameValues := [][]string{ - {"Channel", avail.Channel.String()}, - {"From", from.String()}, - {"To", to.String()}, - {"Confirmed Amt", fmt.Sprintf("%d", avail.ConfirmedAmt)}, - {"Pending Amt", fmt.Sprintf("%d", avail.PendingAmt)}, - {"Queued Amt", fmt.Sprintf("%d", avail.QueuedAmt)}, - {"Voucher Redeemed Amt", fmt.Sprintf("%d", avail.VoucherReedeemedAmt)}, - } - if avail.PendingWaitSentinel != nil { - nameValues = append(nameValues, []string{ - "Add Funds Wait Sentinel", - avail.PendingWaitSentinel.String(), - }) - } - fmt.Fprint(cctx.App.Writer, formatNameValues(nameValues)) + paychStatus(cctx.App.Writer, avail) return nil }, } +var paychStatusCmd = &cli.Command{ + Name: "status", + Usage: "Show the status of an outbound payment channel", + ArgsUsage: "[channelAddress]", + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 1 { + return ShowHelp(cctx, fmt.Errorf("must pass an argument: ")) + } + + ch, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return ShowHelp(cctx, fmt.Errorf("failed to parse channel address: %s", err)) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + avail, err := api.PaychAvailableFunds(ch) + if err != nil { + return err + } + + paychStatus(cctx.App.Writer, avail) + return nil + }, +} + +func paychStatus(writer io.Writer, avail *api.ChannelAvailableFunds) { + if avail.Channel == nil { + if avail.PendingWaitSentinel != nil { + fmt.Fprint(writer, "Creating channel\n") + fmt.Fprintf(writer, " From: %s\n", avail.From) + fmt.Fprintf(writer, " To: %s\n", avail.To) + fmt.Fprintf(writer, " Pending Amt: %d\n", avail.PendingAmt) + fmt.Fprintf(writer, " Wait Sentinel: %s\n", avail.PendingWaitSentinel) + return + } + fmt.Fprint(writer, "Channel does not exist\n") + fmt.Fprintf(writer, " From: %s\n", avail.From) + fmt.Fprintf(writer, " To: %s\n", avail.To) + return + } + + if avail.PendingWaitSentinel != nil { + fmt.Fprint(writer, "Adding Funds to channel\n") + } else { + fmt.Fprint(writer, "Channel exists\n") + } + + nameValues := [][]string{ + {"Channel", avail.Channel.String()}, + {"From", avail.From.String()}, + {"To", avail.To.String()}, + {"Confirmed Amt", fmt.Sprintf("%d", avail.ConfirmedAmt)}, + {"Pending Amt", fmt.Sprintf("%d", avail.PendingAmt)}, + {"Queued Amt", fmt.Sprintf("%d", avail.QueuedAmt)}, + {"Voucher Redeemed Amt", fmt.Sprintf("%d", avail.VoucherReedeemedAmt)}, + } + if avail.PendingWaitSentinel != nil { + nameValues = append(nameValues, []string{ + "Add Funds Wait Sentinel", + avail.PendingWaitSentinel.String(), + }) + } + fmt.Fprint(writer, formatNameValues(nameValues)) +} + func formatNameValues(nameValues [][]string) string { maxLen := 0 for _, nv := range nameValues { diff --git a/cli/paych_test.go b/cli/paych_test.go index 8eaeb0f13..9b21d8070 100644 --- a/cli/paych_test.go +++ b/cli/paych_test.go @@ -117,7 +117,7 @@ func TestPaymentChannelStatus(t *testing.T) { creatorCLI := mockCLI.client(paymentCreator.ListenAddr) cmd := []string{creatorAddr.String(), receiverAddr.String()} - out := creatorCLI.runCmd(paychStatusCmd, cmd) + out := creatorCLI.runCmd(paychStatusByFromToCmd, cmd) fmt.Println(out) noChannelState := "Channel does not exist" require.Regexp(t, regexp.MustCompile(noChannelState), out) @@ -125,15 +125,15 @@ func TestPaymentChannelStatus(t *testing.T) { channelAmt := uint64(100) create := make(chan string) go func() { - // creator: paych get + // creator: paych add-funds cmd = []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)} - create <- creatorCLI.runCmd(paychGetCmd, cmd) + create <- creatorCLI.runCmd(paychAddFundsCmd, cmd) }() // Wait for the output to stop being "Channel does not exist" for regexp.MustCompile(noChannelState).MatchString(out) { cmd = []string{creatorAddr.String(), receiverAddr.String()} - out = creatorCLI.runCmd(paychStatusCmd, cmd) + out = creatorCLI.runCmd(paychStatusByFromToCmd, cmd) } fmt.Println(out) @@ -153,7 +153,7 @@ func TestPaymentChannelStatus(t *testing.T) { // Wait for create channel to complete chstr := <-create - cmd = []string{creatorAddr.String(), receiverAddr.String()} + cmd = []string{chstr} out = creatorCLI.runCmd(paychStatusCmd, cmd) fmt.Println(out) // Output should have the channel address @@ -169,7 +169,7 @@ func TestPaymentChannelStatus(t *testing.T) { cmd = []string{chAddr.String(), fmt.Sprintf("%d", voucherAmt)} creatorCLI.runCmd(paychVoucherCreateCmd, cmd) - cmd = []string{creatorAddr.String(), receiverAddr.String()} + cmd = []string{chstr} out = creatorCLI.runCmd(paychStatusCmd, cmd) fmt.Println(out) voucherAmtAtto := types.BigMul(types.NewInt(voucherAmt), types.NewInt(build.FilecoinPrecision)) @@ -344,10 +344,10 @@ func TestPaymentChannelVoucherCreateShortfall(t *testing.T) { mockCLI := newMockCLI(t) creatorCLI := mockCLI.client(paymentCreator.ListenAddr) - // creator: paych get + // creator: paych add-funds channelAmt := 100 cmd := []string{creatorAddr.String(), receiverAddr.String(), fmt.Sprintf("%d", channelAmt)} - chstr := creatorCLI.runCmd(paychGetCmd, cmd) + chstr := creatorCLI.runCmd(paychAddFundsCmd, cmd) chAddr, err := address.NewFromString(chstr) require.NoError(t, err) diff --git a/node/impl/paych/paych.go b/node/impl/paych/paych.go index e998f969f..84c2cc030 100644 --- a/node/impl/paych/paych.go +++ b/node/impl/paych/paych.go @@ -39,8 +39,12 @@ func (a *PaychAPI) PaychGet(ctx context.Context, from, to address.Address, amt t }, nil } -func (a *PaychAPI) PaychAvailableFunds(from, to address.Address) (*api.ChannelAvailableFunds, error) { - return a.PaychMgr.AvailableFunds(from, to) +func (a *PaychAPI) PaychAvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) { + return a.PaychMgr.AvailableFunds(ch) +} + +func (a *PaychAPI) PaychAvailableFundsByFromTo(from, to address.Address) (*api.ChannelAvailableFunds, error) { + return a.PaychMgr.AvailableFundsByFromTo(from, to) } func (a *PaychAPI) PaychGetWaitReady(ctx context.Context, sentinel cid.Cid) (address.Address, error) { diff --git a/paychmgr/manager.go b/paychmgr/manager.go index d1fd715ef..00d796eea 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -141,13 +141,48 @@ func (pm *Manager) GetPaych(ctx context.Context, from, to address.Address, amt t return chanAccessor.getPaych(ctx, amt) } -func (pm *Manager) AvailableFunds(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) { - chanAccessor, err := pm.accessorByFromTo(from, to) +func (pm *Manager) AvailableFunds(ch address.Address) (*api.ChannelAvailableFunds, error) { + ca, err := pm.accessorByAddress(ch) if err != nil { return nil, err } - return chanAccessor.availableFunds() + ci, err := ca.getChannelInfo(ch) + if err != nil { + return nil, err + } + + return ca.availableFunds(ci.ChannelID) +} + +func (pm *Manager) AvailableFundsByFromTo(from address.Address, to address.Address) (*api.ChannelAvailableFunds, error) { + ca, err := pm.accessorByFromTo(from, to) + if err != nil { + return nil, err + } + + ci, err := ca.outboundActiveByFromTo(from, to) + if err == ErrChannelNotTracked { + // If there is no active channel between from / to we still want to + // return an empty ChannelAvailableFunds, so that clients can check + // for the existence of a channel between from / to without getting + // an error. + return &api.ChannelAvailableFunds{ + Channel: nil, + From: from, + To: to, + ConfirmedAmt: types.NewInt(0), + PendingAmt: types.NewInt(0), + PendingWaitSentinel: nil, + QueuedAmt: types.NewInt(0), + VoucherReedeemedAmt: types.NewInt(0), + }, nil + } + if err != nil { + return nil, err + } + + return ca.availableFunds(ci.ChannelID) } // GetPaychWaitReady waits until the create channel / add funds message with the diff --git a/paychmgr/paych.go b/paychmgr/paych.go index be43aaf9b..dd655b3e6 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -20,7 +20,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/specs-actors/actors/builtin/paych" - xerrors "golang.org/x/xerrors" + "golang.org/x/xerrors" ) // insufficientFundsErr indicates that there are not enough funds in the @@ -81,6 +81,13 @@ func (ca *channelAccessor) getChannelInfo(addr address.Address) (*ChannelInfo, e return ca.store.ByAddress(addr) } +func (ca *channelAccessor) outboundActiveByFromTo(from, to address.Address) (*ChannelInfo, error) { + ca.lk.Lock() + defer ca.lk.Unlock() + + return ca.store.OutboundActiveByFromTo(from, to) +} + // createVoucher creates a voucher with the given specification, setting its // nonce, signing the voucher and storing it in the local datastore. // If there are not enough funds in the channel to create the voucher, returns diff --git a/paychmgr/paychget_test.go b/paychmgr/paychget_test.go index 8eff08bdd..07c84e764 100644 --- a/paychmgr/paychget_test.go +++ b/paychmgr/paychget_test.go @@ -921,7 +921,7 @@ func TestPaychAvailableFunds(t *testing.T) { require.NoError(t, err) // No channel created yet so available funds should be all zeroes - av, err := mgr.AvailableFunds(from, to) + av, err := mgr.AvailableFundsByFromTo(from, to) require.NoError(t, err) require.Nil(t, av.Channel) require.Nil(t, av.PendingWaitSentinel) @@ -936,7 +936,7 @@ func TestPaychAvailableFunds(t *testing.T) { require.NoError(t, err) // Available funds should reflect create channel message sent - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFundsByFromTo(from, to) require.NoError(t, err) require.Nil(t, av.Channel) require.EqualValues(t, 0, av.ConfirmedAmt.Int64()) @@ -964,7 +964,7 @@ func TestPaychAvailableFunds(t *testing.T) { waitForQueueSize(t, mgr, from, to, 1) // Available funds should now include queued funds - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFundsByFromTo(from, to) require.NoError(t, err) require.Nil(t, av.Channel) require.NotNil(t, av.PendingWaitSentinel) @@ -1009,7 +1009,7 @@ func TestPaychAvailableFunds(t *testing.T) { // Available funds should now include the channel and also a wait sentinel // for the add funds message - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFunds(ch) require.NoError(t, err) require.NotNil(t, av.Channel) require.NotNil(t, av.PendingWaitSentinel) @@ -1031,7 +1031,7 @@ func TestPaychAvailableFunds(t *testing.T) { require.NoError(t, err) // Available funds should no longer have a wait sentinel - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFunds(ch) require.NoError(t, err) require.NotNil(t, av.Channel) require.Nil(t, av.PendingWaitSentinel) @@ -1052,7 +1052,7 @@ func TestPaychAvailableFunds(t *testing.T) { _, err = mgr.AddVoucherOutbound(ctx, ch, voucher, nil, types.NewInt(0)) require.NoError(t, err) - av, err = mgr.AvailableFunds(from, to) + av, err = mgr.AvailableFunds(ch) require.NoError(t, err) require.NotNil(t, av.Channel) require.Nil(t, av.PendingWaitSentinel) diff --git a/paychmgr/simple.go b/paychmgr/simple.go index 88d94645e..561f2dfc7 100644 --- a/paychmgr/simple.go +++ b/paychmgr/simple.go @@ -187,11 +187,11 @@ func (ca *channelAccessor) enqueue(task *fundsReq) { defer ca.lk.Unlock() ca.fundsReqQueue = append(ca.fundsReqQueue, task) - go ca.processQueue() // nolint: errcheck + go ca.processQueue("") // nolint: errcheck } // Run the operations in the queue -func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { +func (ca *channelAccessor) processQueue(channelID string) (*api.ChannelAvailableFunds, error) { ca.lk.Lock() defer ca.lk.Unlock() @@ -200,7 +200,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { // If there's nothing in the queue, bail out if len(ca.fundsReqQueue) == 0 { - return ca.currentAvailableFunds(types.NewInt(0)) + return ca.currentAvailableFunds(channelID, types.NewInt(0)) } // Merge all pending requests into one. @@ -211,7 +211,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { if amt.IsZero() { // Note: The amount can be zero if requests are cancelled as we're // building the mergedFundsReq - return ca.currentAvailableFunds(amt) + return ca.currentAvailableFunds(channelID, amt) } res := ca.processTask(merged.ctx, amt) @@ -221,7 +221,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { if res == nil { // Stop processing the fundsReqQueue and wait. When the event occurs it will // call processQueue() again - return ca.currentAvailableFunds(amt) + return ca.currentAvailableFunds(channelID, amt) } // Finished processing so clear the queue @@ -230,7 +230,7 @@ func (ca *channelAccessor) processQueue() (*api.ChannelAvailableFunds, error) { // Call the task callback with its results merged.onComplete(res) - return ca.currentAvailableFunds(types.NewInt(0)) + return ca.currentAvailableFunds(channelID, types.NewInt(0)) } // filterQueue filters cancelled requests out of the queue @@ -283,25 +283,16 @@ func (ca *channelAccessor) msgWaitComplete(mcid cid.Cid, err error) { // The queue may have been waiting for msg completion to proceed, so // process the next queue item if len(ca.fundsReqQueue) > 0 { - go ca.processQueue() // nolint: errcheck + go ca.processQueue("") // nolint: errcheck } } -func (ca *channelAccessor) currentAvailableFunds(queuedAmt types.BigInt) (*api.ChannelAvailableFunds, error) { - channelInfo, err := ca.store.OutboundActiveByFromTo(ca.from, ca.to) - if err == ErrChannelNotTracked { - // If the channel does not exist we still want to return an empty - // ChannelAvailableFunds, so that clients can check for the existence - // of a channel between from / to without getting an error. - return &api.ChannelAvailableFunds{ - Channel: nil, - ConfirmedAmt: types.NewInt(0), - PendingAmt: types.NewInt(0), - PendingWaitSentinel: nil, - QueuedAmt: queuedAmt, - VoucherReedeemedAmt: types.NewInt(0), - }, nil +func (ca *channelAccessor) currentAvailableFunds(channelID string, queuedAmt types.BigInt) (*api.ChannelAvailableFunds, error) { + if len(channelID) == 0 { + return nil, nil } + + channelInfo, err := ca.store.ByChannelID(channelID) if err != nil { return nil, err } @@ -335,6 +326,8 @@ func (ca *channelAccessor) currentAvailableFunds(queuedAmt types.BigInt) (*api.C return &api.ChannelAvailableFunds{ Channel: channelInfo.Channel, + From: channelInfo.from(), + To: channelInfo.to(), ConfirmedAmt: channelInfo.Amount, PendingAmt: channelInfo.PendingAmount, PendingWaitSentinel: waitSentinel, @@ -713,6 +706,6 @@ func (ca *channelAccessor) msgPromise(ctx context.Context, mcid cid.Cid) chan on return promise } -func (ca *channelAccessor) availableFunds() (*api.ChannelAvailableFunds, error) { - return ca.processQueue() +func (ca *channelAccessor) availableFunds(channelID string) (*api.ChannelAvailableFunds, error) { + return ca.processQueue(channelID) } diff --git a/paychmgr/store.go b/paychmgr/store.go index 4a5a4f49f..46249fa36 100644 --- a/paychmgr/store.go +++ b/paychmgr/store.go @@ -86,6 +86,20 @@ type ChannelInfo struct { Settling bool } +func (ci *ChannelInfo) from() address.Address { + if ci.Direction == DirOutbound { + return ci.Control + } + return ci.Target +} + +func (ci *ChannelInfo) to() address.Address { + if ci.Direction == DirOutbound { + return ci.Target + } + return ci.Control +} + // infoForVoucher gets the VoucherInfo for the given voucher. // returns nil if the channel doesn't have the voucher. func (ci *ChannelInfo) infoForVoucher(sv *paych.SignedVoucher) (*VoucherInfo, error) { From 5ef753bfa830296a3f1ad0c711719b582c9b3259 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Fri, 4 Sep 2020 10:04:50 -0700 Subject: [PATCH 003/199] fix(markets): check for nil tipset check for nil tipset when check func is called to avoid panic --- markets/storageadapter/client.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 91fc6a054..1d41ecf91 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -351,6 +351,11 @@ func (c *ClientNodeAdapter) OnDealExpiredOrSlashed(ctx context.Context, dealID a // Called immediately to check if the deal has already expired or been slashed checkFunc := func(ts *types.TipSet) (done bool, more bool, err error) { + if ts == nil { + // keep listening for events + return false, true, nil + } + // Check if the deal has already expired if sd.Proposal.EndEpoch <= ts.Height() { onDealExpired(nil) From 1c27a0c1cf921eb4874a22fa9a1c197666f1b8ea Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 4 Sep 2020 22:04:48 +0300 Subject: [PATCH 004/199] adjust gossipsub gossip factor --- node/modules/lp2p/pubsub.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index d4464e4de..19cd67906 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -33,6 +33,7 @@ func init() { pubsub.GossipSubDirectConnectInitialDelay = 30 * time.Second pubsub.GossipSubIWantFollowupTime = 5 * time.Second pubsub.GossipSubHistoryLength = 10 + pubsub.GossipSubGossipFactor = 0.1 } func ScoreKeeper() *dtypes.ScoreKeeper { return new(dtypes.ScoreKeeper) @@ -248,8 +249,8 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { pubsub.GossipSubDlo = 0 pubsub.GossipSubDhi = 0 pubsub.GossipSubDout = 0 - pubsub.GossipSubDlazy = 1024 - pubsub.GossipSubGossipFactor = 0.5 + pubsub.GossipSubDlazy = 64 + pubsub.GossipSubGossipFactor = 0.25 pubsub.GossipSubPruneBackoff = 5 * time.Minute // turn on PX options = append(options, pubsub.WithPeerExchange(true)) From 6d538621426fe6ff4ffedee65fb9516f1a027b74 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 4 Sep 2020 22:16:10 +0300 Subject: [PATCH 005/199] republish messages even if the chains have negative performance --- chain/messagepool/repub.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index 1173bdb48..044c4ce36 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -67,12 +67,6 @@ func (mp *MessagePool) republishPendingMessages() error { return chains[i].Before(chains[j]) }) - // we don't republish negative performing chains; this is an error that will be screamed - // at the user - if chains[0].gasPerf < 0 { - return xerrors.Errorf("skipping republish: all message chains have negative gas performance; best gas performance: %f", chains[0].gasPerf) - } - gasLimit := int64(build.BlockGasLimit) minGas := int64(gasguess.MinGas) var msgs []*types.SignedMessage @@ -89,12 +83,6 @@ func (mp *MessagePool) republishPendingMessages() error { break } - // we don't republish negative performing chains, as they won't be included in - // a block anyway - if chain.gasPerf < 0 { - break - } - // has the chain been invalidated? if !chain.valid { i++ From 30fdff17b5ece17b2e2890640536c7d6af27d4be Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 3 Sep 2020 20:27:59 -0700 Subject: [PATCH 006/199] Skip nil exports The actors may skip previously used but no longer defined method numbers. --- chain/vm/invoker.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 56f769da2..eaac395ea 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -130,6 +130,9 @@ func (*Invoker) transform(instance Invokee) (nativeCode, error) { } code := make(nativeCode, len(exports)) for id, m := range exports { + if m == nil { + continue + } meth := reflect.ValueOf(m) code[id] = reflect.MakeFunc(reflect.TypeOf((invokeFunc)(nil)), func(in []reflect.Value) []reflect.Value { From fceeaf42ca956d6206a39ed9783c0792a365221a Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Thu, 3 Sep 2020 20:28:42 -0700 Subject: [PATCH 007/199] Robustify state manager against holes in actor method numbers Also, don't simply assume that the field order matches the method numbers in `builtin.Method*` structs. --- chain/stmgr/utils.go | 80 ++++++++++++++++++++++++++++++++++---------- cli/send.go | 7 +++- cli/state.go | 12 +++++-- 3 files changed, 79 insertions(+), 20 deletions(-) diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index db6157b09..17f84e18d 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -3,8 +3,11 @@ package stmgr import ( "bytes" "context" + "fmt" "os" "reflect" + "runtime" + "strings" cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" @@ -586,14 +589,14 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe }, nil } -type methodMeta struct { +type MethodMeta struct { Name string Params reflect.Type Ret reflect.Type } -var MethodsMap = map[cid.Cid][]methodMeta{} +var MethodsMap = map[cid.Cid]map[abi.MethodNum]MethodMeta{} func init() { cidToMethods := map[cid.Cid][2]interface{}{ @@ -611,25 +614,65 @@ func init() { } for c, m := range cidToMethods { - rt := reflect.TypeOf(m[0]) - nf := rt.NumField() + exports := m[1].(abi.Invokee).Exports() + methods := make(map[abi.MethodNum]MethodMeta, len(exports)) - MethodsMap[c] = append(MethodsMap[c], methodMeta{ + // Explicitly add send, it's special. + methods[builtin.MethodSend] = MethodMeta{ Name: "Send", Params: reflect.TypeOf(new(adt.EmptyValue)), Ret: reflect.TypeOf(new(adt.EmptyValue)), - }) - - exports := m[1].(abi.Invokee).Exports() - for i := 0; i < nf; i++ { - export := reflect.TypeOf(exports[i+1]) - - MethodsMap[c] = append(MethodsMap[c], methodMeta{ - Name: rt.Field(i).Name, - Params: export.In(1), - Ret: export.Out(0), - }) } + + // Learn method names from the builtin.Methods* structs. + rv := reflect.ValueOf(m[0]) + rt := rv.Type() + nf := rt.NumField() + methodToName := make([]string, len(exports)) + for i := 0; i < nf; i++ { + name := rt.Field(i).Name + number := rv.Field(i).Interface().(abi.MethodNum) + methodToName[number] = name + } + + // Iterate over exported methods. Some of these _may_ be nil and + // must be skipped. + for number, export := range exports { + if export == nil { + continue + } + + ev := reflect.ValueOf(export) + et := ev.Type() + + // Make sure the method name is correct. + // This is just a nice sanity check. + fnName := runtime.FuncForPC(ev.Pointer()).Name() + fnName = strings.TrimSuffix(fnName[strings.LastIndexByte(fnName, '.')+1:], "-fm") + mName := methodToName[number] + if mName != fnName { + panic(fmt.Sprintf( + "actor method name is %s but exported method name is %s", + fnName, mName, + )) + } + + switch abi.MethodNum(number) { + case builtin.MethodSend: + panic("method 0 is reserved for Send") + case builtin.MethodConstructor: + if fnName != "Constructor" { + panic("method 1 is reserved for Constructor") + } + } + + methods[abi.MethodNum(number)] = MethodMeta{ + Name: fnName, + Params: et.In(1), + Ret: et.Out(0), + } + } + MethodsMap[c] = methods } } @@ -639,7 +682,10 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me return nil, xerrors.Errorf("getting actor: %w", err) } - m := MethodsMap[act.Code][method] + m, found := MethodsMap[act.Code][method] + if !found { + return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code) + } return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil } diff --git a/cli/send.go b/cli/send.go index ecec42191..d06767241 100644 --- a/cli/send.go +++ b/cli/send.go @@ -173,7 +173,12 @@ func decodeTypedParams(ctx context.Context, fapi api.FullNode, to address.Addres return nil, err } - p := reflect.New(stmgr.MethodsMap[act.Code][method].Params.Elem()).Interface().(cbg.CBORMarshaler) + methodMeta, found := stmgr.MethodsMap[act.Code][method] + if !found { + return nil, fmt.Errorf("method %d not found on actor %s", method, act.Code) + } + + p := reflect.New(methodMeta.Params.Elem()).Interface().(cbg.CBORMarshaler) if err := json.Unmarshal([]byte(paramstr), p); err != nil { return nil, fmt.Errorf("unmarshaling input into params type: %w", err) diff --git a/cli/state.go b/cli/state.go index a0256c2e3..a5c11cde6 100644 --- a/cli/state.go +++ b/cli/state.go @@ -1167,7 +1167,11 @@ func sumGas(changes []*types.GasTrace) types.GasTrace { } func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, error) { - re := reflect.New(stmgr.MethodsMap[code][method].Params.Elem()) + methodMeta, found := stmgr.MethodsMap[code][method] + if !found { + return "", fmt.Errorf("method %d not found on actor %s", method, code) + } + re := reflect.New(methodMeta.Params.Elem()) p := re.Interface().(cbg.CBORUnmarshaler) if err := p.UnmarshalCBOR(bytes.NewReader(params)); err != nil { return "", err @@ -1178,7 +1182,11 @@ func jsonParams(code cid.Cid, method abi.MethodNum, params []byte) (string, erro } func jsonReturn(code cid.Cid, method abi.MethodNum, ret []byte) (string, error) { - re := reflect.New(stmgr.MethodsMap[code][method].Ret.Elem()) + methodMeta, found := stmgr.MethodsMap[code][method] + if !found { + return "", fmt.Errorf("method %d not found on actor %s", method, code) + } + re := reflect.New(methodMeta.Ret.Elem()) p := re.Interface().(cbg.CBORUnmarshaler) if err := p.UnmarshalCBOR(bytes.NewReader(ret)); err != nil { return "", err From ad8d550d73613eed9e8544cda7e3665b286f2157 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 4 Sep 2020 22:32:30 +0300 Subject: [PATCH 008/199] remove unused ts argument from Trim, replace it with allowNegative specifier --- chain/messagepool/repub.go | 2 +- chain/messagepool/selection.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index 044c4ce36..806171f52 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -99,7 +99,7 @@ func (mp *MessagePool) republishPendingMessages() error { // we can't fit the current chain but there is gas to spare // trim it and push it down - chain.Trim(gasLimit, mp, baseFee, ts) + chain.Trim(gasLimit, mp, baseFee, true) for j := i; j < len(chains)-1; j++ { if chains[j].Before(chains[j+1]) { break diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 5ba679d76..9a1baaab4 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -217,7 +217,7 @@ tailLoop: for gasLimit >= minGas && last < len(chains) { // trim if necessary if chains[last].gasLimit > gasLimit { - chains[last].Trim(gasLimit, mp, baseFee, ts) + chains[last].Trim(gasLimit, mp, baseFee, false) } // push down if it hasn't been invalidated @@ -284,7 +284,7 @@ tailLoop: } // dependencies fit, just trim it - chain.Trim(gasLimit-depGasLimit, mp, baseFee, ts) + chain.Trim(gasLimit-depGasLimit, mp, baseFee, false) last += i continue tailLoop } @@ -389,7 +389,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S tailLoop: for gasLimit >= minGas && last < len(chains) { // trim - chains[last].Trim(gasLimit, mp, baseFee, ts) + chains[last].Trim(gasLimit, mp, baseFee, false) // push down if it hasn't been invalidated if chains[last].valid { @@ -497,7 +497,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui tailLoop: for gasLimit >= minGas && last < len(chains) { // trim, discarding negative performing messages - chains[last].Trim(gasLimit, mp, baseFee, ts) + chains[last].Trim(gasLimit, mp, baseFee, false) // push down if it hasn't been invalidated if chains[last].valid { @@ -775,9 +775,9 @@ func (mc *msgChain) Before(other *msgChain) bool { (mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0) } -func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, ts *types.TipSet) { +func (mc *msgChain) Trim(gasLimit int64, mp *MessagePool, baseFee types.BigInt, allowNegative bool) { i := len(mc.msgs) - 1 - for i >= 0 && (mc.gasLimit > gasLimit || mc.gasPerf < 0) { + for i >= 0 && (mc.gasLimit > gasLimit || (!allowNegative && mc.gasPerf < 0)) { gasReward := mp.getGasReward(mc.msgs[i], baseFee) mc.gasReward = new(big.Int).Sub(mc.gasReward, gasReward) mc.gasLimit -= mc.msgs[i].Message.GasLimit From 275f071b12b8b0201eadb7714a2d960b0d4cf1ed Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 5 Sep 2020 00:28:13 +0300 Subject: [PATCH 009/199] reduce mpool add failure log spam --- chain/messagepool/messagepool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index e41e8b0c7..b20bc8b91 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -604,7 +604,7 @@ func (mp *MessagePool) addLocked(m *types.SignedMessage, strict bool) error { incr, err := mset.add(m, mp, strict) if err != nil { - log.Info(err) + log.Debug(err) return err } From d6691fe9d8129718979f71188f98dab8b82608cc Mon Sep 17 00:00:00 2001 From: Travis Person Date: Fri, 4 Sep 2020 19:30:46 +0000 Subject: [PATCH 010/199] lotus-pcr: add tipset aggregation --- cmd/lotus-pcr/main.go | 49 +++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/cmd/lotus-pcr/main.go b/cmd/lotus-pcr/main.go index 80732accf..613e746dc 100644 --- a/cmd/lotus-pcr/main.go +++ b/cmd/lotus-pcr/main.go @@ -125,7 +125,13 @@ var runCmd = &cli.Command{ Name: "max-message-queue", EnvVars: []string{"LOTUS_PCR_MAX_MESSAGE_QUEUE"}, Usage: "set the maximum number of messages that can be queue in the mpool", - Value: 3000, + Value: 300, + }, + &cli.IntFlag{ + Name: "aggregate-tipsets", + EnvVars: []string{"LOTUS_PCR_AGGREGATE_TIPSETS"}, + Usage: "number of tipsets to process before sending messages", + Value: 1, }, &cli.BoolFlag{ Name: "dry-run", @@ -194,6 +200,7 @@ var runCmd = &cli.Command{ dryRun := cctx.Bool("dry-run") preCommitEnabled := cctx.Bool("pre-commit") proveCommitEnabled := cctx.Bool("prove-commit") + aggregateTipsets := cctx.Int("aggregate-tipsets") rf := &refunder{ api: api, @@ -204,16 +211,27 @@ var runCmd = &cli.Command{ proveCommitEnabled: proveCommitEnabled, } + var refunds *MinersRefund = NewMinersRefund() + var rounds int = 0 + for tipset := range tipsetsCh { - refunds, err := rf.ProcessTipset(ctx, tipset) + refunds, err = rf.ProcessTipset(ctx, tipset, refunds) if err != nil { return err } - if err := rf.Refund(ctx, tipset, refunds); err != nil { + rounds = rounds + 1 + if rounds < aggregateTipsets { + continue + } + + if err := rf.Refund(ctx, tipset, refunds, rounds); err != nil { return err } + rounds = 0 + refunds = NewMinersRefund() + if err := r.SetHeight(tipset.Height()); err != nil { return err } @@ -247,13 +265,15 @@ var runCmd = &cli.Command{ } type MinersRefund struct { - refunds map[address.Address]types.BigInt - count int + refunds map[address.Address]types.BigInt + count int + totalRefunds types.BigInt } func NewMinersRefund() *MinersRefund { return &MinersRefund{ - refunds: make(map[address.Address]types.BigInt), + refunds: make(map[address.Address]types.BigInt), + totalRefunds: types.NewInt(0), } } @@ -263,6 +283,7 @@ func (m *MinersRefund) Track(addr address.Address, value types.BigInt) { } m.count = m.count + 1 + m.totalRefunds = types.BigAdd(m.totalRefunds, value) m.refunds[addr] = types.BigAdd(m.refunds[addr], value) } @@ -271,6 +292,10 @@ func (m *MinersRefund) Count() int { return m.count } +func (m *MinersRefund) TotalRefunds() types.BigInt { + return m.totalRefunds +} + func (m *MinersRefund) Miners() []address.Address { miners := make([]address.Address, 0, len(m.refunds)) for addr := range m.refunds { @@ -305,7 +330,7 @@ type refunder struct { proveCommitEnabled bool } -func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet) (*MinersRefund, error) { +func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) (*MinersRefund, error) { cids := tipset.Cids() if len(cids) == 0 { log.Errorw("no cids in tipset", "height", tipset.Height(), "key", tipset.Key()) @@ -329,9 +354,8 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet) (*Mi return nil, nil } - refunds := NewMinersRefund() - refundValue := types.NewInt(0) + tipsetRefunds := NewMinersRefund() for i, msg := range msgs { m := msg.Message @@ -427,12 +451,15 @@ func (r *refunder) ProcessTipset(ctx context.Context, tipset *types.TipSet) (*Mi log.Debugw("processing message", "method", messageMethod, "cid", msg.Cid, "from", m.From, "to", m.To, "value", m.Value, "gas_fee_cap", m.GasFeeCap, "gas_premium", m.GasPremium, "gas_used", recps[i].GasUsed, "refund", refundValue) refunds.Track(m.From, refundValue) + tipsetRefunds.Track(m.From, refundValue) } + log.Infow("tipset stats", "height", tipset.Height(), "key", tipset.Key(), "total_refunds", tipsetRefunds.TotalRefunds(), "messages_processed", tipsetRefunds.Count()) + return refunds, nil } -func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund) error { +func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *MinersRefund, rounds int) error { if refunds.Count() == 0 { log.Debugw("no messages to refund in tipset", "height", tipset.Height(), "key", tipset.Key()) return nil @@ -490,7 +517,7 @@ func (r *refunder) Refund(ctx context.Context, tipset *types.TipSet, refunds *Mi refundSum = types.BigAdd(refundSum, msg.Value) } - log.Infow("tipset stats", "height", tipset.Height(), "key", tipset.Key(), "messages_sent", len(messages)-failures, "refund_sum", refundSum, "messages_failures", failures, "messages_processed", refunds.Count()) + log.Infow("refund stats", "tipsets_processed", rounds, "height", tipset.Height(), "key", tipset.Key(), "messages_sent", len(messages)-failures, "refund_sum", refundSum, "messages_failures", failures, "messages_processed", refunds.Count()) return nil } From eebd2efcbf76b71838e3387d69d14e0884d33e60 Mon Sep 17 00:00:00 2001 From: Travis Person Date: Sat, 5 Sep 2020 00:40:57 +0000 Subject: [PATCH 011/199] lotus-shed: add math command --- cmd/lotus-shed/main.go | 1 + cmd/lotus-shed/math.go | 103 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 cmd/lotus-shed/math.go diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 5438a31ef..fb931decf 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -31,6 +31,7 @@ func main() { miscCmd, mpoolCmd, genesisVerifyCmd, + mathCmd, } app := &cli.App{ diff --git a/cmd/lotus-shed/math.go b/cmd/lotus-shed/math.go new file mode 100644 index 000000000..434559f09 --- /dev/null +++ b/cmd/lotus-shed/math.go @@ -0,0 +1,103 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "os" + "strings" + + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/chain/types" +) + +var mathCmd = &cli.Command{ + Name: "math", + Usage: "utility commands around doing math on a list of numbers", + Subcommands: []*cli.Command{ + mathSumCmd, + }, +} + +func readLargeNumbers(i io.Reader) ([]types.BigInt, error) { + list := []types.BigInt{} + reader := bufio.NewReader(i) + + exit := false + for { + if exit { + break + } + + line, err := reader.ReadString('\n') + if err != nil && err != io.EOF { + break + } + if err == io.EOF { + exit = true + } + + line = strings.Trim(line, "\n") + + if len(line) == 0 { + continue + } + + value, err := types.BigFromString(line) + if err != nil { + return []types.BigInt{}, fmt.Errorf("failed to parse line: %s", line) + } + + list = append(list, value) + } + + return list, nil +} + +var mathSumCmd = &cli.Command{ + Name: "sum", + Usage: "Sum numbers", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "avg", + Value: false, + Usage: "Print the average instead of the sum", + }, + &cli.StringFlag{ + Name: "format", + Value: "raw", + Usage: "format the number in a more readable way [fil,bytes2,bytes10]", + }, + }, + Action: func(cctx *cli.Context) error { + list, err := readLargeNumbers(os.Stdin) + if err != nil { + return err + } + + val := types.NewInt(0) + for _, value := range list { + val = types.BigAdd(val, value) + } + + if cctx.Bool("avg") { + val = types.BigDiv(val, types.NewInt(uint64(len(list)))) + } + + switch cctx.String("format") { + case "byte2": + fmt.Printf("%s\n", types.SizeStr(val)) + case "byte10": + fmt.Printf("%s\n", types.DeciStr(val)) + case "fil": + fmt.Printf("%s\n", types.FIL(val)) + case "raw": + fmt.Printf("%s\n", val) + default: + return fmt.Errorf("Unknown format") + } + + return nil + }, +} From bf3466f3cb87c4b96dd1c7cf140a745bf55d7e3b Mon Sep 17 00:00:00 2001 From: Travis Person Date: Sat, 5 Sep 2020 02:34:08 +0000 Subject: [PATCH 012/199] lotus-pcr: use current tipset during refund Using the tipset which is being processed might lead to incorrect gas estimations or balance checking for the wallet. --- cmd/lotus-pcr/main.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmd/lotus-pcr/main.go b/cmd/lotus-pcr/main.go index 613e746dc..a5242bf28 100644 --- a/cmd/lotus-pcr/main.go +++ b/cmd/lotus-pcr/main.go @@ -225,7 +225,12 @@ var runCmd = &cli.Command{ continue } - if err := rf.Refund(ctx, tipset, refunds, rounds); err != nil { + refundTipset, err := api.ChainHead(ctx) + if err != nil { + return err + } + + if err := rf.Refund(ctx, refundTipset, refunds, rounds); err != nil { return err } From 16fd12024e8b13aa5854698911af882074e39d5c Mon Sep 17 00:00:00 2001 From: shepf Date: Sat, 5 Sep 2020 10:40:53 +0800 Subject: [PATCH 013/199] Batch replacement,update lotus-storage-miner to lotus-miner. --- documentation/en/.glossary.json | 2 +- documentation/en/dev/create-miner.md | 10 +++++----- documentation/en/install-systemd-services.md | 2 +- documentation/en/mining-troubleshooting.md | 2 +- scripts/dev/sminer-init | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/documentation/en/.glossary.json b/documentation/en/.glossary.json index 79d96664a..e8a9e0846 100644 --- a/documentation/en/.glossary.json +++ b/documentation/en/.glossary.json @@ -95,7 +95,7 @@ "title": "Miner (Block Producer)", "value": "The Block Producer Miner's logic. It currently shares an interface and process with the Lotus Node. A Block Producer chooses which messages to include in a block and is rewarded according to each message’s gas price and consumption, forming a market." }, - "lotus-storage-miner": { + "lotus-miner": { "title": "Miner (lotus-miner)", "value": "The Miner's logic. It has its own dedicated process. Contributes to the network through Sector commitments and Proofs of Spacetime to prove that it is storing the sectors it has commited to." }, diff --git a/documentation/en/dev/create-miner.md b/documentation/en/dev/create-miner.md index 9a1cf2d4e..7b3b81765 100644 --- a/documentation/en/dev/create-miner.md +++ b/documentation/en/dev/create-miner.md @@ -43,9 +43,9 @@ FIXME: Is there an easy way to visualize the message generated by the Faucet? ## Storage miner node -The `lotus-storage-miner` command provides a set of tools to manage the miners associated with the local storage miner node. At this point it is important to note the different [node types](https://github.com/filecoin-project/lotus/blob/master/node/repo/fsrepo.go), in the previous document we always referred to a *single* local node, `FullNode`, which handled the sync process and any other communication with the Filecoin network (the term *full* stands for full validation of the consensus protocol, there are no *light* clients at the moment that do not do the full validation). We now create a new node of type [`StorageMiner`](https://github.com/filecoin-project/lotus/blob/master/node/repo/fsrepo.go), with its own repo (each node is always associated to its own repo), by default in `~/.lotusstorage`. The difference between the two nodes lies in the services they run (see build options in the main architecture document). +The `lotus-miner` command provides a set of tools to manage the miners associated with the local storage miner node. At this point it is important to note the different [node types](https://github.com/filecoin-project/lotus/blob/master/node/repo/fsrepo.go), in the previous document we always referred to a *single* local node, `FullNode`, which handled the sync process and any other communication with the Filecoin network (the term *full* stands for full validation of the consensus protocol, there are no *light* clients at the moment that do not do the full validation). We now create a new node of type [`StorageMiner`](https://github.com/filecoin-project/lotus/blob/master/node/repo/fsrepo.go), with its own repo (each node is always associated to its own repo), by default in `~/.lotusstorage`. The difference between the two nodes lies in the services they run (see build options in the main architecture document). -The `lotus-storage-miner init` command option creates a new storage miner node. We will only be able to run the command once the chain has been synced by the full node (which needs to be running) and it will also require the download of the [proof parameters](https://filecoin.io/blog/filecoin-proof-system/) (of several GBs, so it may take some time). +The `lotus-miner init` command option creates a new storage miner node. We will only be able to run the command once the chain has been synced by the full node (which needs to be running) and it will also require the download of the [proof parameters](https://filecoin.io/blog/filecoin-proof-system/) (of several GBs, so it may take some time). The main options that define a miner are the owner and worker addresses associated to it (stored in [`MinerInfo`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/miner/miner_state.go), a substructure of the Miner Actor State) and its peer ID. We use default values for all of these options in the command and briefly described them here: @@ -55,7 +55,7 @@ The main options that define a miner are the owner and worker addresses associat * [Peer ID](https://docs.libp2p.io/reference/glossary/#peerid): a network ID (belonging to the `libp2p` stack) used to contact the miner directly off-chain (e.g., to make a storage deal). Note the difference with the rest of the communication in the Filecoin network that happens largely inside the chain itself: when we "send" messages to the different actors that is actually a VM abstraction meaning we execute the method in the VM itself run by logic of the targeted actor, physically (at the network TCP/IP level) we broadcast the message to all of our peers to be included in a Filecoin block. -With the miner information filled the command constructs a Filecoin message to broadcast to the network and be included in a Filecoin block by a miner (see [`createStorageMiner()`](https://github.com/filecoin-project/lotus/blob/master/cmd/lotus-storage-miner/init.go)). We will wait for that block to be synced to the chain (by the full node) before returning the miner ID address. The ID address is another way to refer to the miner through a unique ID in the chain, it has a type 0 and it is the address that is normally seen in chain visualization tools, e.g., `t01475` (since, in contrast with the public-key types of addresses, it is easily readable by humans). +With the miner information filled the command constructs a Filecoin message to broadcast to the network and be included in a Filecoin block by a miner (see [`createStorageMiner()`](https://github.com/filecoin-project/lotus/blob/master/cmd/lotus-miner/init.go)). We will wait for that block to be synced to the chain (by the full node) before returning the miner ID address. The ID address is another way to refer to the miner through a unique ID in the chain, it has a type 0 and it is the address that is normally seen in chain visualization tools, e.g., `t01475` (since, in contrast with the public-key types of addresses, it is easily readable by humans). The Filecoin message constructed will be targeted to the [Power Actor](https://filecoin-project.github.io/specs/#systems__filecoin_blockchain__storage_power_consensus__storage_power_actor) (`StoragePowerActorAddr`), which tracks the amount of power (storage capacity) every miner has, and it will have the method number of the [`CreateMiner`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/methods.go) constant. @@ -69,13 +69,13 @@ Back to the CLI command, the [`MpoolPushMessage`](https://github.com/filecoin-pr ## VM: message execution -We describe here the code flow inside the VM when it executes the `CreateMiner` method (of the message sent by the `lotus-storage-miner` command included by a miner in a block). This execution will be the same seen by all participants in the Filecoin protocol, the miner including the message in the block, the full node syncing to it, and any other peer receiving also this message. +We describe here the code flow inside the VM when it executes the `CreateMiner` method (of the message sent by the `lotus-miner` command included by a miner in a block). This execution will be the same seen by all participants in the Filecoin protocol, the miner including the message in the block, the full node syncing to it, and any other peer receiving also this message. There is a one-to-one mapping between the pair of actor and method number (`To:`/`Method:` fields) in a message in the VM, and the Go function in an actor's exported methods list that implement it. In this case, for the Power Actor list of method numbers defined in [`MethodsPower`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/methods.go), the `CreateMiner` method number 2 will correspond to the Go function with the same index in the list of methods returned by [`Exports()`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/power/power_actor.go) (and normally also the same name, here `(Actor).CreateMiner()`). The Power Actor in `CreateMiner()` will do two things: -1. Send *another* message, `Exec`, to the Init Actor to instruct it to create the miner actor with the information provided by `lotus-storage-miner` and receive its ID address (this ID is the one returned to the CLI command). +1. Send *another* message, `Exec`, to the Init Actor to instruct it to create the miner actor with the information provided by `lotus-miner` and receive its ID address (this ID is the one returned to the CLI command). 2. Generate an entry in its list of power claims ([`State.Claims`](https://github.com/filecoin-project/specs-actors/blob/master/actors/builtin/power/power_state.go)) for the newly created ID address of the miner. diff --git a/documentation/en/install-systemd-services.md b/documentation/en/install-systemd-services.md index fbde1feec..3ce52acdf 100644 --- a/documentation/en/install-systemd-services.md +++ b/documentation/en/install-systemd-services.md @@ -8,7 +8,7 @@ The services expect their binaries to be present in `/usr/local/bin/`. You can u $ sudo make install ``` -for `lotus` and `lotus-storage-miner` and +for `lotus` and `lotus-miner` and ```sh $ sudo make install-chainwatch diff --git a/documentation/en/mining-troubleshooting.md b/documentation/en/mining-troubleshooting.md index 5aaf9f6ef..d2cc036a7 100644 --- a/documentation/en/mining-troubleshooting.md +++ b/documentation/en/mining-troubleshooting.md @@ -22,7 +22,7 @@ This bug occurs when the miner can't acquire the `bellman.lock`. To fix it you n ```sh lotus-miner info -# WARN main lotus-storage-miner/main.go:73 failed to get api endpoint: (/Users/myrmidon/.lotusminer) %!w(*errors.errorString=&{API not running (no endpoint)}): +# WARN main lotus-miner/main.go:73 failed to get api endpoint: (/Users/myrmidon/.lotusminer) %!w(*errors.errorString=&{API not running (no endpoint)}): ``` If you see this, that means your **Lotus Miner** isn't ready yet. You need to finish [syncing the chain](https://lotu.sh/en+join-testnet). diff --git a/scripts/dev/sminer-init b/scripts/dev/sminer-init index 2f4a3f7af..767921511 100755 --- a/scripts/dev/sminer-init +++ b/scripts/dev/sminer-init @@ -7,4 +7,4 @@ export TRUST_PARAMS=1 tag=${TAG:-debug} go run -tags=$tag ./cmd/lotus wallet import ~/.genesis-sectors/pre-seal-t01000.key -go run -tags=$tag ./cmd/lotus-storage-miner init --actor=t01000 --genesis-miner --pre-sealed-sectors=~/.genesis-sectors --pre-sealed-metadata=~/.genesis-sectors/pre-seal-t01000.json +go run -tags=$tag ./cmd/lotus-miner init --actor=t01000 --genesis-miner --pre-sealed-sectors=~/.genesis-sectors --pre-sealed-metadata=~/.genesis-sectors/pre-seal-t01000.json From 2adb80729b16d06a9bf4f5912b3c0a7650a60838 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Sat, 5 Sep 2020 15:17:55 +0200 Subject: [PATCH 014/199] Add additional info about gas premium Signed-off-by: Jakub Sztandera --- node/impl/full/mpool.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/node/impl/full/mpool.go b/node/impl/full/mpool.go index bfb7439bb..6acb17990 100644 --- a/node/impl/full/mpool.go +++ b/node/impl/full/mpool.go @@ -2,6 +2,7 @@ package full import ( "context" + "encoding/json" "github.com/filecoin-project/go-address" "github.com/ipfs/go-cid" @@ -113,6 +114,7 @@ func (a *MpoolAPI) MpoolPush(ctx context.Context, smsg *types.SignedMessage) (ci } func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spec *api.MessageSendSpec) (*types.SignedMessage, error) { + inMsg := *msg { fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msg.From, nil) if err != nil { @@ -134,6 +136,13 @@ func (a *MpoolAPI) MpoolPushMessage(ctx context.Context, msg *types.Message, spe return nil, xerrors.Errorf("GasEstimateMessageGas error: %w", err) } + if msg.GasPremium.GreaterThan(msg.GasFeeCap) { + inJson, _ := json.Marshal(inMsg) + outJson, _ := json.Marshal(msg) + return nil, xerrors.Errorf("After estimation, GasPremium is greater than GasFeeCap, inmsg: %s, outmsg: %s", + inJson, outJson) + } + sign := func(from address.Address, nonce uint64) (*types.SignedMessage, error) { msg.Nonce = nonce if msg.From.Protocol() == address.ID { From 0b3685e5299c24b6e5112bcb181b6de0ad63250a Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 5 Sep 2020 21:30:02 +0300 Subject: [PATCH 015/199] fix selection bug; priority messages were not included if other's chains were negative --- chain/messagepool/selection.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 5ba679d76..df1d7b801 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -102,7 +102,7 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 if len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf) - return nil, nil + return result, nil } // 3. Parition chains into blocks (without trimming) @@ -351,7 +351,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S if len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf) - return nil, nil + return result, nil } // 3. Merge the head chains to produce the list of messages selected for inclusion, subject to From 5037282b984c0eef90f59852f01f17262244a8e0 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 5 Sep 2020 22:15:18 +0300 Subject: [PATCH 016/199] add test for priority selection with negative chains --- chain/messagepool/messagepool_test.go | 5 +- chain/messagepool/selection_test.go | 94 +++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 484c72746..c97c03166 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -34,6 +34,8 @@ type testMpoolAPI struct { tipsets []*types.TipSet published int + + baseFee types.BigInt } func newTestMpoolAPI() *testMpoolAPI { @@ -41,6 +43,7 @@ func newTestMpoolAPI() *testMpoolAPI { bmsgs: make(map[cid.Cid][]*types.SignedMessage), statenonce: make(map[address.Address]uint64), balance: make(map[address.Address]types.BigInt), + baseFee: types.NewInt(100), } genesis := mock.MkBlock(nil, 1, 1) tma.tipsets = append(tma.tipsets, mock.TipSet(genesis)) @@ -182,7 +185,7 @@ func (tma *testMpoolAPI) LoadTipSet(tsk types.TipSetKey) (*types.TipSet, error) } func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) { - return types.NewInt(100), nil + return tma.baseFee, nil } func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) { diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index a9ead3c01..d9ed3af9c 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -728,6 +728,100 @@ func TestPriorityMessageSelection2(t *testing.T) { } } +func TestPriorityMessageSelection3(t *testing.T) { + mp, tma := makeTestMpool() + + // the actors + w1, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a1, err := w1.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + w2, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a2, err := w2.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + block := tma.nextBlock() + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin.StorageMarketActorCodeID, M: 2}] + + tma.setBalance(a1, 1) // in FIL + tma.setBalance(a2, 1) // in FIL + + mp.cfg.PriorityAddrs = []address.Address{a1} + + tma.baseFee = types.NewInt(1000) + nMessages := 10 + for i := 0; i < nMessages; i++ { + bias := (nMessages - i) / 3 + m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(1000+i%3+bias)) + mustAdd(t, mp, m) + // messages from a2 have negative performance + m = makeTestMessage(w2, a2, a1, uint64(i), gasLimit, 100) + mustAdd(t, mp, m) + } + + // test greedy selection + msgs, err := mp.SelectMessages(ts, 1.0) + if err != nil { + t.Fatal(err) + } + + expectedMsgs := 10 + if len(msgs) != expectedMsgs { + t.Fatalf("expected %d messages but got %d", expectedMsgs, len(msgs)) + } + + // all messages must be from a1 + nextNonce := uint64(0) + for _, m := range msgs { + if m.Message.From != a1 { + t.Fatal("expected messages from a1 before messages from a2") + } + if m.Message.Nonce != nextNonce { + t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce) + } + nextNonce++ + } + + // test optimal selection + msgs, err = mp.SelectMessages(ts, 0.1) + if err != nil { + t.Fatal(err) + } + + expectedMsgs = 10 + if len(msgs) != expectedMsgs { + t.Fatalf("expected %d messages but got %d", expectedMsgs, len(msgs)) + } + + // all messages must be from a1 + nextNonce = uint64(0) + for _, m := range msgs { + if m.Message.From != a1 { + t.Fatal("expected messages from a1 before messages from a2") + } + if m.Message.Nonce != nextNonce { + t.Fatalf("expected nonce %d but got %d", nextNonce, m.Message.Nonce) + } + nextNonce++ + } + +} + func TestOptimalMessageSelection1(t *testing.T) { // this test uses just a single actor sending messages with a low tq // the chain depenent merging algorithm should pick messages from the actor From 4718efab9b993808d72a283211cb21d1823d021e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Sat, 5 Sep 2020 21:51:30 +0200 Subject: [PATCH 017/199] docsgen --- documentation/en/api-methods.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index bba212d45..dd5c13815 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -98,6 +98,7 @@ * [Paych](#Paych) * [PaychAllocateLane](#PaychAllocateLane) * [PaychAvailableFunds](#PaychAvailableFunds) + * [PaychAvailableFundsByFromTo](#PaychAvailableFundsByFromTo) * [PaychCollect](#PaychCollect) * [PaychGet](#PaychGet) * [PaychGetWaitReady](#PaychGetWaitReady) @@ -2239,6 +2240,27 @@ There are not yet any comments for this method. Perms: sign +Inputs: `null` + +Response: +```json +{ + "Channel": "\u003cempty\u003e", + "From": "t01234", + "To": "t01234", + "ConfirmedAmt": "0", + "PendingAmt": "0", + "PendingWaitSentinel": null, + "QueuedAmt": "0", + "VoucherReedeemedAmt": "0" +} +``` + +### PaychAvailableFundsByFromTo +There are not yet any comments for this method. + +Perms: sign + Inputs: ```json [ @@ -2250,6 +2272,8 @@ Response: ```json { "Channel": "\u003cempty\u003e", + "From": "t01234", + "To": "t01234", "ConfirmedAmt": "0", "PendingAmt": "0", "PendingWaitSentinel": null, From aaad01105e7fca6fb9e9fa7804887d5ec9343d46 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sat, 5 Sep 2020 20:29:26 -0400 Subject: [PATCH 018/199] Msig: Introduce an API & CLI to calculate amount that vests between 2 tipsets --- api/api_full.go | 3 ++ api/apistruct/struct.go | 5 ++++ cli/multisig.go | 63 +++++++++++++++++++++++++++++++++++++++++ node/impl/full/state.go | 42 +++++++++++++++++++++++++++ 4 files changed, 113 insertions(+) diff --git a/api/api_full.go b/api/api_full.go index 8ae857dfd..fb1810ad9 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -384,6 +384,9 @@ type FullNode interface { // MsigGetAvailableBalance returns the portion of a multisig's balance that can be withdrawn or spent MsigGetAvailableBalance(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) + // MsigGetVested returns the amount of FIL that vested in a multisig in a certain period. + // It takes the following params: , , + MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) // MsigCreate creates a multisig wallet // It takes the following params: , , //, , diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index e2444f16b..de0ddd31b 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -197,6 +197,7 @@ type FullNodeStruct struct { StateCirculatingSupply func(context.Context, types.TipSetKey) (api.CirculatingSupply, error) `perm:"read"` MsigGetAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"` + MsigGetVested func(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) `perm:"read"` MsigCreate func(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) `perm:"sign"` MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"` MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"` @@ -866,6 +867,10 @@ func (c *FullNodeStruct) MsigGetAvailableBalance(ctx context.Context, a address. return c.Internal.MsigGetAvailableBalance(ctx, a, tsk) } +func (c *FullNodeStruct) MsigGetVested(ctx context.Context, a address.Address, sTsk types.TipSetKey, eTsk types.TipSetKey) (types.BigInt, error) { + return c.Internal.MsigGetVested(ctx, a, sTsk, eTsk) +} + func (c *FullNodeStruct) MsigCreate(ctx context.Context, req uint64, addrs []address.Address, duration abi.ChainEpoch, val types.BigInt, src address.Address, gp types.BigInt) (cid.Cid, error) { return c.Internal.MsigCreate(ctx, req, addrs, duration, val, src, gp) } diff --git a/cli/multisig.go b/cli/multisig.go index 57f6c2c03..70780fd29 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -40,6 +40,7 @@ var multisigCmd = &cli.Command{ msigSwapProposeCmd, msigSwapApproveCmd, msigSwapCancelCmd, + msigVestedCmd, }, } @@ -736,3 +737,65 @@ var msigSwapCancelCmd = &cli.Command{ return nil }, } + +var msigVestedCmd = &cli.Command{ + Name: "vested", + Usage: "Gets the amount vested in an msig between two epochs", + ArgsUsage: "[multisigAddress]", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "start-epoch", + Usage: "start epoch to measure vesting from", + Value: 0, + }, + &cli.Int64Flag{ + Name: "end-epoch", + Usage: "end epoch to stop measure vesting at", + Value: -1, + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 1 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address")) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + msig, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + start, err := api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int64("start-epoch")), types.EmptyTSK) + if err != nil { + return err + } + + var end *types.TipSet + if cctx.Int64("end-epoch") < 0 { + end, err = LoadTipSet(ctx, cctx, api) + if err != nil { + return err + } + } else { + end, err = api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Int64("end-epoch")), types.EmptyTSK) + if err != nil { + return err + } + } + + ret, err := api.MsigGetVested(ctx, msig, start.Key(), end.Key()) + if err != nil { + return err + } + + fmt.Printf("Vested: %s between %d and %d\n", types.FIL(ret), start.Height(), end.Height()) + + return nil + }, +} diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 36721a93d..f2b0df0ec 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -886,6 +886,48 @@ func (a *StateAPI) MsigGetAvailableBalance(ctx context.Context, addr address.Add return types.BigSub(act.Balance, minBalance), nil } +func (a *StateAPI) MsigGetVested(ctx context.Context, addr address.Address, start types.TipSetKey, end types.TipSetKey) (types.BigInt, error) { + startTs, err := a.Chain.GetTipSetFromKey(start) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading start tipset %s: %w", start, err) + } + + endTs, err := a.Chain.GetTipSetFromKey(end) + if err != nil { + return types.EmptyInt, xerrors.Errorf("loading end tipset %s: %w", end, err) + } + + if startTs.Height() > endTs.Height() { + return types.EmptyInt, xerrors.Errorf("start tipset %d is after end tipset %d", startTs.Height(), endTs.Height()) + } else if startTs.Height() == endTs.Height() { + return big.Zero(), nil + } + + var mst samsig.State + act, err := a.StateManager.LoadActorState(ctx, addr, &mst, endTs) + if err != nil { + return types.EmptyInt, xerrors.Errorf("failed to load multisig actor state at end epoch: %w", err) + } + + if act.Code != builtin.MultisigActorCodeID { + return types.EmptyInt, fmt.Errorf("given actor was not a multisig") + } + + if mst.UnlockDuration == 0 || + mst.InitialBalance.IsZero() || + mst.StartEpoch+mst.UnlockDuration <= startTs.Height() || + mst.StartEpoch >= endTs.Height() { + return big.Zero(), nil + } + + startLk := mst.InitialBalance + if startTs.Height() > mst.StartEpoch { + startLk = mst.AmountLocked(startTs.Height() - mst.StartEpoch) + } + + return big.Sub(startLk, mst.AmountLocked(endTs.Height()-mst.StartEpoch)), nil +} + var initialPledgeNum = types.NewInt(110) var initialPledgeDen = types.NewInt(100) From d0ccb54aba947c690045ec79406af901022d3a0c Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sun, 6 Sep 2020 01:52:30 -0400 Subject: [PATCH 019/199] Msig: Add RPC endpoints to propose, approve, or cancel adding signers --- api/api_full.go | 18 +++++++++++++++--- api/apistruct/struct.go | 15 +++++++++++++++ node/impl/full/multisig.go | 39 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index fb1810ad9..6ff5b0709 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -403,17 +403,29 @@ type FullNode interface { // It takes the following params: , , , , // , , MsigCancel(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) + // MsigAddPropose proposes adding a signer in the multisig + // It takes the following params: , , + // , + MsigAddPropose(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error) + // MsigAddApprove approves a previously proposed AddSigner message + // It takes the following params: , , , + // , , + MsigAddApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) + // MsigAddCancel cancels a previously proposed AddSigner message + // It takes the following params: , , , + // , + MsigAddCancel(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error) // MsigSwapPropose proposes swapping 2 signers in the multisig // It takes the following params: , , - // + // , MsigSwapPropose(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) // MsigSwapApprove approves a previously proposed SwapSigner // It takes the following params: , , , - // , + // , , MsigSwapApprove(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) // MsigSwapCancel cancels a previously proposed SwapSigner message // It takes the following params: , , , - // + // , MsigSwapCancel(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) MarketEnsureAvailable(context.Context, address.Address, address.Address, types.BigInt) (cid.Cid, error) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index de0ddd31b..2325ae93a 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -202,6 +202,9 @@ type FullNodeStruct struct { MsigPropose func(context.Context, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"` MsigApprove func(context.Context, address.Address, uint64, address.Address, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"` MsigCancel func(context.Context, address.Address, uint64, address.Address, types.BigInt, address.Address, uint64, []byte) (cid.Cid, error) `perm:"sign"` + MsigAddPropose func(context.Context, address.Address, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"` + MsigAddApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, bool) (cid.Cid, error) `perm:"sign"` + MsigAddCancel func(context.Context, address.Address, address.Address, uint64, address.Address, bool) (cid.Cid, error) `perm:"sign"` MsigSwapPropose func(context.Context, address.Address, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"` MsigSwapApprove func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address, address.Address) (cid.Cid, error) `perm:"sign"` MsigSwapCancel func(context.Context, address.Address, address.Address, uint64, address.Address, address.Address) (cid.Cid, error) `perm:"sign"` @@ -887,6 +890,18 @@ func (c *FullNodeStruct) MsigCancel(ctx context.Context, msig address.Address, t return c.Internal.MsigCancel(ctx, msig, txID, to, amt, src, method, params) } +func (c *FullNodeStruct) MsigAddPropose(ctx context.Context, msig address.Address, src address.Address, newAdd address.Address, inc bool) (cid.Cid, error) { + return c.Internal.MsigAddPropose(ctx, msig, src, newAdd, inc) +} + +func (c *FullNodeStruct) MsigAddApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, newAdd address.Address, inc bool) (cid.Cid, error) { + return c.Internal.MsigAddApprove(ctx, msig, src, txID, proposer, newAdd, inc) +} + +func (c *FullNodeStruct) MsigAddCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, newAdd address.Address, inc bool) (cid.Cid, error) { + return c.Internal.MsigAddCancel(ctx, msig, src, txID, newAdd, inc) +} + func (c *FullNodeStruct) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) { return c.Internal.MsigSwapPropose(ctx, msig, src, oldAdd, newAdd) } diff --git a/node/impl/full/multisig.go b/node/impl/full/multisig.go index f1e3c61fd..9f412aa07 100644 --- a/node/impl/full/multisig.go +++ b/node/impl/full/multisig.go @@ -130,6 +130,33 @@ func (a *MsigAPI) MsigPropose(ctx context.Context, msig address.Address, to addr return smsg.Cid(), nil } +func (a *MsigAPI) MsigAddPropose(ctx context.Context, msig address.Address, src address.Address, newAdd address.Address, inc bool) (cid.Cid, error) { + enc, actErr := serializeAddParams(newAdd, inc) + if actErr != nil { + return cid.Undef, actErr + } + + return a.MsigPropose(ctx, msig, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.AddSigner), enc) +} + +func (a *MsigAPI) MsigAddApprove(ctx context.Context, msig address.Address, src address.Address, txID uint64, proposer address.Address, newAdd address.Address, inc bool) (cid.Cid, error) { + enc, actErr := serializeAddParams(newAdd, inc) + if actErr != nil { + return cid.Undef, actErr + } + + return a.MsigApprove(ctx, msig, txID, proposer, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.AddSigner), enc) +} + +func (a *MsigAPI) MsigAddCancel(ctx context.Context, msig address.Address, src address.Address, txID uint64, newAdd address.Address, inc bool) (cid.Cid, error) { + enc, actErr := serializeAddParams(newAdd, inc) + if actErr != nil { + return cid.Undef, actErr + } + + return a.MsigCancel(ctx, msig, txID, msig, big.Zero(), src, uint64(builtin.MethodsMultisig.AddSigner), enc) +} + func (a *MsigAPI) MsigSwapPropose(ctx context.Context, msig address.Address, src address.Address, oldAdd address.Address, newAdd address.Address) (cid.Cid, error) { enc, actErr := serializeSwapParams(oldAdd, newAdd) if actErr != nil { @@ -244,6 +271,18 @@ func (a *MsigAPI) msigApproveOrCancel(ctx context.Context, operation api.MsigPro return smsg.Cid(), nil } +func serializeAddParams(new address.Address, inc bool) ([]byte, error) { + enc, actErr := actors.SerializeParams(&samsig.AddSignerParams{ + Signer: new, + Increase: inc, + }) + if actErr != nil { + return nil, actErr + } + + return enc, nil +} + func serializeSwapParams(old address.Address, new address.Address) ([]byte, error) { enc, actErr := actors.SerializeParams(&samsig.SwapSignerParams{ From: old, From 5ead23a8d46d94ee32b9949d916d656f4ed89ff0 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sun, 6 Sep 2020 02:10:33 -0400 Subject: [PATCH 020/199] Msig: Add CLI commands to propose, approve, or cancel adding signers --- cli/multisig.go | 237 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 235 insertions(+), 2 deletions(-) diff --git a/cli/multisig.go b/cli/multisig.go index 70780fd29..ff6abf4f7 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -37,6 +37,9 @@ var multisigCmd = &cli.Command{ msigInspectCmd, msigProposeCmd, msigApproveCmd, + msigAddProposeCmd, + msigAddApproveCmd, + msigAddCancelCmd, msigSwapProposeCmd, msigSwapApproveCmd, msigSwapCancelCmd, @@ -507,6 +510,236 @@ var msigApproveCmd = &cli.Command{ }, } +var msigAddProposeCmd = &cli.Command{ + Name: "add-propose", + Usage: "Propose to add a signer", + ArgsUsage: "[multisigAddress signer]", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "increase-threshold", + Usage: "whether the number of required signers should be increased", + }, + &cli.StringFlag{ + Name: "from", + Usage: "account to send the propose message from", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 2 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address and signer address")) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + msig, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + addr, err := address.NewFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + var from address.Address + if cctx.IsSet("from") { + f, err := address.NewFromString(cctx.String("from")) + if err != nil { + return err + } + from = f + } else { + defaddr, err := api.WalletDefaultAddress(ctx) + if err != nil { + return err + } + from = defaddr + } + + msgCid, err := api.MsigAddPropose(ctx, msig, from, addr, cctx.Bool("increase-threshold")) + if err != nil { + return err + } + + fmt.Println("sent add proposal in message: ", msgCid) + + wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) + if err != nil { + return err + } + + if wait.Receipt.ExitCode != 0 { + return fmt.Errorf("add proposal returned exit %d", wait.Receipt.ExitCode) + } + + return nil + }, +} + +var msigAddApproveCmd = &cli.Command{ + Name: "add-approve", + Usage: "Approve a message to add a signer", + ArgsUsage: "[multisigAddress proposerAddress txId newAddress increaseThreshold]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "account to send the approve message from", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 5 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address, proposer address, transaction id, new signer address, whether to increase threshold")) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + msig, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + prop, err := address.NewFromString(cctx.Args().Get(1)) + if err != nil { + return err + } + + txid, err := strconv.ParseUint(cctx.Args().Get(2), 10, 64) + if err != nil { + return err + } + + newAdd, err := address.NewFromString(cctx.Args().Get(3)) + if err != nil { + return err + } + + inc, err := strconv.ParseBool(cctx.Args().Get(4)) + if err != nil { + return err + } + + var from address.Address + if cctx.IsSet("from") { + f, err := address.NewFromString(cctx.String("from")) + if err != nil { + return err + } + from = f + } else { + defaddr, err := api.WalletDefaultAddress(ctx) + if err != nil { + return err + } + from = defaddr + } + + msgCid, err := api.MsigAddApprove(ctx, msig, from, txid, prop, newAdd, inc) + if err != nil { + return err + } + + fmt.Println("sent add approval in message: ", msgCid) + + wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) + if err != nil { + return err + } + + if wait.Receipt.ExitCode != 0 { + return fmt.Errorf("add approval returned exit %d", wait.Receipt.ExitCode) + } + + return nil + }, +} + +var msigAddCancelCmd = &cli.Command{ + Name: "add-cancel", + Usage: "Cancel a message to add a signer", + ArgsUsage: "[multisigAddress txId newAddress increaseThreshold]", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "account to send the approve message from", + }, + }, + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 4 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address, transaction id, new signer address, whether to increase threshold")) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + msig, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + txid, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64) + if err != nil { + return err + } + + newAdd, err := address.NewFromString(cctx.Args().Get(2)) + if err != nil { + return err + } + + inc, err := strconv.ParseBool(cctx.Args().Get(3)) + if err != nil { + return err + } + + var from address.Address + if cctx.IsSet("from") { + f, err := address.NewFromString(cctx.String("from")) + if err != nil { + return err + } + from = f + } else { + defaddr, err := api.WalletDefaultAddress(ctx) + if err != nil { + return err + } + from = defaddr + } + + msgCid, err := api.MsigAddCancel(ctx, msig, from, txid, newAdd, inc) + if err != nil { + return err + } + + fmt.Println("sent add cancellation in message: ", msgCid) + + wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) + if err != nil { + return err + } + + if wait.Receipt.ExitCode != 0 { + return fmt.Errorf("add cancellation returned exit %d", wait.Receipt.ExitCode) + } + + return nil + }, +} + var msigSwapProposeCmd = &cli.Command{ Name: "swap-propose", Usage: "Propose to swap signers", @@ -723,7 +956,7 @@ var msigSwapCancelCmd = &cli.Command{ return err } - fmt.Println("sent swap approval in message: ", msgCid) + fmt.Println("sent swap cancellation in message: ", msgCid) wait, err := api.StateWaitMsg(ctx, msgCid, build.MessageConfidence) if err != nil { @@ -731,7 +964,7 @@ var msigSwapCancelCmd = &cli.Command{ } if wait.Receipt.ExitCode != 0 { - return fmt.Errorf("swap approval returned exit %d", wait.Receipt.ExitCode) + return fmt.Errorf("swap cancellation returned exit %d", wait.Receipt.ExitCode) } return nil From 88c04ce959356d4e3a381ab3c4cb9727bee6d820 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sun, 6 Sep 2020 03:51:06 -0400 Subject: [PATCH 021/199] Update docs --- documentation/en/api-methods.md | 120 +++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index dd5c13815..a4906660c 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -74,10 +74,14 @@ * [MpoolSetConfig](#MpoolSetConfig) * [MpoolSub](#MpoolSub) * [Msig](#Msig) + * [MsigAddApprove](#MsigAddApprove) + * [MsigAddCancel](#MsigAddCancel) + * [MsigAddPropose](#MsigAddPropose) * [MsigApprove](#MsigApprove) * [MsigCancel](#MsigCancel) * [MsigCreate](#MsigCreate) * [MsigGetAvailableBalance](#MsigGetAvailableBalance) + * [MsigGetVested](#MsigGetVested) * [MsigPropose](#MsigPropose) * [MsigSwapApprove](#MsigSwapApprove) * [MsigSwapCancel](#MsigSwapCancel) @@ -1820,6 +1824,84 @@ The Msig methods are used to interact with multisig wallets on the filecoin network +### MsigAddApprove +MsigAddApprove approves a previously proposed AddSigner message +It takes the following params: , , , +, , + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + 42, + "t01234", + "t01234", + true +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigAddCancel +MsigAddCancel cancels a previously proposed AddSigner message +It takes the following params: , , , +, + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + 42, + "t01234", + true +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + +### MsigAddPropose +MsigAddPropose proposes adding a signer in the multisig +It takes the following params: , , +, + + +Perms: sign + +Inputs: +```json +[ + "t01234", + "t01234", + "t01234", + true +] +``` + +Response: +```json +{ + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" +} +``` + ### MsigApprove MsigApprove approves a previously-proposed multisig message It takes the following params: , , , , , @@ -1927,6 +2009,38 @@ Inputs: Response: `"0"` +### MsigGetVested +MsigGetVested returns the amount of FIL that vested in a multisig in a certain period. +It takes the following params: , , + + +Perms: read + +Inputs: +```json +[ + "t01234", + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ], + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `"0"` + ### MsigPropose MsigPropose proposes a multisig message It takes the following params: , , , @@ -1957,7 +2071,7 @@ Response: ### MsigSwapApprove MsigSwapApprove approves a previously proposed SwapSigner It takes the following params: , , , -, +, , Perms: sign @@ -1984,7 +2098,7 @@ Response: ### MsigSwapCancel MsigSwapCancel cancels a previously proposed SwapSigner message It takes the following params: , , , - +, Perms: sign @@ -2010,7 +2124,7 @@ Response: ### MsigSwapPropose MsigSwapPropose proposes swapping 2 signers in the multisig It takes the following params: , , - +, Perms: sign From 1c0e6d76f0da61aaf955dd5824af55c9d910a152 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 5 Sep 2020 20:09:46 +0300 Subject: [PATCH 022/199] add defensive check for minimum GasFeeCap for inclusion within the next 20 blocks --- chain/messagepool/messagepool.go | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index b20bc8b91..68924480b 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -11,7 +11,6 @@ import ( "sync" "time" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" @@ -49,6 +48,7 @@ const RbfDenom = 256 var RepublishInterval = pubsub.TimeCacheDuration + time.Duration(5*build.BlockDelaySecs+build.PropagationDelaySecs)*time.Second var minimumBaseFee = types.NewInt(uint64(build.MinimumBaseFee)) +var baseFeeLowerBoundFactor = types.NewInt(10) var MaxActorPendingMessages = 1000 @@ -355,12 +355,30 @@ func (mp *MessagePool) addLocal(m *types.SignedMessage, msgb []byte) error { return nil } -func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, epoch abi.ChainEpoch) error { +func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet) error { + epoch := curTs.Height() minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength()) if err := m.VMMessage().ValidForBlockInclusion(minGas.Total()); err != nil { return xerrors.Errorf("message will not be included in a block: %w", err) } + + // this checks if the GasFeeCap is suffisciently high for inclusion in the next 20 blocks + // if the GasFeeCap is too low, we soft reject the message (Ignore in pubsub) and rely + // on republish to push it through later, if the baseFee has fallen. + // this is a defensive check that stops minimum baseFee spam attacks from overloading validation + // queues. + baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), curTs) + if err != nil { + return xerrors.Errorf("error computing base fee: %w", err) + } + + baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) + if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { + return xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w", + m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure) + } + return nil } @@ -523,7 +541,7 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error mp.lk.Lock() defer mp.lk.Unlock() - if err := mp.verifyMsgBeforeAdd(m, curTs.Height()); err != nil { + if err := mp.verifyMsgBeforeAdd(m, curTs); err != nil { return err } @@ -557,7 +575,7 @@ func (mp *MessagePool) addLoaded(m *types.SignedMessage) error { mp.lk.Lock() defer mp.lk.Unlock() - if err := mp.verifyMsgBeforeAdd(m, curTs.Height()); err != nil { + if err := mp.verifyMsgBeforeAdd(m, curTs); err != nil { return err } @@ -743,7 +761,7 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address, return nil, ErrTryAgain } - if err := mp.verifyMsgBeforeAdd(msg, curTs.Height()); err != nil { + if err := mp.verifyMsgBeforeAdd(msg, curTs); err != nil { return nil, err } From f9492691a6ef91519709f3f792c687fe933f399a Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 5 Sep 2020 20:31:16 +0300 Subject: [PATCH 023/199] don't check baseFee lower bound for local messages --- chain/messagepool/messagepool.go | 34 ++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 68924480b..173c72e8e 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -355,7 +355,7 @@ func (mp *MessagePool) addLocal(m *types.SignedMessage, msgb []byte) error { return nil } -func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet) error { +func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) error { epoch := curTs.Height() minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength()) @@ -368,15 +368,19 @@ func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.T // on republish to push it through later, if the baseFee has fallen. // this is a defensive check that stops minimum baseFee spam attacks from overloading validation // queues. - baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), curTs) - if err != nil { - return xerrors.Errorf("error computing base fee: %w", err) - } + // Note that we don't do that for local messages, so that they can be accepted and republished + // automatically + if !local { + baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), curTs) + if err != nil { + return xerrors.Errorf("error computing base fee: %w", err) + } - baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) - if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { - return xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w", - m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure) + baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) + if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { + return xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w", + m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure) + } } return nil @@ -400,7 +404,7 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) { } mp.curTsLk.Lock() - if err := mp.addTs(m, mp.curTs); err != nil { + if err := mp.addTs(m, mp.curTs, true); err != nil { mp.curTsLk.Unlock() return cid.Undef, err } @@ -461,7 +465,7 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error { mp.curTsLk.Lock() defer mp.curTsLk.Unlock() - return mp.addTs(m, mp.curTs) + return mp.addTs(m, mp.curTs, false) } func sigCacheKey(m *types.SignedMessage) (string, error) { @@ -528,7 +532,7 @@ func (mp *MessagePool) checkBalance(m *types.SignedMessage, curTs *types.TipSet) return nil } -func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error { +func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local bool) error { snonce, err := mp.getStateNonce(m.Message.From, curTs) if err != nil { return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure) @@ -541,7 +545,7 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet) error mp.lk.Lock() defer mp.lk.Unlock() - if err := mp.verifyMsgBeforeAdd(m, curTs); err != nil { + if err := mp.verifyMsgBeforeAdd(m, curTs, local); err != nil { return err } @@ -575,7 +579,7 @@ func (mp *MessagePool) addLoaded(m *types.SignedMessage) error { mp.lk.Lock() defer mp.lk.Unlock() - if err := mp.verifyMsgBeforeAdd(m, curTs); err != nil { + if err := mp.verifyMsgBeforeAdd(m, curTs, true); err != nil { return err } @@ -761,7 +765,7 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address, return nil, ErrTryAgain } - if err := mp.verifyMsgBeforeAdd(msg, curTs); err != nil { + if err := mp.verifyMsgBeforeAdd(msg, curTs, true); err != nil { return nil, err } From ffb2640736b338f1359ee18afb58c51cd0bcec84 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 5 Sep 2020 21:03:22 +0300 Subject: [PATCH 024/199] use faster lookup for base fee --- chain/messagepool/messagepool.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 173c72e8e..0d62e5423 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -370,12 +370,8 @@ func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.T // queues. // Note that we don't do that for local messages, so that they can be accepted and republished // automatically - if !local { - baseFee, err := mp.api.ChainComputeBaseFee(context.TODO(), curTs) - if err != nil { - return xerrors.Errorf("error computing base fee: %w", err) - } - + if !local && len(curTs.Blocks()) > 0 { + baseFee := curTs.Blocks()[0].ParentBaseFee baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { return xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w", From e24a29b1460f9a11a11cb4ba5c24b4cf58eab194 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 5 Sep 2020 21:26:21 +0300 Subject: [PATCH 025/199] fix tests that touch the mpool; mock block must have a ParentBaseFee --- chain/types/mock/chain.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/chain/types/mock/chain.go b/chain/types/mock/chain.go index 33b13d408..b535f203a 100644 --- a/chain/types/mock/chain.go +++ b/chain/types/mock/chain.go @@ -9,6 +9,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/ipfs/go-cid" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" ) @@ -80,6 +81,7 @@ func MkBlock(parents *types.TipSet, weightInc uint64, ticketNonce uint64) *types Height: height, ParentStateRoot: pstateRoot, BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS, Data: []byte("boo! im a signature")}, + ParentBaseFee: types.NewInt(uint64(build.MinimumBaseFee)), } } From f7b52d16f5836f405ad42aadfa838daac4c336f6 Mon Sep 17 00:00:00 2001 From: Travis Person Date: Sun, 6 Sep 2020 04:32:05 +0000 Subject: [PATCH 026/199] metrics: add expected height metric --- chain/sync.go | 26 ++++++++++++++++++++++++++ metrics/metrics.go | 6 ++++++ 2 files changed, 32 insertions(+) diff --git a/chain/sync.go b/chain/sync.go index 1b1cbdde9..cc29e3550 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -125,6 +125,8 @@ type Syncer struct { verifier ffiwrapper.Verifier windowSize int + + tickerCtxCancel context.CancelFunc } // NewSyncer creates a new Syncer object. @@ -166,11 +168,35 @@ func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connm } func (syncer *Syncer) Start() { + tickerCtx, tickerCtxCancel := context.WithCancel(context.Background()) syncer.syncmgr.Start() + + syncer.tickerCtxCancel = tickerCtxCancel + + go syncer.runMetricsTricker(tickerCtx) +} + +func (syncer *Syncer) runMetricsTricker(tickerCtx context.Context) { + genesisTime := time.Unix(int64(syncer.Genesis.MinTimestamp()), 0) + ticker := build.Clock.Ticker(time.Duration(build.BlockDelaySecs) * time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + sinceGenesis := build.Clock.Now().Sub(genesisTime) + expectedHeight := int64(sinceGenesis.Seconds()) / int64(build.BlockDelaySecs) + + stats.Record(tickerCtx, metrics.ChainNodeHeightExpected.M(int64(expectedHeight))) + case <-tickerCtx.Done(): + return + } + } } func (syncer *Syncer) Stop() { syncer.syncmgr.Stop() + syncer.tickerCtxCancel() } // InformNewHead informs the syncer about a new potential tipset diff --git a/metrics/metrics.go b/metrics/metrics.go index a6732e8ea..5dd865263 100644 --- a/metrics/metrics.go +++ b/metrics/metrics.go @@ -30,6 +30,7 @@ var ( var ( LotusInfo = stats.Int64("info", "Arbitrary counter to tag lotus info to", stats.UnitDimensionless) ChainNodeHeight = stats.Int64("chain/node_height", "Current Height of the node", stats.UnitDimensionless) + ChainNodeHeightExpected = stats.Int64("chain/node_height_expected", "Expected Height of the node", stats.UnitDimensionless) ChainNodeWorkerHeight = stats.Int64("chain/node_worker_height", "Current Height of workers on the node", stats.UnitDimensionless) MessagePublished = stats.Int64("message/published", "Counter for total locally published messages", stats.UnitDimensionless) MessageReceived = stats.Int64("message/received", "Counter for total received messages", stats.UnitDimensionless) @@ -62,6 +63,10 @@ var ( Measure: ChainNodeHeight, Aggregation: view.LastValue(), } + ChainNodeHeightExpectedView = &view.View{ + Measure: ChainNodeHeightExpected, + Aggregation: view.LastValue(), + } ChainNodeWorkerHeightView = &view.View{ Measure: ChainNodeWorkerHeight, Aggregation: view.LastValue(), @@ -138,6 +143,7 @@ var ( var DefaultViews = append([]*view.View{ InfoView, ChainNodeHeightView, + ChainNodeHeightExpectedView, ChainNodeWorkerHeightView, BlockReceivedView, BlockValidationFailureView, From 798061506eda85b20d2b0deb46e5879e193a9058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 7 Sep 2020 11:34:36 +0100 Subject: [PATCH 027/199] decommission chain validation. --- chain/validation/applier.go | 215 -------------------------------- chain/validation/config.go | 37 ------ chain/validation/factories.go | 40 ------ chain/validation/keymanager.go | 104 ---------------- chain/validation/state.go | 217 --------------------------------- chain/vm/validation_test.go | 71 ----------- go.mod | 1 - 7 files changed, 685 deletions(-) delete mode 100644 chain/validation/applier.go delete mode 100644 chain/validation/config.go delete mode 100644 chain/validation/factories.go delete mode 100644 chain/validation/keymanager.go delete mode 100644 chain/validation/state.go delete mode 100644 chain/vm/validation_test.go diff --git a/chain/validation/applier.go b/chain/validation/applier.go deleted file mode 100644 index ac2fccf85..000000000 --- a/chain/validation/applier.go +++ /dev/null @@ -1,215 +0,0 @@ -package validation - -import ( - "context" - - "golang.org/x/xerrors" - - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/puppet" - "github.com/ipfs/go-cid" - - vtypes "github.com/filecoin-project/chain-validation/chain/types" - vstate "github.com/filecoin-project/chain-validation/state" - - "github.com/filecoin-project/lotus/chain/stmgr" - "github.com/filecoin-project/lotus/chain/store" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/vm" -) - -// Applier applies messages to state trees and storage. -type Applier struct { - stateWrapper *StateWrapper - syscalls vm.SyscallBuilder -} - -var _ vstate.Applier = &Applier{} - -func NewApplier(sw *StateWrapper, syscalls vm.SyscallBuilder) *Applier { - return &Applier{sw, syscalls} -} - -func (a *Applier) ApplyMessage(epoch abi.ChainEpoch, message *vtypes.Message) (vtypes.ApplyMessageResult, error) { - lm := toLotusMsg(message) - receipt, penalty, reward, err := a.applyMessage(epoch, lm) - return vtypes.ApplyMessageResult{ - Msg: *message, - Receipt: receipt, - Penalty: penalty, - Reward: reward, - Root: a.stateWrapper.Root().String(), - }, err -} - -func (a *Applier) ApplySignedMessage(epoch abi.ChainEpoch, msg *vtypes.SignedMessage) (vtypes.ApplyMessageResult, error) { - var lm types.ChainMsg - switch msg.Signature.Type { - case crypto.SigTypeSecp256k1: - lm = toLotusSignedMsg(msg) - case crypto.SigTypeBLS: - lm = toLotusMsg(&msg.Message) - default: - return vtypes.ApplyMessageResult{}, xerrors.New("Unknown signature type") - } - // TODO: Validate the sig first - receipt, penalty, reward, err := a.applyMessage(epoch, lm) - return vtypes.ApplyMessageResult{ - Msg: msg.Message, - Receipt: receipt, - Penalty: penalty, - Reward: reward, - Root: a.stateWrapper.Root().String(), - }, err - -} - -func (a *Applier) ApplyTipSetMessages(epoch abi.ChainEpoch, blocks []vtypes.BlockMessagesInfo, rnd vstate.RandomnessSource) (vtypes.ApplyTipSetResult, error) { - cs := store.NewChainStore(a.stateWrapper.bs, a.stateWrapper.ds, a.syscalls) - sm := stmgr.NewStateManager(cs) - - var bms []store.BlockMessages - for _, b := range blocks { - bm := store.BlockMessages{ - Miner: b.Miner, - WinCount: 1, - } - - for _, m := range b.BLSMessages { - bm.BlsMessages = append(bm.BlsMessages, toLotusMsg(m)) - } - - for _, m := range b.SECPMessages { - bm.SecpkMessages = append(bm.SecpkMessages, toLotusSignedMsg(m)) - } - - bms = append(bms, bm) - } - - 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 { - if msg.From == builtin.SystemActorAddr { - return nil // ignore reward and cron calls - } - rval := ret.Return - if rval == nil { - rval = []byte{} // chain validation tests expect empty arrays to not be nil... - } - receipts = append(receipts, vtypes.MessageReceipt{ - ExitCode: ret.ExitCode, - ReturnValue: rval, - - GasUsed: vtypes.GasUnits(ret.GasUsed), - }) - return nil - }, abi.NewTokenAmount(100)) - if err != nil { - return vtypes.ApplyTipSetResult{}, err - } - - a.stateWrapper.stateRoot = sroot - - return vtypes.ApplyTipSetResult{ - Receipts: receipts, - Root: a.stateWrapper.Root().String(), - }, nil -} - -type randWrapper struct { - rand vstate.RandomnessSource -} - -// TODO: these should really be two different randomness sources -func (w *randWrapper) GetChainRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return w.rand.Randomness(ctx, pers, round, entropy) -} - -func (w *randWrapper) GetBeaconRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) { - return w.rand.Randomness(ctx, pers, round, entropy) -} - -type vmRand struct { -} - -func (*vmRand) GetChainRandomness(ctx context.Context, dst crypto.DomainSeparationTag, h abi.ChainEpoch, input []byte) ([]byte, error) { - panic("implement me") -} - -func (*vmRand) GetBeaconRandomness(ctx context.Context, dst crypto.DomainSeparationTag, h abi.ChainEpoch, input []byte) ([]byte, error) { - panic("implement me") -} - -func (a *Applier) applyMessage(epoch abi.ChainEpoch, lm types.ChainMsg) (vtypes.MessageReceipt, abi.TokenAmount, abi.TokenAmount, error) { - ctx := context.TODO() - base := a.stateWrapper.Root() - - vmopt := &vm.VMOpts{ - StateBase: base, - Epoch: epoch, - Rand: &vmRand{}, - Bstore: a.stateWrapper.bs, - Syscalls: a.syscalls, - CircSupplyCalc: nil, - BaseFee: abi.NewTokenAmount(100), - } - - lotusVM, err := vm.NewVM(vmopt) - // need to modify the VM invoker to add the puppet actor - chainValInvoker := vm.NewInvoker() - chainValInvoker.Register(puppet.PuppetActorCodeID, puppet.Actor{}, puppet.State{}) - lotusVM.SetInvoker(chainValInvoker) - if err != nil { - return vtypes.MessageReceipt{}, big.Zero(), big.Zero(), err - } - - ret, err := lotusVM.ApplyMessage(ctx, lm) - if err != nil { - return vtypes.MessageReceipt{}, big.Zero(), big.Zero(), err - } - - rval := ret.Return - if rval == nil { - rval = []byte{} - } - - a.stateWrapper.stateRoot, err = lotusVM.Flush(ctx) - if err != nil { - return vtypes.MessageReceipt{}, big.Zero(), big.Zero(), err - } - - mr := vtypes.MessageReceipt{ - ExitCode: ret.ExitCode, - ReturnValue: rval, - GasUsed: vtypes.GasUnits(ret.GasUsed), - } - - return mr, ret.Penalty, abi.NewTokenAmount(ret.GasUsed), nil -} - -func toLotusMsg(msg *vtypes.Message) *types.Message { - return &types.Message{ - To: msg.To, - From: msg.From, - - Nonce: msg.CallSeqNum, - Method: msg.Method, - - Value: msg.Value, - GasLimit: msg.GasLimit, - GasFeeCap: msg.GasFeeCap, - GasPremium: msg.GasPremium, - - Params: msg.Params, - } -} - -func toLotusSignedMsg(msg *vtypes.SignedMessage) *types.SignedMessage { - return &types.SignedMessage{ - Message: *toLotusMsg(&msg.Message), - Signature: msg.Signature, - } -} diff --git a/chain/validation/config.go b/chain/validation/config.go deleted file mode 100644 index 1e5936350..000000000 --- a/chain/validation/config.go +++ /dev/null @@ -1,37 +0,0 @@ -package validation - -// -// Config -// - -type Config struct { - trackGas bool - checkExitCode bool - checkReturnValue bool - checkState bool -} - -func NewConfig(gas, exit, ret, state bool) *Config { - return &Config{ - trackGas: gas, - checkExitCode: exit, - checkReturnValue: ret, - checkState: state, - } -} - -func (v Config) ValidateGas() bool { - return v.trackGas -} - -func (v Config) ValidateExitCode() bool { - return v.checkExitCode -} - -func (v Config) ValidateReturnValue() bool { - return v.checkReturnValue -} - -func (v Config) ValidateStateRoot() bool { - return v.checkState -} diff --git a/chain/validation/factories.go b/chain/validation/factories.go deleted file mode 100644 index b7781cacc..000000000 --- a/chain/validation/factories.go +++ /dev/null @@ -1,40 +0,0 @@ -package validation - -import ( - "context" - - "github.com/filecoin-project/lotus/chain/state" - "github.com/filecoin-project/specs-actors/actors/runtime" - cbor "github.com/ipfs/go-ipld-cbor" - - vstate "github.com/filecoin-project/chain-validation/state" -) - -type Factories struct { - *Applier -} - -var _ vstate.Factories = &Factories{} - -func NewFactories() *Factories { - return &Factories{} -} - -func (f *Factories) NewStateAndApplier(syscalls runtime.Syscalls) (vstate.VMWrapper, vstate.Applier) { - st := NewState() - return st, NewApplier(st, func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls { - return syscalls - }) -} - -func (f *Factories) NewKeyManager() vstate.KeyManager { - return newKeyManager() -} - -func (f *Factories) NewValidationConfig() vstate.ValidationConfig { - trackGas := true - checkExit := true - checkRet := true - checkState := true - return NewConfig(trackGas, checkExit, checkRet, checkState) -} diff --git a/chain/validation/keymanager.go b/chain/validation/keymanager.go deleted file mode 100644 index e93f169bf..000000000 --- a/chain/validation/keymanager.go +++ /dev/null @@ -1,104 +0,0 @@ -package validation - -import ( - "fmt" - "math/rand" - - "github.com/minio/blake2b-simd" - - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-crypto" - acrypto "github.com/filecoin-project/specs-actors/actors/crypto" - - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/wallet" -) - -type KeyManager struct { - // Private keys by address - keys map[address.Address]*wallet.Key - - // Seed for deterministic secp key generation. - secpSeed int64 - // Seed for deterministic bls key generation. - blsSeed int64 // nolint: structcheck -} - -func newKeyManager() *KeyManager { - return &KeyManager{ - keys: make(map[address.Address]*wallet.Key), - secpSeed: 0, - } -} - -func (k *KeyManager) NewSECP256k1AccountAddress() address.Address { - secpKey := k.newSecp256k1Key() - k.keys[secpKey.Address] = secpKey - return secpKey.Address -} - -func (k *KeyManager) NewBLSAccountAddress() address.Address { - blsKey := k.newBLSKey() - k.keys[blsKey.Address] = blsKey - return blsKey.Address -} - -func (k *KeyManager) Sign(addr address.Address, data []byte) (acrypto.Signature, error) { - ki, ok := k.keys[addr] - if !ok { - return acrypto.Signature{}, fmt.Errorf("unknown address %v", addr) - } - var sigType acrypto.SigType - if ki.Type == wallet.KTSecp256k1 { - sigType = acrypto.SigTypeBLS - hashed := blake2b.Sum256(data) - sig, err := crypto.Sign(ki.PrivateKey, hashed[:]) - if err != nil { - return acrypto.Signature{}, err - } - - return acrypto.Signature{ - Type: sigType, - Data: sig, - }, nil - } else if ki.Type == wallet.KTBLS { - panic("lotus validator cannot sign BLS messages") - } else { - panic("unknown signature type") - } - -} - -func (k *KeyManager) newSecp256k1Key() *wallet.Key { - randSrc := rand.New(rand.NewSource(k.secpSeed)) // nolint - prv, err := crypto.GenerateKeyFromSeed(randSrc) - if err != nil { - panic(err) - } - k.secpSeed++ - key, err := wallet.NewKey(types.KeyInfo{ - Type: wallet.KTSecp256k1, - PrivateKey: prv, - }) - if err != nil { - panic(err) - } - return key -} - -func (k *KeyManager) newBLSKey() *wallet.Key { - // FIXME: bls needs deterministic key generation - //sk := ffi.PrivateKeyGenerate(s.blsSeed) - // s.blsSeed++ - sk := [32]byte{} - sk[0] = uint8(k.blsSeed) // hack to keep gas values determinist - k.blsSeed++ - key, err := wallet.NewKey(types.KeyInfo{ - Type: wallet.KTBLS, - PrivateKey: sk[:], - }) - if err != nil { - panic(err) - } - return key -} diff --git a/chain/validation/state.go b/chain/validation/state.go deleted file mode 100644 index 2a10eb6af..000000000 --- a/chain/validation/state.go +++ /dev/null @@ -1,217 +0,0 @@ -package validation - -import ( - "context" - - "github.com/ipfs/go-cid" - "github.com/ipfs/go-datastore" - cbor "github.com/ipfs/go-ipld-cbor" - "golang.org/x/xerrors" - - vstate "github.com/filecoin-project/chain-validation/state" - "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/runtime" - - "github.com/filecoin-project/lotus/chain/state" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/lib/blockstore" -) - -var _ vstate.VMWrapper = &StateWrapper{} - -type StateWrapper struct { - // The blockstore underlying the state tree and storage. - bs blockstore.Blockstore - - ds datastore.Batching - // HAMT-CBOR store on top of the blockstore. - cst cbor.IpldStore - - // CID of the root of the state tree. - stateRoot cid.Cid -} - -func NewState() *StateWrapper { - bs := blockstore.NewTemporary() - cst := cbor.NewCborStore(bs) - // Put EmptyObjectCid value in the store. When an actor is initially created its Head is set to this value. - _, err := cst.Put(context.TODO(), map[string]string{}) - if err != nil { - panic(err) - } - - treeImpl, err := state.NewStateTree(cst) - if err != nil { - panic(err) // Never returns error, the error return should be removed. - } - root, err := treeImpl.Flush(context.TODO()) - if err != nil { - panic(err) - } - return &StateWrapper{ - bs: bs, - ds: datastore.NewMapDatastore(), - cst: cst, - stateRoot: root, - } -} - -func (s *StateWrapper) NewVM() { - return -} - -func (s *StateWrapper) Root() cid.Cid { - return s.stateRoot -} - -// StoreGet the value at key from vm store -func (s *StateWrapper) StoreGet(key cid.Cid, out runtime.CBORUnmarshaler) error { - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return err - } - return tree.Store.Get(context.Background(), key, out) -} - -// StorePut `value` into vm store -func (s *StateWrapper) StorePut(value runtime.CBORMarshaler) (cid.Cid, error) { - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return cid.Undef, err - } - return tree.Store.Put(context.Background(), value) -} - -func (s *StateWrapper) Actor(addr address.Address) (vstate.Actor, error) { - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return nil, err - } - fcActor, err := tree.GetActor(addr) - if err != nil { - return nil, err - } - return &actorWrapper{*fcActor}, nil -} - -func (s *StateWrapper) SetActorState(addr address.Address, balance abi.TokenAmount, actorState runtime.CBORMarshaler) (vstate.Actor, error) { - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return nil, err - } - // actor should exist - act, err := tree.GetActor(addr) - if err != nil { - return nil, err - } - // add the state to the store and get a new head cid - actHead, err := tree.Store.Put(context.Background(), actorState) - if err != nil { - return nil, err - } - // update the actor object with new head and balance parameter - actr := &actorWrapper{types.Actor{ - Code: act.Code, - Nonce: act.Nonce, - // updates - Head: actHead, - Balance: balance, - }} - if err := tree.SetActor(addr, &actr.Actor); err != nil { - return nil, err - } - return actr, s.flush(tree) -} - -func (s *StateWrapper) CreateActor(code cid.Cid, addr address.Address, balance abi.TokenAmount, actorState runtime.CBORMarshaler) (vstate.Actor, address.Address, error) { - idAddr := addr - tree, err := state.LoadStateTree(s.cst, s.stateRoot) - if err != nil { - return nil, address.Undef, err - } - if addr.Protocol() != address.ID { - - actHead, err := tree.Store.Put(context.Background(), actorState) - if err != nil { - return nil, address.Undef, err - } - actr := &actorWrapper{types.Actor{ - Code: code, - Head: actHead, - Balance: balance, - }} - - idAddr, err = tree.RegisterNewAddress(addr) - if err != nil { - return nil, address.Undef, xerrors.Errorf("register new address for actor: %w", err) - } - - if err := tree.SetActor(addr, &actr.Actor); err != nil { - return nil, address.Undef, xerrors.Errorf("setting new actor for actor: %w", err) - } - } - - // store newState - head, err := tree.Store.Put(context.Background(), actorState) - if err != nil { - return nil, address.Undef, err - } - - // create and store actor object - a := types.Actor{ - Code: code, - Head: head, - Balance: balance, - } - if err := tree.SetActor(idAddr, &a); err != nil { - return nil, address.Undef, err - } - - return &actorWrapper{a}, idAddr, s.flush(tree) -} - -// Flushes a state tree to storage and sets this state's root to that tree's root CID. -func (s *StateWrapper) flush(tree *state.StateTree) (err error) { - s.stateRoot, err = tree.Flush(context.TODO()) - return -} - -// -// Actor Wrapper -// - -type actorWrapper struct { - types.Actor -} - -func (a *actorWrapper) Code() cid.Cid { - return a.Actor.Code -} - -func (a *actorWrapper) Head() cid.Cid { - return a.Actor.Head -} - -func (a *actorWrapper) CallSeqNum() uint64 { - return a.Actor.Nonce -} - -func (a *actorWrapper) Balance() big.Int { - return a.Actor.Balance - -} - -// -// Storage -// - -type contextStore struct { - cbor.IpldStore - ctx context.Context -} - -func (s *contextStore) Context() context.Context { - return s.ctx -} diff --git a/chain/vm/validation_test.go b/chain/vm/validation_test.go deleted file mode 100644 index 880b33401..000000000 --- a/chain/vm/validation_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package vm_test - -import ( - "fmt" - "reflect" - "runtime" - "strings" - "testing" - - suites "github.com/filecoin-project/chain-validation/suites" - - factory "github.com/filecoin-project/lotus/chain/validation" -) - -// TestSkipper contains a list of test cases skipped by the implementation. -type TestSkipper struct { - testSkips []suites.TestCase -} - -// Skip return true if the sutire.TestCase should be skipped. -func (ts *TestSkipper) Skip(test suites.TestCase) bool { - for _, skip := range ts.testSkips { - if reflect.ValueOf(skip).Pointer() == reflect.ValueOf(test).Pointer() { - fmt.Printf("=== SKIP %v\n", runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name()) - return true - } - } - return false -} - -// TestSuiteSkips contains tests we wish to skip. -var TestSuiteSkipper TestSkipper - -func init() { - // initialize the test skipper with tests being skipped - TestSuiteSkipper = TestSkipper{testSkips: []suites.TestCase{ - // tests to skip go here - }} -} - -func TestChainValidationMessageSuite(t *testing.T) { - f := factory.NewFactories() - for _, testCase := range suites.MessageTestCases() { - testCase := testCase - if TestSuiteSkipper.Skip(testCase) { - continue - } - t.Run(caseName(testCase), func(t *testing.T) { - testCase(t, f) - }) - } -} - -func TestChainValidationTipSetSuite(t *testing.T) { - f := factory.NewFactories() - for _, testCase := range suites.TipSetTestCases() { - testCase := testCase - if TestSuiteSkipper.Skip(testCase) { - continue - } - t.Run(caseName(testCase), func(t *testing.T) { - testCase(t, f) - }) - } -} - -func caseName(testCase suites.TestCase) string { - fqName := runtime.FuncForPC(reflect.ValueOf(testCase).Pointer()).Name() - toks := strings.Split(fqName, ".") - return toks[len(toks)-1] -} diff --git a/go.mod b/go.mod index 109f8110b..70fe0dea4 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,6 @@ require ( github.com/dustin/go-humanize v1.0.0 github.com/elastic/go-sysinfo v1.3.0 github.com/fatih/color v1.8.0 - github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d github.com/filecoin-project/go-address v0.0.3 github.com/filecoin-project/go-bitfield v0.2.0 From 7fdab46729855ca201ed3ac03f34e2349bccd8b3 Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 3 Sep 2020 15:31:22 +0300 Subject: [PATCH 028/199] update go-libp2p-pubsub@master --- go.mod | 2 +- go.sum | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 109f8110b..93576f1f0 100644 --- a/go.mod +++ b/go.mod @@ -91,7 +91,7 @@ require ( github.com/libp2p/go-libp2p-mplex v0.2.4 github.com/libp2p/go-libp2p-noise v0.1.1 github.com/libp2p/go-libp2p-peerstore v0.2.6 - github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200901174250-06a12f17b7de + github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb github.com/libp2p/go-libp2p-quic-transport v0.8.0 github.com/libp2p/go-libp2p-record v0.1.3 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 diff --git a/go.sum b/go.sum index 0c525579e..3d712940a 100644 --- a/go.sum +++ b/go.sum @@ -902,6 +902,14 @@ github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820194335-bfc96c2cd081/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200901174250-06a12f17b7de h1:Dl0B0x6u+OSKXAa1DeB6xHFsUOBAhjrXJ10zykVSN6Q= github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200901174250-06a12f17b7de/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200903122708-d895a89eb223 h1:tgwVd77HnrN8ze5pHVQ1eNHaetwe9V78FwYU9SCDk64= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200903122708-d895a89eb223/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200905112914-5fc61a58fc03 h1:gabZ3OnkgRE3kzbwDKOJOaQgI3oseD9dSnOMZLuNoys= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200905112914-5fc61a58fc03/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200905203513-0f42a472006f h1:jfItamsfw3cihUHCAlCo0u4U4aljJ33dxHklFOmoapg= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200905203513-0f42a472006f/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb h1:0jm9ZSDkteX9XRjZqZwG5X0wuR+e0zAJ6ZEnqo2vcb0= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= github.com/libp2p/go-libp2p-quic-transport v0.7.1/go.mod h1:TD31to4E5exogR/GWHClXCfkktigjAl5rXSt7HoxNvY= From 453ab95e54fab37beea3ced7cab28f6038eb00be Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 3 Sep 2020 15:33:29 +0300 Subject: [PATCH 029/199] enable pubsub RED --- node/modules/lp2p/pubsub.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index 19cd67906..c44d3dab8 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -277,6 +277,9 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { options = append(options, pubsub.WithDirectPeers(directPeerInfo)) } + // validation queue RED + options = append(options, pubsub.WithPeerGater(pubsub.DefaultPeerGaterParams())) + // tracer if in.Cfg.RemoteTracer != "" { a, err := ma.NewMultiaddr(in.Cfg.RemoteTracer) From c616958557d13168be436efb2b96b6c5168c6d43 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sat, 5 Sep 2020 23:46:49 +0300 Subject: [PATCH 030/199] specify topic delivery weights, with priority for blocks --- node/modules/lp2p/pubsub.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index c44d3dab8..d81133f81 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -278,7 +278,12 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { } // validation queue RED - options = append(options, pubsub.WithPeerGater(pubsub.DefaultPeerGaterParams())) + options = append(options, pubsub.WithPeerGater( + pubsub.DefaultPeerGaterParams().WithTopicDeliveryWeights(map[string]float64{ + drandTopic: 5, + build.BlocksTopic(in.Nn): 10, + build.MessagesTopic(in.Nn): 1, + }))) // tracer if in.Cfg.RemoteTracer != "" { From 219c8b927d023cf165bb275f092abd4326dcbc14 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 13:41:49 +0300 Subject: [PATCH 031/199] go mod tidy --- go.sum | 7 ------- 1 file changed, 7 deletions(-) diff --git a/go.sum b/go.sum index 3d712940a..c94136ce2 100644 --- a/go.sum +++ b/go.sum @@ -900,14 +900,7 @@ github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEX github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820194335-bfc96c2cd081/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200901174250-06a12f17b7de h1:Dl0B0x6u+OSKXAa1DeB6xHFsUOBAhjrXJ10zykVSN6Q= github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200901174250-06a12f17b7de/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200903122708-d895a89eb223 h1:tgwVd77HnrN8ze5pHVQ1eNHaetwe9V78FwYU9SCDk64= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200903122708-d895a89eb223/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200905112914-5fc61a58fc03 h1:gabZ3OnkgRE3kzbwDKOJOaQgI3oseD9dSnOMZLuNoys= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200905112914-5fc61a58fc03/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200905203513-0f42a472006f h1:jfItamsfw3cihUHCAlCo0u4U4aljJ33dxHklFOmoapg= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200905203513-0f42a472006f/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb h1:0jm9ZSDkteX9XRjZqZwG5X0wuR+e0zAJ6ZEnqo2vcb0= github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= From 9d9d2a2a9876143dcfb09b2c6723cb02408a0465 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Mon, 7 Sep 2020 12:29:40 +0100 Subject: [PATCH 032/199] fix: second argument error message Second argument should be a pointer, not runtime. --- chain/vm/invoker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index eaac395ea..5b299cfef 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -116,7 +116,7 @@ func (*Invoker) transform(instance Invokee) (nativeCode, error) { return nil, newErr("first arguemnt should be vmr.Runtime") } if t.In(1).Kind() != reflect.Ptr { - return nil, newErr("second argument should be Runtime") + return nil, newErr("second argument should be of kind reflect.Ptr") } if t.NumOut() != 1 { From 76a1b3286bddb0c0cc27e6b8a4091cdea3b03fbc Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 7 Sep 2020 14:43:06 +0200 Subject: [PATCH 033/199] fix: if cache best is nil, return chain head --- chain/events/events.go | 3 +- chain/events/events_called.go | 5 ++- chain/events/events_height.go | 14 ++++++- chain/events/events_test.go | 17 +++++++-- chain/events/tscache.go | 21 ++++++---- chain/events/tscache_test.go | 72 ++++++++++++++++++++++++++++------- 6 files changed, 105 insertions(+), 27 deletions(-) diff --git a/chain/events/events.go b/chain/events/events.go index 4550fc98a..ba5899270 100644 --- a/chain/events/events.go +++ b/chain/events/events.go @@ -35,6 +35,7 @@ type eventAPI interface { ChainNotify(context.Context) (<-chan []*api.HeadChange, error) ChainGetBlockMessages(context.Context, cid.Cid) (*api.BlockMessages, error) ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) + ChainHead(context.Context) (*types.TipSet, error) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) ChainGetTipSet(context.Context, types.TipSetKey) (*types.TipSet, error) @@ -57,7 +58,7 @@ type Events struct { func NewEvents(ctx context.Context, api eventAPI) *Events { gcConfidence := 2 * build.ForkLengthThreshold - tsc := newTSCache(gcConfidence, api.ChainGetTipSetByHeight) + tsc := newTSCache(gcConfidence, api) e := &Events{ api: api, diff --git a/chain/events/events_called.go b/chain/events/events_called.go index 196034a9a..2f813a1d4 100644 --- a/chain/events/events_called.go +++ b/chain/events/events_called.go @@ -307,7 +307,10 @@ func (e *hcEvents) onHeadChanged(check CheckFunc, hnd EventHandler, rev RevertHa defer e.lk.Unlock() // Check if the event has already occurred - ts := e.tsc.best() + ts, err := e.tsc.best() + if err != nil { + return 0, xerrors.Errorf("error getting best tipset: %w", err) + } done, more, err := check(ts) if err != nil { return 0, xerrors.Errorf("called check error (h: %d): %w", ts.Height(), err) diff --git a/chain/events/events_height.go b/chain/events/events_height.go index 24d758a31..8317c4da4 100644 --- a/chain/events/events_height.go +++ b/chain/events/events_height.go @@ -4,6 +4,8 @@ import ( "context" "sync" + "golang.org/x/xerrors" + "github.com/filecoin-project/specs-actors/actors/abi" "go.opencensus.io/trace" @@ -152,8 +154,12 @@ func (e *heightEvents) ChainAt(hnd HeightHandler, rev RevertHandler, confidence e.lk.Lock() // Tricky locking, check your locks if you modify this function! - bestH := e.tsc.best().Height() + best, err := e.tsc.best() + if err != nil { + return xerrors.Errorf("error getting best tipset: %w", err) + } + bestH := best.Height() if bestH >= h+abi.ChainEpoch(confidence) { ts, err := e.tsc.getNonNull(h) if err != nil { @@ -172,7 +178,11 @@ func (e *heightEvents) ChainAt(hnd HeightHandler, rev RevertHandler, confidence } e.lk.Lock() - bestH = e.tsc.best().Height() + best, err = e.tsc.best() + if err != nil { + return xerrors.Errorf("error getting best tipset: %w", err) + } + bestH = best.Height() } defer e.lk.Unlock() diff --git a/chain/events/events_test.go b/chain/events/events_test.go index 1204e3938..58cb855e2 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -46,6 +46,10 @@ type fakeCS struct { sub func(rev, app []*types.TipSet) } +func (fcs *fakeCS) ChainHead(ctx context.Context) (*types.TipSet, error) { + panic("implement me") +} + func (fcs *fakeCS) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) { return fcs.tipsets[key], nil } @@ -110,7 +114,11 @@ func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msg func (fcs *fakeCS) ChainNotify(context.Context) (<-chan []*api.HeadChange, error) { out := make(chan []*api.HeadChange, 1) - out <- []*api.HeadChange{{Type: store.HCCurrent, Val: fcs.tsc.best()}} + best, err := fcs.tsc.best() + if err != nil { + return nil, err + } + out <- []*api.HeadChange{{Type: store.HCCurrent, Val: best}} fcs.sub = func(rev, app []*types.TipSet) { notif := make([]*api.HeadChange, len(rev)+len(app)) @@ -174,7 +182,8 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { / var revs []*types.TipSet for i := 0; i < rev; i++ { - ts := fcs.tsc.best() + ts, err := fcs.tsc.best() + require.NoError(fcs.t, err) if _, ok := nullm[int(ts.Height())]; !ok { revs = append(revs, ts) @@ -196,7 +205,9 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { / continue } - ts := fcs.makeTs(fcs.t, fcs.tsc.best().Key().Cids(), fcs.h, mc) + best, err := fcs.tsc.best() + require.NoError(fcs.t, err) + ts := fcs.makeTs(fcs.t, best.Key().Cids(), fcs.h, mc) require.NoError(fcs.t, fcs.tsc.add(ts)) if hasMsgs { diff --git a/chain/events/tscache.go b/chain/events/tscache.go index 3852c9930..20935976c 100644 --- a/chain/events/tscache.go +++ b/chain/events/tscache.go @@ -9,7 +9,10 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -type tsByHFunc func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) +type tsCacheAPI interface { + ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) + ChainHead(context.Context) (*types.TipSet, error) +} // tipSetCache implements a simple ring-buffer cache to keep track of recent // tipsets @@ -18,10 +21,10 @@ type tipSetCache struct { start int len int - storage tsByHFunc + storage tsCacheAPI } -func newTSCache(cap abi.ChainEpoch, storage tsByHFunc) *tipSetCache { +func newTSCache(cap abi.ChainEpoch, storage tsCacheAPI) *tipSetCache { return &tipSetCache{ cache: make([]*types.TipSet, cap), start: 0, @@ -94,7 +97,7 @@ func (tsc *tipSetCache) getNonNull(height abi.ChainEpoch) (*types.TipSet, error) func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) { if tsc.len == 0 { log.Warnf("tipSetCache.get: cache is empty, requesting from storage (h=%d)", height) - return tsc.storage(context.TODO(), height, types.EmptyTSK) + return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, types.EmptyTSK) } headH := tsc.cache[tsc.start].Height() @@ -114,14 +117,18 @@ func (tsc *tipSetCache) get(height abi.ChainEpoch) (*types.TipSet, error) { if height < tail.Height() { log.Warnf("tipSetCache.get: requested tipset not in cache, requesting from storage (h=%d; tail=%d)", height, tail.Height()) - return tsc.storage(context.TODO(), height, tail.Key()) + return tsc.storage.ChainGetTipSetByHeight(context.TODO(), height, tail.Key()) } return tsc.cache[normalModulo(tsc.start-int(headH-height), clen)], nil } -func (tsc *tipSetCache) best() *types.TipSet { - return tsc.cache[tsc.start] +func (tsc *tipSetCache) best() (*types.TipSet, error) { + best := tsc.cache[tsc.start] + if best == nil { + return tsc.storage.ChainHead(context.TODO()) + } + return best, nil } func normalModulo(n, m int) int { diff --git a/chain/events/tscache_test.go b/chain/events/tscache_test.go index 1278e58e9..201221e9f 100644 --- a/chain/events/tscache_test.go +++ b/chain/events/tscache_test.go @@ -13,10 +13,7 @@ import ( ) func TestTsCache(t *testing.T) { - tsc := newTSCache(50, func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) { - t.Fatal("storage call") - return &types.TipSet{}, nil - }) + tsc := newTSCache(50, &tsCacheAPIFailOnStorageCall{t: t}) h := abi.ChainEpoch(75) @@ -43,7 +40,12 @@ func TestTsCache(t *testing.T) { for i := 0; i < 9000; i++ { if i%90 > 60 { - if err := tsc.revert(tsc.best()); err != nil { + best, err := tsc.best() + if err != nil { + t.Fatal(err, "; i:", i) + return + } + if err := tsc.revert(best); err != nil { t.Fatal(err, "; i:", i) return } @@ -55,11 +57,21 @@ func TestTsCache(t *testing.T) { } +type tsCacheAPIFailOnStorageCall struct { + t *testing.T +} + +func (tc *tsCacheAPIFailOnStorageCall) ChainGetTipSetByHeight(ctx context.Context, epoch abi.ChainEpoch, key types.TipSetKey) (*types.TipSet, error) { + tc.t.Fatal("storage call") + return &types.TipSet{}, nil +} +func (tc *tsCacheAPIFailOnStorageCall) ChainHead(ctx context.Context) (*types.TipSet, error) { + tc.t.Fatal("storage call") + return &types.TipSet{}, nil +} + func TestTsCacheNulls(t *testing.T) { - tsc := newTSCache(50, func(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) { - t.Fatal("storage call") - return &types.TipSet{}, nil - }) + tsc := newTSCache(50, &tsCacheAPIFailOnStorageCall{t: t}) h := abi.ChainEpoch(75) @@ -91,7 +103,9 @@ func TestTsCacheNulls(t *testing.T) { add() add() - require.Equal(t, h-1, tsc.best().Height()) + best, err := tsc.best() + require.NoError(t, err) + require.Equal(t, h-1, best.Height()) ts, err := tsc.get(h - 1) require.NoError(t, err) @@ -109,9 +123,17 @@ func TestTsCacheNulls(t *testing.T) { require.NoError(t, err) require.Equal(t, h-8, ts.Height()) - require.NoError(t, tsc.revert(tsc.best())) - require.NoError(t, tsc.revert(tsc.best())) - require.Equal(t, h-8, tsc.best().Height()) + best, err = tsc.best() + require.NoError(t, err) + require.NoError(t, tsc.revert(best)) + + best, err = tsc.best() + require.NoError(t, err) + require.NoError(t, tsc.revert(best)) + + best, err = tsc.best() + require.NoError(t, err) + require.Equal(t, h-8, best.Height()) h += 50 add() @@ -120,3 +142,27 @@ func TestTsCacheNulls(t *testing.T) { require.NoError(t, err) require.Equal(t, h-1, ts.Height()) } + +type tsCacheAPIStorageCallCounter struct { + t *testing.T + chainGetTipSetByHeight int + chainHead int +} + +func (tc *tsCacheAPIStorageCallCounter) ChainGetTipSetByHeight(ctx context.Context, epoch abi.ChainEpoch, key types.TipSetKey) (*types.TipSet, error) { + tc.chainGetTipSetByHeight++ + return &types.TipSet{}, nil +} +func (tc *tsCacheAPIStorageCallCounter) ChainHead(ctx context.Context) (*types.TipSet, error) { + tc.chainHead++ + return &types.TipSet{}, nil +} + +func TestTsCacheEmpty(t *testing.T) { + // Calling best on an empty cache should just call out to the chain API + callCounter := &tsCacheAPIStorageCallCounter{t: t} + tsc := newTSCache(50, callCounter) + _, err := tsc.best() + require.NoError(t, err) + require.Equal(t, 1, callCounter.chainHead) +} From 666dc65b8e732bc4245e5014078d67d289c14272 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 09:53:42 +0300 Subject: [PATCH 034/199] only subscribed to pubsub topics once we are synced --- node/modules/services.go | 80 +++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/node/modules/services.go b/node/modules/services.go index fc7486abe..a90ef9ff9 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -1,6 +1,8 @@ package modules import ( + "time" + "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" eventbus "github.com/libp2p/go-eventbus" @@ -22,6 +24,7 @@ import ( "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/sub" + "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/peermgr" "github.com/filecoin-project/lotus/node/hello" "github.com/filecoin-project/lotus/node/modules/dtypes" @@ -73,14 +76,50 @@ func RunBlockSync(h host.Host, svc *blocksync.BlockSyncService) { h.SetStreamHandler(blocksync.BlockSyncProtocolID, svc.HandleStream) } +func waitForSync(stmgr *stmgr.StateManager, blocks int, subscribe func()) { + nearsync := uint64(blocks) * uint64(build.BlockDelaySecs) * uint64(time.Second) + + // early check, are we synced at start up? + ts := stmgr.ChainStore().GetHeaviestTipSet() + timestamp := ts.MinTimestamp() + now := uint64(build.Clock.Now().UnixNano()) + if timestamp > now-nearsync { + subscribe() + return + } + + // we are not synced, subscribe to head changes and wait for sync + subscribed := false + stmgr.ChainStore().SubscribeHeadChanges(func(rev, app []*types.TipSet) error { + if subscribed { + return nil + } + + if len(app) == 0 { + return nil + } + + latest := app[0].MinTimestamp() + for _, ts := range app[1:] { + timestamp := ts.MinTimestamp() + if timestamp > latest { + latest = timestamp + } + } + + now := uint64(build.Clock.Now().UnixNano()) + if latest > now-nearsync { + subscribe() + subscribed = true + } + + return nil + }) +} + func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName) { ctx := helpers.LifecycleCtx(mctx, lc) - blocksub, err := ps.Subscribe(build.BlocksTopic(nn)) //nolint - if err != nil { - panic(err) - } - v := sub.NewBlockValidator( h.ID(), chain, stmgr, func(p peer.ID) { @@ -92,24 +131,39 @@ func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.P panic(err) } - go sub.HandleIncomingBlocks(ctx, blocksub, s, bserv, h.ConnManager()) + // wait until we are synced within 10 blocks + waitForSync(stmgr, 10, func() { + log.Infof("subscribing to pubsub topic %s", build.BlocksTopic(nn)) + + blocksub, err := ps.Subscribe(build.BlocksTopic(nn)) //nolint + if err != nil { + panic(err) + } + + go sub.HandleIncomingBlocks(ctx, blocksub, s, bserv, h.ConnManager()) + }) } -func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, mpool *messagepool.MessagePool, h host.Host, nn dtypes.NetworkName) { +func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, stmgr *stmgr.StateManager, mpool *messagepool.MessagePool, h host.Host, nn dtypes.NetworkName) { ctx := helpers.LifecycleCtx(mctx, lc) - msgsub, err := ps.Subscribe(build.MessagesTopic(nn)) //nolint:staticcheck - if err != nil { - panic(err) - } - v := sub.NewMessageValidator(h.ID(), mpool) if err := ps.RegisterTopicValidator(build.MessagesTopic(nn), v.Validate); err != nil { panic(err) } - go sub.HandleIncomingMessages(ctx, mpool, msgsub) + // wait until we are synced within 1 block + waitForSync(stmgr, 1, func() { + log.Infof("subscribing to pubsub topic %s", build.MessagesTopic(nn)) + + msgsub, err := ps.Subscribe(build.MessagesTopic(nn)) //nolint + if err != nil { + panic(err) + } + + go sub.HandleIncomingMessages(ctx, mpool, msgsub) + }) } func NewLocalDiscovery(ds dtypes.MetadataDS) *discovery.Local { From 05740e0f64575736ac5c0c7a6de75c43684008ad Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 10:03:47 +0300 Subject: [PATCH 035/199] silence linter for unnecessary conversion --- node/modules/services.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/modules/services.go b/node/modules/services.go index a90ef9ff9..a98613932 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -77,7 +77,7 @@ func RunBlockSync(h host.Host, svc *blocksync.BlockSyncService) { } func waitForSync(stmgr *stmgr.StateManager, blocks int, subscribe func()) { - nearsync := uint64(blocks) * uint64(build.BlockDelaySecs) * uint64(time.Second) + nearsync := uint64(blocks) * uint64(build.BlockDelaySecs) * uint64(time.Second) //nolint // early check, are we synced at start up? ts := stmgr.ChainStore().GetHeaviestTipSet() From 4f0ab4f2266759d555d05e68dfd515458ae88fb8 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 13:17:48 +0300 Subject: [PATCH 036/199] remove notifee after subscribing --- chain/store/store.go | 31 ++++++++++++++++++++++++++++--- node/modules/services.go | 7 +------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/chain/store/store.go b/chain/store/store.go index 2ae7fab2c..4bfd20040 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -5,6 +5,7 @@ import ( "context" "encoding/binary" "encoding/json" + "errors" "io" "os" "strconv" @@ -51,6 +52,8 @@ var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation") var DefaultTipSetCacheSize = 8192 var DefaultMsgMetaCacheSize = 2048 +var ErrNotifieeDone = errors.New("notifee is done and should be removed") + func init() { if s := os.Getenv("LOTUS_CHAIN_TIPSET_CACHE"); s != "" { tscs, err := strconv.Atoi(s) @@ -358,11 +361,33 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo apply[i], apply[opp] = apply[opp], apply[i] } - for _, hcf := range notifees { - if err := hcf(revert, apply); err != nil { - log.Error("head change func errored (BAD): ", err) + var toremove map[int]struct{} + for i, hcf := range notifees { + err := hcf(revert, apply) + if err != nil { + if err == ErrNotifieeDone { + if toremove == nil { + toremove = make(map[int]struct{}) + } + toremove[i] = struct{}{} + } else { + log.Error("head change func errored (BAD): ", err) + } } } + + if len(toremove) > 0 { + newNotifees := make([]ReorgNotifee, 0, len(notifees)-len(toremove)) + for i, hcf := range notifees { + _, remove := toremove[i] + if remove { + continue + } + newNotifees = append(newNotifees, hcf) + } + notifees = newNotifees + } + case <-ctx.Done(): return } diff --git a/node/modules/services.go b/node/modules/services.go index a98613932..65e488d36 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -89,12 +89,7 @@ func waitForSync(stmgr *stmgr.StateManager, blocks int, subscribe func()) { } // we are not synced, subscribe to head changes and wait for sync - subscribed := false stmgr.ChainStore().SubscribeHeadChanges(func(rev, app []*types.TipSet) error { - if subscribed { - return nil - } - if len(app) == 0 { return nil } @@ -110,7 +105,7 @@ func waitForSync(stmgr *stmgr.StateManager, blocks int, subscribe func()) { now := uint64(build.Clock.Now().UnixNano()) if latest > now-nearsync { subscribe() - subscribed = true + return store.ErrNotifieeDone } return nil From d9faff19a5bfb6de48f876a6e1e2aaad94541977 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 15:52:45 +0300 Subject: [PATCH 037/199] fix tests --- chain/sync_test.go | 2 ++ cli/paych_test.go | 3 +++ node/modules/services.go | 31 +++++++++++++++++++++++++------ node/node_test.go | 3 +++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/chain/sync_test.go b/chain/sync_test.go index cf1385baa..d7cf7e555 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -46,6 +46,8 @@ func init() { } power.ConsensusMinerMinPower = big.NewInt(2048) verifreg.MinVerifiedDealSize = big.NewInt(256) + + modules.PubsubSubscribeImmediately = true } const source = 0 diff --git a/cli/paych_test.go b/cli/paych_test.go index 9b21d8070..279bfb996 100644 --- a/cli/paych_test.go +++ b/cli/paych_test.go @@ -29,6 +29,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules" "github.com/filecoin-project/lotus/api/test" "github.com/filecoin-project/lotus/chain/wallet" @@ -44,6 +45,8 @@ func init() { abi.RegisteredSealProof_StackedDrg2KiBV1: {}, } verifreg.MinVerifiedDealSize = big.NewInt(256) + + modules.PubsubSubscribeImmediately = true } // TestPaymentChannels does a basic test to exercise the payment channel CLI diff --git a/node/modules/services.go b/node/modules/services.go index 65e488d36..e3ec01503 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -31,6 +31,9 @@ import ( "github.com/filecoin-project/lotus/node/modules/helpers" ) +// for tests +var PubsubSubscribeImmediately = false + func RunHello(mctx helpers.MetricsCtx, lc fx.Lifecycle, h host.Host, svc *hello.Service) error { h.SetStreamHandler(hello.ProtocolID, svc.HandleStream) @@ -126,8 +129,7 @@ func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.P panic(err) } - // wait until we are synced within 10 blocks - waitForSync(stmgr, 10, func() { + subscribe := func() { log.Infof("subscribing to pubsub topic %s", build.BlocksTopic(nn)) blocksub, err := ps.Subscribe(build.BlocksTopic(nn)) //nolint @@ -136,7 +138,16 @@ func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.P } go sub.HandleIncomingBlocks(ctx, blocksub, s, bserv, h.ConnManager()) - }) + } + + // for tests + if PubsubSubscribeImmediately { + subscribe() + return + } + + // wait until we are synced within 10 blocks + waitForSync(stmgr, 10, subscribe) } func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, stmgr *stmgr.StateManager, mpool *messagepool.MessagePool, h host.Host, nn dtypes.NetworkName) { @@ -148,8 +159,7 @@ func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub panic(err) } - // wait until we are synced within 1 block - waitForSync(stmgr, 1, func() { + subscribe := func() { log.Infof("subscribing to pubsub topic %s", build.MessagesTopic(nn)) msgsub, err := ps.Subscribe(build.MessagesTopic(nn)) //nolint @@ -158,7 +168,16 @@ func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub } go sub.HandleIncomingMessages(ctx, mpool, msgsub) - }) + } + + // for tests + if PubsubSubscribeImmediately { + subscribe() + return + } + + // wait until we are synced within 1 block + waitForSync(stmgr, 1, subscribe) } func NewLocalDiscovery(ds dtypes.MetadataDS) *discovery.Local { diff --git a/node/node_test.go b/node/node_test.go index 31a14bc20..219795f67 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -16,6 +16,7 @@ import ( logging "github.com/ipfs/go-log/v2" "github.com/filecoin-project/lotus/api/test" + "github.com/filecoin-project/lotus/node/modules" ) func init() { @@ -26,6 +27,8 @@ func init() { abi.RegisteredSealProof_StackedDrg2KiBV1: {}, } verifreg.MinVerifiedDealSize = big.NewInt(256) + + modules.PubsubSubscribeImmediately = true } func TestAPI(t *testing.T) { From e33798ff90ec69fc563b2d849c38656c3d2aaa80 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 15:55:01 +0300 Subject: [PATCH 038/199] rename variable for better semantics --- node/modules/services.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/modules/services.go b/node/modules/services.go index e3ec01503..e8e5c648a 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -79,8 +79,8 @@ func RunBlockSync(h host.Host, svc *blocksync.BlockSyncService) { h.SetStreamHandler(blocksync.BlockSyncProtocolID, svc.HandleStream) } -func waitForSync(stmgr *stmgr.StateManager, blocks int, subscribe func()) { - nearsync := uint64(blocks) * uint64(build.BlockDelaySecs) * uint64(time.Second) //nolint +func waitForSync(stmgr *stmgr.StateManager, epochs int, subscribe func()) { + nearsync := uint64(epochs) * uint64(build.BlockDelaySecs) * uint64(time.Second) //nolint // early check, are we synced at start up? ts := stmgr.ChainStore().GetHeaviestTipSet() From 07a4553e6e5fee9ab360e39a1eb3858bac583ad4 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 7 Sep 2020 16:04:12 +0200 Subject: [PATCH 039/199] fix: storage manager - bail out with an error if unsealed cid is undefined --- extern/sector-storage/manager.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/extern/sector-storage/manager.go b/extern/sector-storage/manager.go index 300958e39..86a739c19 100644 --- a/extern/sector-storage/manager.go +++ b/extern/sector-storage/manager.go @@ -217,16 +217,11 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return xerrors.Errorf("read piece: checking for already existing unsealed sector: %w", err) } + var readOk bool var selector WorkerSelector if len(best) == 0 { // new selector = newAllocSelector(m.index, stores.FTUnsealed, stores.PathSealing) } else { // append to existing - selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false) - } - - var readOk bool - - if len(best) > 0 { // There is unsealed sector, see if we can read from it selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false) @@ -257,6 +252,10 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return nil } + if unsealed == cid.Undef { + return xerrors.Errorf("cannot unseal piece (sector: %d, offset: %d size: %d) - unsealed cid is undefined", sector, offset, size) + } + err = m.sched.Schedule(ctx, sector, sealtasks.TTUnseal, selector, unsealFetch, func(ctx context.Context, w Worker) error { return w.UnsealPiece(ctx, sector, offset, size, ticket, unsealed) }) From a97f978cad5b832f658743e25eb9c14eb6e998aa Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Mon, 7 Sep 2020 16:14:19 +0200 Subject: [PATCH 040/199] fix: storage manager - dont fail on successful read piece --- extern/sector-storage/manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/sector-storage/manager.go b/extern/sector-storage/manager.go index 86a739c19..7513b2dbf 100644 --- a/extern/sector-storage/manager.go +++ b/extern/sector-storage/manager.go @@ -273,7 +273,7 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return xerrors.Errorf("reading piece from sealed sector: %w", err) } - if readOk { + if !readOk { return xerrors.Errorf("failed to read unsealed piece") } From f6f5405a2c8100c0b20606cc92a14fb3d46bf4c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 7 Sep 2020 18:21:45 +0200 Subject: [PATCH 041/199] Fix lint --- chain/sync.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/sync.go b/chain/sync.go index cc29e3550..0bcb290f8 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -187,7 +187,7 @@ func (syncer *Syncer) runMetricsTricker(tickerCtx context.Context) { sinceGenesis := build.Clock.Now().Sub(genesisTime) expectedHeight := int64(sinceGenesis.Seconds()) / int64(build.BlockDelaySecs) - stats.Record(tickerCtx, metrics.ChainNodeHeightExpected.M(int64(expectedHeight))) + stats.Record(tickerCtx, metrics.ChainNodeHeightExpected.M(expectedHeight)) case <-tickerCtx.Done(): return } From 81e674ad367f1289af0e32ce153ba9bd75786ed9 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 19:46:35 +0300 Subject: [PATCH 042/199] subscribe early in bootstrappers and get rid of ugly test flag --- node/modules/services.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/node/modules/services.go b/node/modules/services.go index e8e5c648a..22d99fa54 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -31,9 +31,6 @@ import ( "github.com/filecoin-project/lotus/node/modules/helpers" ) -// for tests -var PubsubSubscribeImmediately = false - func RunHello(mctx helpers.MetricsCtx, lc fx.Lifecycle, h host.Host, svc *hello.Service) error { h.SetStreamHandler(hello.ProtocolID, svc.HandleStream) @@ -115,7 +112,7 @@ func waitForSync(stmgr *stmgr.StateManager, epochs int, subscribe func()) { }) } -func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName) { +func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName, bootstrapper dtypes.Bootstrapper) { ctx := helpers.LifecycleCtx(mctx, lc) v := sub.NewBlockValidator( @@ -140,8 +137,7 @@ func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.P go sub.HandleIncomingBlocks(ctx, blocksub, s, bserv, h.ConnManager()) } - // for tests - if PubsubSubscribeImmediately { + if bootstrapper { subscribe() return } @@ -150,7 +146,7 @@ func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.P waitForSync(stmgr, 10, subscribe) } -func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, stmgr *stmgr.StateManager, mpool *messagepool.MessagePool, h host.Host, nn dtypes.NetworkName) { +func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, stmgr *stmgr.StateManager, mpool *messagepool.MessagePool, h host.Host, nn dtypes.NetworkName, bootstrapper dtypes.Bootstrapper) { ctx := helpers.LifecycleCtx(mctx, lc) v := sub.NewMessageValidator(h.ID(), mpool) @@ -170,8 +166,7 @@ func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub go sub.HandleIncomingMessages(ctx, mpool, msgsub) } - // for tests - if PubsubSubscribeImmediately { + if bootstrapper { subscribe() return } From e3aaedbc33cefa043cdfd09bc48a7e2f7f80b291 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 19:46:58 +0300 Subject: [PATCH 043/199] fix tests --- chain/sync_test.go | 5 +++-- cli/paych_test.go | 3 --- node/node_test.go | 3 --- node/test/builder.go | 3 +++ 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/chain/sync_test.go b/chain/sync_test.go index d7cf7e555..0bd372fcc 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -32,6 +32,7 @@ import ( "github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/node/impl" "github.com/filecoin-project/lotus/node/modules" + "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/repo" ) @@ -46,8 +47,6 @@ func init() { } power.ConsensusMinerMinPower = big.NewInt(2048) verifreg.MinVerifiedDealSize = big.NewInt(256) - - modules.PubsubSubscribeImmediately = true } const source = 0 @@ -233,6 +232,7 @@ func (tu *syncTestUtil) addSourceNode(gen int) { node.Repo(sourceRepo), node.MockHost(tu.mn), node.Test(), + node.Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(true)), node.Override(new(modules.Genesis), modules.LoadGenesis(genesis)), ) @@ -265,6 +265,7 @@ func (tu *syncTestUtil) addClientNode() int { node.Repo(repo.NewMemory(nil)), node.MockHost(tu.mn), node.Test(), + node.Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(true)), node.Override(new(modules.Genesis), modules.LoadGenesis(tu.genesis)), ) diff --git a/cli/paych_test.go b/cli/paych_test.go index 279bfb996..9b21d8070 100644 --- a/cli/paych_test.go +++ b/cli/paych_test.go @@ -29,7 +29,6 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/node/modules" "github.com/filecoin-project/lotus/api/test" "github.com/filecoin-project/lotus/chain/wallet" @@ -45,8 +44,6 @@ func init() { abi.RegisteredSealProof_StackedDrg2KiBV1: {}, } verifreg.MinVerifiedDealSize = big.NewInt(256) - - modules.PubsubSubscribeImmediately = true } // TestPaymentChannels does a basic test to exercise the payment channel CLI diff --git a/node/node_test.go b/node/node_test.go index 219795f67..31a14bc20 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -16,7 +16,6 @@ import ( logging "github.com/ipfs/go-log/v2" "github.com/filecoin-project/lotus/api/test" - "github.com/filecoin-project/lotus/node/modules" ) func init() { @@ -27,8 +26,6 @@ func init() { abi.RegisteredSealProof_StackedDrg2KiBV1: {}, } verifreg.MinVerifiedDealSize = big.NewInt(256) - - modules.PubsubSubscribeImmediately = true } func TestAPI(t *testing.T) { diff --git a/node/test/builder.go b/node/test/builder.go index 64e20e4f2..2f98f65e0 100644 --- a/node/test/builder.go +++ b/node/test/builder.go @@ -31,6 +31,7 @@ import ( miner2 "github.com/filecoin-project/lotus/miner" "github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/node/modules" + "github.com/filecoin-project/lotus/node/modules/dtypes" testing2 "github.com/filecoin-project/lotus/node/modules/testing" "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/storage/mockstorage" @@ -370,6 +371,8 @@ func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), + node.Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(true)), + genesis, ) if err != nil { From 0d0dd250ee2df4c3139b2707b19532e93f9960d0 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 19:54:38 +0300 Subject: [PATCH 044/199] use faster decay for bootstrappers --- node/modules/lp2p/pubsub.go | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index d81133f81..90c56f20d 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -278,12 +278,28 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { } // validation queue RED - options = append(options, pubsub.WithPeerGater( - pubsub.DefaultPeerGaterParams().WithTopicDeliveryWeights(map[string]float64{ - drandTopic: 5, - build.BlocksTopic(in.Nn): 10, - build.MessagesTopic(in.Nn): 1, - }))) + pgTopicWeights := map[string]float64{ + drandTopic: 5, + build.BlocksTopic(in.Nn): 10, + build.MessagesTopic(in.Nn): 1, + } + var pgParams *pubsub.PeerGaterParams + + if isBootstrapNode { + pgParams = pubsub.NewPeerGaterParams( + 0.33, + pubsub.ScoreParameterDecay(2*time.Minute), + pubsub.ScoreParameterDecay(10*time.Minute), + ).WithTopicDeliveryWeights(pgTopicWeights) + } else { + pgParams = pubsub.NewPeerGaterParams( + 0.33, + pubsub.ScoreParameterDecay(2*time.Minute), + pubsub.ScoreParameterDecay(time.Hour), + ).WithTopicDeliveryWeights(pgTopicWeights) + } + + options = append(options, pubsub.WithPeerGater(pgParams)) // tracer if in.Cfg.RemoteTracer != "" { From 0fcf8838ccb15f2b98de390dd89c5b0982d5ffba Mon Sep 17 00:00:00 2001 From: vyzo Date: Sun, 6 Sep 2020 13:36:10 +0300 Subject: [PATCH 045/199] improve republish logic to only republish messages that can be included in the next 20 blocks --- chain/messagepool/repub.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index 806171f52..f57e8c412 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -16,7 +16,7 @@ import ( const repubMsgLimit = 30 -var RepublishBatchDelay = 200 * time.Millisecond +var RepublishBatchDelay = 100 * time.Millisecond func (mp *MessagePool) republishPendingMessages() error { mp.curTsLk.Lock() @@ -27,6 +27,7 @@ func (mp *MessagePool) republishPendingMessages() error { mp.curTsLk.Unlock() return xerrors.Errorf("computing basefee: %w", err) } + baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) pending := make(map[address.Address]map[uint64]*types.SignedMessage) mp.lk.Lock() @@ -70,6 +71,7 @@ func (mp *MessagePool) republishPendingMessages() error { gasLimit := int64(build.BlockGasLimit) minGas := int64(gasguess.MinGas) var msgs []*types.SignedMessage +loop: for i := 0; i < len(chains); { chain := chains[i] @@ -91,8 +93,18 @@ func (mp *MessagePool) republishPendingMessages() error { // does it fit in a block? if chain.gasLimit <= gasLimit { - gasLimit -= chain.gasLimit - msgs = append(msgs, chain.msgs...) + // check the baseFee lower bound -- only republish messages that can be included in the chain + // within the next 20 blocks. + for _, m := range chain.msgs { + if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { + chain.Invalidate() + continue loop + } + gasLimit -= m.Message.GasLimit + msgs = append(msgs, m) + } + + // we processed the whole chain, advance i++ continue } From 2e75d9c80ae5301745e59612f1d9a7bff9aa02cf Mon Sep 17 00:00:00 2001 From: vyzo Date: Sun, 6 Sep 2020 13:36:25 +0300 Subject: [PATCH 046/199] be explicit about republish interval, check against timecache duration --- chain/messagepool/messagepool.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 0d62e5423..72d0a01ab 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -45,7 +45,7 @@ var rbfDenomBig = types.NewInt(RbfDenom) const RbfDenom = 256 -var RepublishInterval = pubsub.TimeCacheDuration + time.Duration(5*build.BlockDelaySecs+build.PropagationDelaySecs)*time.Second +var RepublishInterval = time.Duration(10*build.BlockDelaySecs+build.PropagationDelaySecs) * time.Second var minimumBaseFee = types.NewInt(uint64(build.MinimumBaseFee)) var baseFeeLowerBoundFactor = types.NewInt(10) @@ -81,6 +81,14 @@ const ( localUpdates = "update" ) +func init() { + // if the republish interval is too short compared to the pubsub timecache, adjust it + minInterval := pubsub.TimeCacheDuration + time.Duration(build.PropagationDelaySecs) + if RepublishInterval < minInterval { + RepublishInterval = minInterval + } +} + type MessagePool struct { lk sync.Mutex From 5659faf7f0732f3a3a8851fb9b7d2af7c1096956 Mon Sep 17 00:00:00 2001 From: vyzo Date: Sun, 6 Sep 2020 13:48:26 +0300 Subject: [PATCH 047/199] don't immediately publish messages that cannot be included in the next 20 blocks --- chain/messagepool/messagepool.go | 63 +++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 72d0a01ab..b37f347fd 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -363,12 +363,12 @@ func (mp *MessagePool) addLocal(m *types.SignedMessage, msgb []byte) error { return nil } -func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) error { +func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) { epoch := curTs.Height() minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength()) if err := m.VMMessage().ValidForBlockInclusion(minGas.Total()); err != nil { - return xerrors.Errorf("message will not be included in a block: %w", err) + return false, xerrors.Errorf("message will not be included in a block: %w", err) } // this checks if the GasFeeCap is suffisciently high for inclusion in the next 20 blocks @@ -376,18 +376,25 @@ func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.T // on republish to push it through later, if the baseFee has fallen. // this is a defensive check that stops minimum baseFee spam attacks from overloading validation // queues. - // Note that we don't do that for local messages, so that they can be accepted and republished - // automatically - if !local && len(curTs.Blocks()) > 0 { + // Note that for local messages, we always add them so that they can be accepted and republished + // automatically. + publish := local + if len(curTs.Blocks()) > 0 { baseFee := curTs.Blocks()[0].ParentBaseFee baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { - return xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w", - m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure) + if local { + log.Warnf("local message will not be immediately published because GasFeeCap doesn't meet the lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s)", + m.Message.GasFeeCap, baseFeeLowerBound) + publish = false + } else { + return false, xerrors.Errorf("GasFeeCap doesn't meet base fee lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s): %w", + m.Message.GasFeeCap, baseFeeLowerBound, ErrSoftValidationFailure) + } } } - return nil + return publish, nil } func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) { @@ -408,7 +415,8 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) { } mp.curTsLk.Lock() - if err := mp.addTs(m, mp.curTs, true); err != nil { + publish, err := mp.addTs(m, mp.curTs, true) + if err != nil { mp.curTsLk.Unlock() return cid.Undef, err } @@ -421,7 +429,11 @@ func (mp *MessagePool) Push(m *types.SignedMessage) (cid.Cid, error) { } mp.lk.Unlock() - return m.Cid(), mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb) + if publish { + err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb) + } + + return m.Cid(), err } func (mp *MessagePool) checkMessage(m *types.SignedMessage) error { @@ -469,7 +481,9 @@ func (mp *MessagePool) Add(m *types.SignedMessage) error { mp.curTsLk.Lock() defer mp.curTsLk.Unlock() - return mp.addTs(m, mp.curTs, false) + + _, err = mp.addTs(m, mp.curTs, false) + return err } func sigCacheKey(m *types.SignedMessage) (string, error) { @@ -536,28 +550,29 @@ func (mp *MessagePool) checkBalance(m *types.SignedMessage, curTs *types.TipSet) return nil } -func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local bool) error { +func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) { snonce, err := mp.getStateNonce(m.Message.From, curTs) if err != nil { - return xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure) + return false, xerrors.Errorf("failed to look up actor state nonce: %s: %w", err, ErrSoftValidationFailure) } if snonce > m.Message.Nonce { - return xerrors.Errorf("minimum expected nonce is %d: %w", snonce, ErrNonceTooLow) + return false, xerrors.Errorf("minimum expected nonce is %d: %w", snonce, ErrNonceTooLow) } mp.lk.Lock() defer mp.lk.Unlock() - if err := mp.verifyMsgBeforeAdd(m, curTs, local); err != nil { - return err + publish, err := mp.verifyMsgBeforeAdd(m, curTs, local) + if err != nil { + return false, err } if err := mp.checkBalance(m, curTs); err != nil { - return err + return false, err } - return mp.addLocked(m, true) + return publish, mp.addLocked(m, true) } func (mp *MessagePool) addLoaded(m *types.SignedMessage) error { @@ -583,7 +598,8 @@ func (mp *MessagePool) addLoaded(m *types.SignedMessage) error { mp.lk.Lock() defer mp.lk.Unlock() - if err := mp.verifyMsgBeforeAdd(m, curTs, true); err != nil { + _, err = mp.verifyMsgBeforeAdd(m, curTs, true) + if err != nil { return err } @@ -769,7 +785,8 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address, return nil, ErrTryAgain } - if err := mp.verifyMsgBeforeAdd(msg, curTs, true); err != nil { + publish, err := mp.verifyMsgBeforeAdd(msg, curTs, true) + if err != nil { return nil, err } @@ -784,7 +801,11 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address, log.Errorf("addLocal failed: %+v", err) } - return msg, mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb) + if publish { + err = mp.api.PubSubPublish(build.MessagesTopic(mp.netName), msgb) + } + + return msg, err } func (mp *MessagePool) Remove(from address.Address, nonce uint64, applied bool) { From 41222792edfd6f5e1cf1253eef32922f936a0725 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 20:26:51 +0300 Subject: [PATCH 048/199] add docstring for verifyMsgBeforeAdd --- chain/messagepool/messagepool.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index b37f347fd..621a67ae0 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -363,6 +363,16 @@ func (mp *MessagePool) addLocal(m *types.SignedMessage, msgb []byte) error { return nil } +// verifyMsgBeforeAdd verifies that the message meets the minimum criteria for block inclusio +// and whether the message has enough funds to be included in the next 20 blocks. +// If the message is not valid for block inclusion, it returns an error. +// For local messages, if the message can be included in the next 20 blocks, it returns true to +// signal that it should be immediately published. If the message cannot be included in the next 20 +// blocks, it returns false so that the message doesn't immediately get published (and ignored by our +// peers); instead it will be published through the republish loop, once the base fee has fallen +// sufficiently. +// For non local messages, if the message cannot be included in the next 20 blocks it returns +// a (soft) validation error. func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.TipSet, local bool) (bool, error) { epoch := curTs.Height() minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength()) From 47c59afea01f03dc3e34ac95b99e7f611cc1892a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Mon, 7 Sep 2020 20:12:29 +0200 Subject: [PATCH 049/199] Revert "storage manager: bail out with an error if unsealed cid is undefined" --- extern/sector-storage/manager.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/extern/sector-storage/manager.go b/extern/sector-storage/manager.go index 7513b2dbf..300958e39 100644 --- a/extern/sector-storage/manager.go +++ b/extern/sector-storage/manager.go @@ -217,11 +217,16 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return xerrors.Errorf("read piece: checking for already existing unsealed sector: %w", err) } - var readOk bool var selector WorkerSelector if len(best) == 0 { // new selector = newAllocSelector(m.index, stores.FTUnsealed, stores.PathSealing) } else { // append to existing + selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false) + } + + var readOk bool + + if len(best) > 0 { // There is unsealed sector, see if we can read from it selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false) @@ -252,10 +257,6 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return nil } - if unsealed == cid.Undef { - return xerrors.Errorf("cannot unseal piece (sector: %d, offset: %d size: %d) - unsealed cid is undefined", sector, offset, size) - } - err = m.sched.Schedule(ctx, sector, sealtasks.TTUnseal, selector, unsealFetch, func(ctx context.Context, w Worker) error { return w.UnsealPiece(ctx, sector, offset, size, ticket, unsealed) }) @@ -273,7 +274,7 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return xerrors.Errorf("reading piece from sealed sector: %w", err) } - if !readOk { + if readOk { return xerrors.Errorf("failed to read unsealed piece") } From 55b1456d4568da630e25f1479000c43694b86493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 7 Sep 2020 19:31:43 +0100 Subject: [PATCH 050/199] blocksync: introduce interfaces; rename to chainexchange. --- chain/{blocksync => exchange}/cbor_gen.go | 2 +- chain/{blocksync => exchange}/client.go | 124 +++++++----------- chain/exchange/doc.go | 19 +++ chain/exchange/interfaces.go | 51 +++++++ chain/{blocksync => exchange}/peer_tracker.go | 2 +- chain/{blocksync => exchange}/protocol.go | 20 +-- chain/{blocksync => exchange}/server.go | 65 +++------ chain/sync.go | 36 ++--- gen/main.go | 10 +- node/builder.go | 6 +- node/modules/chain.go | 6 +- node/modules/services.go | 6 +- 12 files changed, 186 insertions(+), 161 deletions(-) rename chain/{blocksync => exchange}/cbor_gen.go (99%) rename chain/{blocksync => exchange}/client.go (80%) create mode 100644 chain/exchange/doc.go create mode 100644 chain/exchange/interfaces.go rename chain/{blocksync => exchange}/peer_tracker.go (99%) rename chain/{blocksync => exchange}/protocol.go (94%) rename chain/{blocksync => exchange}/server.go (75%) diff --git a/chain/blocksync/cbor_gen.go b/chain/exchange/cbor_gen.go similarity index 99% rename from chain/blocksync/cbor_gen.go rename to chain/exchange/cbor_gen.go index cd43f4a64..dc91babe3 100644 --- a/chain/blocksync/cbor_gen.go +++ b/chain/exchange/cbor_gen.go @@ -1,6 +1,6 @@ // Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. -package blocksync +package exchange import ( "fmt" diff --git a/chain/blocksync/client.go b/chain/exchange/client.go similarity index 80% rename from chain/blocksync/client.go rename to chain/exchange/client.go index 38e1f6d2c..2133b7805 100644 --- a/chain/blocksync/client.go +++ b/chain/exchange/client.go @@ -1,4 +1,4 @@ -package blocksync +package exchange import ( "bufio" @@ -7,13 +7,15 @@ import ( "math/rand" "time" - host "github.com/libp2p/go-libp2p-core/host" - inet "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/host" + "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" + "go.opencensus.io/trace" "golang.org/x/xerrors" cborutil "github.com/filecoin-project/go-cbor-util" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -21,11 +23,9 @@ import ( "github.com/filecoin-project/lotus/lib/peermgr" ) -// Protocol client. -// FIXME: Rename to just `Client`. Not done at the moment to avoid -// disrupting too much of the consumer code, should be done along -// https://github.com/filecoin-project/lotus/issues/2612. -type BlockSync struct { +// client implements exchange.Client, using the libp2p ChainExchange protocol +// as the fetching mechanism. +type client struct { // Connection manager used to contact the server. // FIXME: We should have a reduced interface here, initialized // just with our protocol ID, we shouldn't be able to open *any* @@ -35,11 +35,12 @@ type BlockSync struct { peerTracker *bsPeerTracker } -func NewClient( - host host.Host, - pmgr peermgr.MaybePeerMgr, -) *BlockSync { - return &BlockSync{ +var _ Client = (*client)(nil) + +// NewClient creates a new libp2p-based exchange.Client that uses the libp2p +// ChainExhange protocol as the fetching mechanism. +func NewClient(host host.Host, pmgr peermgr.MaybePeerMgr) Client { + return &client{ host: host, peerTracker: newPeerTracker(pmgr.Mgr), } @@ -62,11 +63,7 @@ func NewClient( // request options without disrupting external calls. In the future the // consumers should be forced to use a more standardized service and // adhere to a single API derived from this function. -func (client *BlockSync) doRequest( - ctx context.Context, - req *Request, - singlePeer *peer.ID, -) (*validatedResponse, error) { +func (c *client) doRequest(ctx context.Context, req *Request, singlePeer *peer.ID) (*validatedResponse, error) { // Validate request. if req.Length == 0 { return nil, xerrors.Errorf("invalid request of length 0") @@ -86,7 +83,7 @@ func (client *BlockSync) doRequest( if singlePeer != nil { peers = []peer.ID{*singlePeer} } else { - peers = client.getShuffledPeers() + peers = c.getShuffledPeers() if len(peers) == 0 { return nil, xerrors.Errorf("no peers available") } @@ -107,9 +104,9 @@ func (client *BlockSync) doRequest( } // Send request, read response. - res, err := client.sendRequestToPeer(ctx, peer, req) + res, err := c.sendRequestToPeer(ctx, peer, req) if err != nil { - if !xerrors.Is(err, inet.ErrNoConn) { + if !xerrors.Is(err, network.ErrNoConn) { log.Warnf("could not connect to peer %s: %s", peer.String(), err) } @@ -117,15 +114,15 @@ func (client *BlockSync) doRequest( } // Process and validate response. - validRes, err := client.processResponse(req, res) + validRes, err := c.processResponse(req, res) if err != nil { log.Warnf("processing peer %s response failed: %s", peer.String(), err) continue } - client.peerTracker.logGlobalSuccess(build.Clock.Since(globalTime)) - client.host.ConnManager().TagPeer(peer, "bsync", SUCCESS_PEER_TAG_VALUE) + c.peerTracker.logGlobalSuccess(build.Clock.Since(globalTime)) + c.host.ConnManager().TagPeer(peer, "bsync", SuccessPeerTagValue) return validRes, nil } @@ -144,11 +141,8 @@ func (client *BlockSync) doRequest( // We are conflating in the single error returned both status and validation // errors. Peer penalization should happen here then, before returning, so // we can apply the correct penalties depending on the cause of the error. -func (client *BlockSync) processResponse( - req *Request, - res *Response, - // FIXME: Add the `peer` as argument once we implement penalties. -) (*validatedResponse, error) { +// FIXME: Add the `peer` as argument once we implement penalties. +func (c *client) processResponse(req *Request, res *Response) (*validatedResponse, error) { err := res.statusToError() if err != nil { return nil, xerrors.Errorf("status error: %s", err) @@ -246,16 +240,8 @@ func (client *BlockSync) processResponse( return validRes, nil } -// GetBlocks fetches count blocks from the network, from the provided tipset -// *backwards*, returning as many tipsets as count. -// -// {hint/usage}: This is used by the Syncer during normal chain syncing and when -// resolving forks. -func (client *BlockSync) GetBlocks( - ctx context.Context, - tsk types.TipSetKey, - count int, -) ([]*types.TipSet, error) { +// GetBlocks implements Client.GetBlocks(). Refer to the godocs there. +func (c *client) GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) { ctx, span := trace.StartSpan(ctx, "bsync.GetBlocks") defer span.End() if span.IsRecordingEvents() { @@ -271,7 +257,7 @@ func (client *BlockSync) GetBlocks( Options: Headers, } - validRes, err := client.doRequest(ctx, req, nil) + validRes, err := c.doRequest(ctx, req, nil) if err != nil { return nil, err } @@ -279,11 +265,8 @@ func (client *BlockSync) GetBlocks( return validRes.tipsets, nil } -func (client *BlockSync) GetFullTipSet( - ctx context.Context, - peer peer.ID, - tsk types.TipSetKey, -) (*store.FullTipSet, error) { +// GetFullTipSet implements Client.GetFullTipSet(). Refer to the godocs there. +func (c *client) GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) { // TODO: round robin through these peers on error req := &Request{ @@ -292,7 +275,7 @@ func (client *BlockSync) GetFullTipSet( Options: Headers | Messages, } - validRes, err := client.doRequest(ctx, req, &peer) + validRes, err := c.doRequest(ctx, req, &peer) if err != nil { return nil, err } @@ -302,11 +285,8 @@ func (client *BlockSync) GetFullTipSet( // *one* tipset here, so it's safe to index directly. } -func (client *BlockSync) GetChainMessages( - ctx context.Context, - head *types.TipSet, - length uint64, -) ([]*CompactedMessages, error) { +// GetChainMessages implements Client.GetChainMessages(). Refer to the godocs there. +func (c *client) GetChainMessages(ctx context.Context, head *types.TipSet, length uint64) ([]*CompactedMessages, error) { ctx, span := trace.StartSpan(ctx, "GetChainMessages") if span.IsRecordingEvents() { span.AddAttributes( @@ -322,7 +302,7 @@ func (client *BlockSync) GetChainMessages( Options: Messages, } - validRes, err := client.doRequest(ctx, req, nil) + validRes, err := c.doRequest(ctx, req, nil) if err != nil { return nil, err } @@ -333,11 +313,7 @@ func (client *BlockSync) GetChainMessages( // Send a request to a peer. Write request in the stream and read the // response back. We do not do any processing of the request/response // here. -func (client *BlockSync) sendRequestToPeer( - ctx context.Context, - peer peer.ID, - req *Request, -) (_ *Response, err error) { +func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Request) (_ *Response, err error) { // Trace code. ctx, span := trace.StartSpan(ctx, "sendRequestToPeer") defer span.End() @@ -358,7 +334,7 @@ func (client *BlockSync) sendRequestToPeer( }() // -- TRACE -- - supported, err := client.host.Peerstore().SupportsProtocols(peer, BlockSyncProtocolID) + supported, err := c.host.Peerstore().SupportsProtocols(peer, BlockSyncProtocolID) if err != nil { return nil, xerrors.Errorf("failed to get protocols for peer: %w", err) } @@ -372,20 +348,20 @@ func (client *BlockSync) sendRequestToPeer( connectionStart := build.Clock.Now() // Open stream to peer. - stream, err := client.host.NewStream( - inet.WithNoDial(ctx, "should already have connection"), + stream, err := c.host.NewStream( + network.WithNoDial(ctx, "should already have connection"), peer, BlockSyncProtocolID) if err != nil { - client.RemovePeer(peer) + c.RemovePeer(peer) return nil, xerrors.Errorf("failed to open stream to peer: %w", err) } // Write request. - _ = stream.SetWriteDeadline(time.Now().Add(WRITE_REQ_DEADLINE)) + _ = stream.SetWriteDeadline(time.Now().Add(WriteReqDeadline)) if err := cborutil.WriteCborRPC(stream, req); err != nil { _ = stream.SetWriteDeadline(time.Time{}) - client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart)) + c.peerTracker.logFailure(peer, build.Clock.Since(connectionStart)) // FIXME: Should we also remove peer here? return nil, err } @@ -395,10 +371,10 @@ func (client *BlockSync) sendRequestToPeer( // Read response. var res Response err = cborutil.ReadCborRPC( - bufio.NewReader(incrt.New(stream, READ_RES_MIN_SPEED, READ_RES_DEADLINE)), + bufio.NewReader(incrt.New(stream, ReadResMinSpeed, ReadResDeadline)), &res) if err != nil { - client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart)) + c.peerTracker.logFailure(peer, build.Clock.Since(connectionStart)) return nil, xerrors.Errorf("failed to read blocksync response: %w", err) } @@ -412,32 +388,34 @@ func (client *BlockSync) sendRequestToPeer( ) } - client.peerTracker.logSuccess(peer, build.Clock.Since(connectionStart)) + c.peerTracker.logSuccess(peer, build.Clock.Since(connectionStart)) // FIXME: We should really log a success only after we validate the response. // It might be a bit hard to do. return &res, nil } -func (client *BlockSync) AddPeer(p peer.ID) { - client.peerTracker.addPeer(p) +// AddPeer implements Client.AddPeer(). Refer to the godocs there. +func (c *client) AddPeer(p peer.ID) { + c.peerTracker.addPeer(p) } -func (client *BlockSync) RemovePeer(p peer.ID) { - client.peerTracker.removePeer(p) +// RemovePeer implements Client.RemovePeer(). Refer to the godocs there. +func (c *client) RemovePeer(p peer.ID) { + c.peerTracker.removePeer(p) } // getShuffledPeers returns a preference-sorted set of peers (by latency // and failure counting), shuffling the first few peers so we don't always // pick the same peer. // FIXME: Consider merging with `shufflePrefix()s`. -func (client *BlockSync) getShuffledPeers() []peer.ID { - peers := client.peerTracker.prefSortedPeers() +func (c *client) getShuffledPeers() []peer.ID { + peers := c.peerTracker.prefSortedPeers() shufflePrefix(peers) return peers } func shufflePrefix(peers []peer.ID) { - prefix := SHUFFLE_PEERS_PREFIX + prefix := ShufflePeersPrefix if len(peers) < prefix { prefix = len(peers) } diff --git a/chain/exchange/doc.go b/chain/exchange/doc.go new file mode 100644 index 000000000..b20ee0c1f --- /dev/null +++ b/chain/exchange/doc.go @@ -0,0 +1,19 @@ +// Package exchange contains the ChainExchange server and client components. +// +// ChainExchange is the basic chain synchronization protocol of Filecoin. +// ChainExchange is an RPC-oriented protocol, with a single operation to +// request blocks for now. +// +// A request contains a start anchor block (referred to with a CID), and a +// amount of blocks requested beyond the anchor (including the anchor itself). +// +// A client can also pass options, encoded as a 64-bit bitfield. Lotus supports +// two options at the moment: +// +// - include block contents +// - include block messages +// +// The response will include a status code, an optional message, and the +// response payload in case of success. The payload is a slice of serialized +// tipsets. +package exchange diff --git a/chain/exchange/interfaces.go b/chain/exchange/interfaces.go new file mode 100644 index 000000000..79d8fd4b1 --- /dev/null +++ b/chain/exchange/interfaces.go @@ -0,0 +1,51 @@ +package exchange + +import ( + "context" + + "github.com/libp2p/go-libp2p-core/network" + "github.com/libp2p/go-libp2p-core/peer" + + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" +) + +// Server is the responder side of the ChainExchange protocol. It accepts +// requests from clients and services them by returning the requested +// chain data. +type Server interface { + // HandleStream is the protocol handler to be registered on a libp2p + // protocol router. + // + // In the current version of the protocol, streams are single-use. The + // server will read a single Request, and will respond with a single + // Response. It will dispose of the stream straight after. + HandleStream(stream network.Stream) +} + +// Client is the requesting side of the ChainExchange protocol. It acts as +// a proxy for other components to request chain data from peers. It is chiefly +// used by the Syncer. +type Client interface { + // GetBlocks fetches block headers from the network, from the provided + // tipset *backwards*, returning as many tipsets as the count parameter, + // or less. + GetBlocks(ctx context.Context, tsk types.TipSetKey, count int) ([]*types.TipSet, error) + + // GetChainMessages fetches messages from the network, from the provided + // tipset *backwards*, returning the messages from as many tipsets as the + // count parameter, or less. + GetChainMessages(ctx context.Context, head *types.TipSet, length uint64) ([]*CompactedMessages, error) + + // GetFullTipSet fetches a full tipset from a given peer. If successful, + // the fetched object contains block headers and all messages in full form. + GetFullTipSet(ctx context.Context, peer peer.ID, tsk types.TipSetKey) (*store.FullTipSet, error) + + // AddPeer adds a peer to the pool of peers that the Client requests + // data from. + AddPeer(peer peer.ID) + + // RemovePeer removes a peer from the pool of peers that the Client + // requests data from. + RemovePeer(peer peer.ID) +} diff --git a/chain/blocksync/peer_tracker.go b/chain/exchange/peer_tracker.go similarity index 99% rename from chain/blocksync/peer_tracker.go rename to chain/exchange/peer_tracker.go index f1f6ede07..812868cec 100644 --- a/chain/blocksync/peer_tracker.go +++ b/chain/exchange/peer_tracker.go @@ -1,4 +1,4 @@ -package blocksync +package exchange // FIXME: This needs to be reviewed. diff --git a/chain/blocksync/protocol.go b/chain/exchange/protocol.go similarity index 94% rename from chain/blocksync/protocol.go rename to chain/exchange/protocol.go index 6a2861b80..3fdf06cc0 100644 --- a/chain/blocksync/protocol.go +++ b/chain/exchange/protocol.go @@ -1,4 +1,4 @@ -package blocksync +package exchange import ( "time" @@ -25,14 +25,16 @@ const BlockSyncProtocolID = "/fil/sync/blk/0.0.1" // qualifier to avoid "const initializer [...] is not a constant" error.) var MaxRequestLength = uint64(build.ForkLengthThreshold) -// Extracted constants from the code. -// FIXME: Should be reviewed and confirmed. -const SUCCESS_PEER_TAG_VALUE = 25 -const WRITE_REQ_DEADLINE = 5 * time.Second -const READ_RES_DEADLINE = WRITE_REQ_DEADLINE -const READ_RES_MIN_SPEED = 50 << 10 -const SHUFFLE_PEERS_PREFIX = 5 -const WRITE_RES_DEADLINE = 60 * time.Second +const ( + // Extracted constants from the code. + // FIXME: Should be reviewed and confirmed. + SuccessPeerTagValue = 25 + WriteReqDeadline = 5 * time.Second + ReadResDeadline = WriteReqDeadline + ReadResMinSpeed = 50 << 10 + ShufflePeersPrefix = 5 + WriteResDeadline = 60 * time.Second +) // FIXME: Rename. Make private. type Request struct { diff --git a/chain/blocksync/server.go b/chain/exchange/server.go similarity index 75% rename from chain/blocksync/server.go rename to chain/exchange/server.go index ffdf79ad0..c69b9f0f2 100644 --- a/chain/blocksync/server.go +++ b/chain/exchange/server.go @@ -1,4 +1,4 @@ -package blocksync +package exchange import ( "bufio" @@ -18,37 +18,24 @@ import ( inet "github.com/libp2p/go-libp2p-core/network" ) -// BlockSyncService is the component that services BlockSync requests from -// peers. -// -// BlockSync is the basic chain synchronization protocol of Filecoin. BlockSync -// is an RPC-oriented protocol, with a single operation to request blocks. -// -// A request contains a start anchor block (referred to with a CID), and a -// amount of blocks requested beyond the anchor (including the anchor itself). -// -// A client can also pass options, encoded as a 64-bit bitfield. Lotus supports -// two options at the moment: -// -// - include block contents -// - include block messages -// -// The response will include a status code, an optional message, and the -// response payload in case of success. The payload is a slice of serialized -// tipsets. -// FIXME: Rename to just `Server` (will be done later, see note on `BlockSync`). -type BlockSyncService struct { +// server implements exchange.Server. It services requests for the +// libp2p ChainExchange protocol. +type server struct { cs *store.ChainStore } -func NewBlockSyncService(cs *store.ChainStore) *BlockSyncService { - return &BlockSyncService{ +var _ Server = (*server)(nil) + +// NewServer creates a new libp2p-based exchange.Server. It services requests +// for the libp2p ChainExchange protocol. +func NewServer(cs *store.ChainStore) Server { + return &server{ cs: cs, } } -// Entry point of the service, handles `Request`s. -func (server *BlockSyncService) HandleStream(stream inet.Stream) { +// HandleStream implements Server.HandleStream. Refer to the godocs there. +func (s *server) HandleStream(stream inet.Stream) { ctx, span := trace.StartSpan(context.Background(), "blocksync.HandleStream") defer span.End() @@ -62,13 +49,13 @@ func (server *BlockSyncService) HandleStream(stream inet.Stream) { log.Infow("block sync request", "start", req.Head, "len", req.Length) - resp, err := server.processRequest(ctx, &req) + resp, err := s.processRequest(ctx, &req) if err != nil { log.Warn("failed to process request: ", err) return } - _ = stream.SetDeadline(time.Now().Add(WRITE_RES_DEADLINE)) + _ = stream.SetDeadline(time.Now().Add(WriteResDeadline)) if err := cborutil.WriteCborRPC(stream, resp); err != nil { _ = stream.SetDeadline(time.Time{}) log.Warnw("failed to write back response for handle stream", @@ -80,10 +67,7 @@ func (server *BlockSyncService) HandleStream(stream inet.Stream) { // Validate and service the request. We return either a protocol // response or an internal error. -func (server *BlockSyncService) processRequest( - ctx context.Context, - req *Request, -) (*Response, error) { +func (s *server) processRequest(ctx context.Context, req *Request) (*Response, error) { validReq, errResponse := validateRequest(ctx, req) if errResponse != nil { // The request did not pass validation, return the response @@ -91,16 +75,13 @@ func (server *BlockSyncService) processRequest( return errResponse, nil } - return server.serviceRequest(ctx, validReq) + return s.serviceRequest(ctx, validReq) } // Validate request. We either return a `validatedRequest`, or an error // `Response` indicating why we can't process it. We do not return any // internal errors here, we just signal protocol ones. -func validateRequest( - ctx context.Context, - req *Request, -) (*validatedRequest, *Response) { +func validateRequest(ctx context.Context, req *Request) (*validatedRequest, *Response) { _, span := trace.StartSpan(ctx, "blocksync.ValidateRequest") defer span.End() @@ -147,14 +128,11 @@ func validateRequest( return &validReq, nil } -func (server *BlockSyncService) serviceRequest( - ctx context.Context, - req *validatedRequest, -) (*Response, error) { +func (s *server) serviceRequest(ctx context.Context, req *validatedRequest) (*Response, error) { _, span := trace.StartSpan(ctx, "blocksync.ServiceRequest") defer span.End() - chain, err := collectChainSegment(server.cs, req) + chain, err := collectChainSegment(s.cs, req) if err != nil { log.Warn("block sync request: collectChainSegment failed: ", err) return &Response{ @@ -174,10 +152,7 @@ func (server *BlockSyncService) serviceRequest( }, nil } -func collectChainSegment( - cs *store.ChainStore, - req *validatedRequest, -) ([]*BSTipSet, error) { +func collectChainSegment(cs *store.ChainStore, req *validatedRequest) ([]*BSTipSet, error) { var bstips []*BSTipSet cur := req.head diff --git a/chain/sync.go b/chain/sync.go index 1b1cbdde9..06789e14a 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -36,7 +36,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/beacon" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/stmgr" @@ -50,7 +50,7 @@ import ( ) // Blocks that are more than MaxHeightDrift epochs above -//the theoretical max height based on systime are quickly rejected +// the theoretical max height based on systime are quickly rejected const MaxHeightDrift = 5 var defaultMessageFetchWindowSize = 200 @@ -87,7 +87,7 @@ var LocalIncoming = "incoming" // The Syncer does not run workers itself. It's mainly concerned with // ensuring a consistent state of chain consensus. The reactive and network- // interfacing processes are part of other components, such as the SyncManager -// (which owns the sync scheduler and sync workers), BlockSync, the HELLO +// (which owns the sync scheduler and sync workers), client, the HELLO // protocol, and the gossipsub block propagation layer. // // {hint/concept} The fork-choice rule as it currently stands is: "pick the @@ -110,7 +110,7 @@ type Syncer struct { bad *BadBlockCache // handle to the block sync service - Bsync *blocksync.BlockSync + Exchange exchange.Client self peer.ID @@ -128,7 +128,7 @@ type Syncer struct { } // NewSyncer creates a new Syncer object. -func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) { +func NewSyncer(sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) { gen, err := sm.ChainStore().GetGenesis() if err != nil { return nil, xerrors.Errorf("getting genesis block: %w", err) @@ -143,7 +143,7 @@ func NewSyncer(sm *stmgr.StateManager, bsync *blocksync.BlockSync, connmgr connm beacon: beacon, bad: NewBadBlockCache(), Genesis: gent, - Bsync: bsync, + Exchange: exchange, store: sm.ChainStore(), sm: sm, self: self, @@ -220,7 +220,7 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool { return false } - syncer.Bsync.AddPeer(from) + syncer.Exchange.AddPeer(from) bestPweight := syncer.store.GetHeaviestTipSet().ParentWeight() targetWeight := fts.TipSet().ParentWeight() @@ -451,7 +451,7 @@ func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cid.Cid) (cid.Cid, e } // FetchTipSet tries to load the provided tipset from the store, and falls back -// to the network (BlockSync) by querying the supplied peer if not found +// to the network (client) by querying the supplied peer if not found // locally. // // {hint/usage} This is used from the HELLO protocol, to fetch the greeting @@ -462,7 +462,7 @@ func (syncer *Syncer) FetchTipSet(ctx context.Context, p peer.ID, tsk types.TipS } // fall back to the network. - return syncer.Bsync.GetFullTipSet(ctx, p, tsk) + return syncer.Exchange.GetFullTipSet(ctx, p, tsk) } // tryLoadFullTipSet queries the tipset in the ChainStore, and returns a full @@ -1164,7 +1164,7 @@ func extractSyncState(ctx context.Context) *SyncerState { // total equality of the BeaconEntries in each block. // 3. Traverse the chain backwards, for each tipset: // 3a. Load it from the chainstore; if found, it move on to its parent. -// 3b. Query our peers via BlockSync in batches, requesting up to a +// 3b. Query our peers via client in batches, requesting up to a // maximum of 500 tipsets every time. // // Once we've concluded, if we find a mismatching tipset at the height where the @@ -1265,7 +1265,7 @@ loop: if gap := int(blockSet[len(blockSet)-1].Height() - untilHeight); gap < window { window = gap } - blks, err := syncer.Bsync.GetBlocks(ctx, at, window) + blks, err := syncer.Exchange.GetBlocks(ctx, at, window) if err != nil { // Most likely our peers aren't fully synced yet, but forwarded // new block message (ideally we'd find better peers) @@ -1283,7 +1283,7 @@ loop: // have. Since we fetch from the head backwards our reassembled chain // is sorted in reverse here: we have a child -> parent order, our last // tipset then should be child of the first tipset retrieved. - // FIXME: The reassembly logic should be part of the `BlockSync` + // FIXME: The reassembly logic should be part of the `client` // service, the consumer should not be concerned with the // `MaxRequestLength` limitation, it should just be able to request // an segment of arbitrary length. The same burden is put on @@ -1357,7 +1357,7 @@ var ErrForkTooLong = fmt.Errorf("fork longer than threshold") // denylist. Else, we find the common ancestor, and add the missing chain // fragment until the fork point to the returned []TipSet. func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, known *types.TipSet) ([]*types.TipSet, error) { - tips, err := syncer.Bsync.GetBlocks(ctx, incoming.Parents(), int(build.ForkLengthThreshold)) + tips, err := syncer.Exchange.GetBlocks(ctx, incoming.Parents(), int(build.ForkLengthThreshold)) if err != nil { return nil, err } @@ -1438,12 +1438,12 @@ mainLoop: nextI := (i + 1) - batchSize // want to fetch batchSize values, 'i' points to last one we want to fetch, so its 'inclusive' of our request, thus we need to add one to our request start index - var bstout []*blocksync.CompactedMessages + var bstout []*exchange.CompactedMessages for len(bstout) < batchSize { next := headers[nextI] nreq := batchSize - len(bstout) - bstips, err := syncer.Bsync.GetChainMessages(ctx, next, uint64(nreq)) + bstips, err := syncer.Exchange.GetChainMessages(ctx, next, uint64(nreq)) if err != nil { // TODO check errors for temporary nature if windowSize > 1 { @@ -1488,8 +1488,8 @@ mainLoop: if i >= windowSize { newWindowSize := windowSize + 10 - if newWindowSize > int(blocksync.MaxRequestLength) { - newWindowSize = int(blocksync.MaxRequestLength) + if newWindowSize > int(exchange.MaxRequestLength) { + newWindowSize = int(exchange.MaxRequestLength) } if newWindowSize > windowSize { windowSize = newWindowSize @@ -1506,7 +1506,7 @@ mainLoop: return nil } -func persistMessages(bs bstore.Blockstore, bst *blocksync.CompactedMessages) error { +func persistMessages(bs bstore.Blockstore, bst *exchange.CompactedMessages) error { for _, m := range bst.Bls { //log.Infof("putting BLS message: %s", m.Cid()) if _, err := store.PutMessage(bs, m); err != nil { diff --git a/gen/main.go b/gen/main.go index e062f6a2e..1a9894a7e 100644 --- a/gen/main.go +++ b/gen/main.go @@ -7,7 +7,7 @@ import ( gen "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/hello" "github.com/filecoin-project/lotus/paychmgr" @@ -64,10 +64,10 @@ func main() { } err = gen.WriteTupleEncodersToFile("./chain/blocksync/cbor_gen.go", "blocksync", - blocksync.Request{}, - blocksync.Response{}, - blocksync.CompactedMessages{}, - blocksync.BSTipSet{}, + exchange.Request{}, + exchange.Response{}, + exchange.CompactedMessages{}, + exchange.BSTipSet{}, ) if err != nil { fmt.Println(err) diff --git a/node/builder.go b/node/builder.go index 5b6966cd4..3749059c5 100644 --- a/node/builder.go +++ b/node/builder.go @@ -29,7 +29,7 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/beacon" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/lotus/chain/market" @@ -243,7 +243,7 @@ func Online() Option { // Filecoin services Override(new(*chain.Syncer), modules.NewSyncer), - Override(new(*blocksync.BlockSync), blocksync.NewClient), + Override(new(exchange.Client), exchange.NewClient), Override(new(*messagepool.MessagePool), modules.MessagePool), Override(new(modules.Genesis), modules.ErrorGenesis), @@ -252,7 +252,7 @@ func Online() Option { Override(new(dtypes.NetworkName), modules.NetworkName), Override(new(*hello.Service), hello.NewHelloService), - Override(new(*blocksync.BlockSyncService), blocksync.NewBlockSyncService), + Override(new(exchange.Server), exchange.NewServer), Override(new(*peermgr.PeerMgr), peermgr.NewPeerMgr), Override(new(dtypes.Graphsync), modules.Graphsync), diff --git a/node/modules/chain.go b/node/modules/chain.go index ea04945ef..36257d055 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -20,7 +20,7 @@ import ( "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/beacon" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/stmgr" @@ -163,8 +163,8 @@ func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, return netName, err } -func NewSyncer(lc fx.Lifecycle, sm *stmgr.StateManager, bsync *blocksync.BlockSync, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { - syncer, err := chain.NewSyncer(sm, bsync, h.ConnManager(), h.ID(), beacon, verifier) +func NewSyncer(lc fx.Lifecycle, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { + syncer, err := chain.NewSyncer(sm, exchange, h.ConnManager(), h.ID(), beacon, verifier) if err != nil { return nil, err } diff --git a/node/modules/services.go b/node/modules/services.go index fc7486abe..c6889d8ba 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -17,7 +17,7 @@ import ( "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/beacon/drand" - "github.com/filecoin-project/lotus/chain/blocksync" + "github.com/filecoin-project/lotus/chain/exchange" "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" @@ -69,8 +69,8 @@ func RunPeerMgr(mctx helpers.MetricsCtx, lc fx.Lifecycle, pmgr *peermgr.PeerMgr) go pmgr.Run(helpers.LifecycleCtx(mctx, lc)) } -func RunBlockSync(h host.Host, svc *blocksync.BlockSyncService) { - h.SetStreamHandler(blocksync.BlockSyncProtocolID, svc.HandleStream) +func RunBlockSync(h host.Host, svc exchange.Server) { + h.SetStreamHandler(exchange.BlockSyncProtocolID, svc.HandleStream) } func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName) { From 453e826a0fdb43bad94d8ad6d9fa00bbb5a202b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 7 Sep 2020 19:45:34 +0100 Subject: [PATCH 051/199] rename p2p protocol to /fil/chain/xchg/0.0.1 (backwards-compatible); rename more. --- chain/exchange/client.go | 14 ++++++-------- chain/exchange/protocol.go | 14 +++++++++++--- chain/exchange/server.go | 6 +++--- chain/sync.go | 2 +- cli/log.go | 2 +- gen/main.go | 2 +- node/builder.go | 4 ++-- node/modules/services.go | 5 +++-- 8 files changed, 28 insertions(+), 21 deletions(-) diff --git a/chain/exchange/client.go b/chain/exchange/client.go index 2133b7805..76b93fb6c 100644 --- a/chain/exchange/client.go +++ b/chain/exchange/client.go @@ -334,15 +334,13 @@ func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Reque }() // -- TRACE -- - supported, err := c.host.Peerstore().SupportsProtocols(peer, BlockSyncProtocolID) + supported, err := c.host.Peerstore().SupportsProtocols(peer, BlockSyncProtocolID, ChainExchangeProtocolID) if err != nil { return nil, xerrors.Errorf("failed to get protocols for peer: %w", err) } - if len(supported) == 0 || supported[0] != BlockSyncProtocolID { - return nil, xerrors.Errorf("peer %s does not support protocol %s", - peer, BlockSyncProtocolID) - // FIXME: `ProtoBook` should support a *single* protocol check that returns - // a bool instead of a list. + if len(supported) == 0 || (supported[0] != BlockSyncProtocolID && supported[0] != ChainExchangeProtocolID) { + return nil, xerrors.Errorf("peer %s does not support protocols %s", + peer, []string{BlockSyncProtocolID, ChainExchangeProtocolID}) } connectionStart := build.Clock.Now() @@ -351,7 +349,7 @@ func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Reque stream, err := c.host.NewStream( network.WithNoDial(ctx, "should already have connection"), peer, - BlockSyncProtocolID) + ChainExchangeProtocolID, BlockSyncProtocolID) if err != nil { c.RemovePeer(peer) return nil, xerrors.Errorf("failed to open stream to peer: %w", err) @@ -375,7 +373,7 @@ func (c *client) sendRequestToPeer(ctx context.Context, peer peer.ID, req *Reque &res) if err != nil { c.peerTracker.logFailure(peer, build.Clock.Since(connectionStart)) - return nil, xerrors.Errorf("failed to read blocksync response: %w", err) + return nil, xerrors.Errorf("failed to read chainxchg response: %w", err) } // FIXME: Move all this together at the top using a defer as done elsewhere. diff --git a/chain/exchange/protocol.go b/chain/exchange/protocol.go index 3fdf06cc0..ca4b61836 100644 --- a/chain/exchange/protocol.go +++ b/chain/exchange/protocol.go @@ -13,9 +13,17 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -var log = logging.Logger("blocksync") +var log = logging.Logger("chainxchg") -const BlockSyncProtocolID = "/fil/sync/blk/0.0.1" +const ( + // BlockSyncProtocolID is the protocol ID of the former blocksync protocol. + // Deprecated. + BlockSyncProtocolID = "/fil/sync/blk/0.0.1" + + // ChainExchangeProtocolID is the protocol ID of the chain exchange + // protocol. + ChainExchangeProtocolID = "/fil/chain/xchg/0.0.1" +) // FIXME: Bumped from original 800 to this to accommodate `syncFork()` // use of `GetBlocks()`. It seems the expectation of that API is to @@ -119,7 +127,7 @@ func (res *Response) statusToError() error { case NotFound: return xerrors.Errorf("not found") case GoAway: - return xerrors.Errorf("not handling 'go away' blocksync responses yet") + return xerrors.Errorf("not handling 'go away' chainxchg responses yet") case InternalError: return xerrors.Errorf("block sync peer errored: %s", res.ErrorMessage) case BadRequest: diff --git a/chain/exchange/server.go b/chain/exchange/server.go index c69b9f0f2..54e169b3f 100644 --- a/chain/exchange/server.go +++ b/chain/exchange/server.go @@ -36,7 +36,7 @@ func NewServer(cs *store.ChainStore) Server { // HandleStream implements Server.HandleStream. Refer to the godocs there. func (s *server) HandleStream(stream inet.Stream) { - ctx, span := trace.StartSpan(context.Background(), "blocksync.HandleStream") + ctx, span := trace.StartSpan(context.Background(), "chainxchg.HandleStream") defer span.End() defer stream.Close() //nolint:errcheck @@ -82,7 +82,7 @@ func (s *server) processRequest(ctx context.Context, req *Request) (*Response, e // `Response` indicating why we can't process it. We do not return any // internal errors here, we just signal protocol ones. func validateRequest(ctx context.Context, req *Request) (*validatedRequest, *Response) { - _, span := trace.StartSpan(ctx, "blocksync.ValidateRequest") + _, span := trace.StartSpan(ctx, "chainxchg.ValidateRequest") defer span.End() validReq := validatedRequest{} @@ -129,7 +129,7 @@ func validateRequest(ctx context.Context, req *Request) (*validatedRequest, *Res } func (s *server) serviceRequest(ctx context.Context, req *validatedRequest) (*Response, error) { - _, span := trace.StartSpan(ctx, "blocksync.ServiceRequest") + _, span := trace.StartSpan(ctx, "chainxchg.ServiceRequest") defer span.End() chain, err := collectChainSegment(s.cs, req) diff --git a/chain/sync.go b/chain/sync.go index 06789e14a..f980531fc 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -87,7 +87,7 @@ var LocalIncoming = "incoming" // The Syncer does not run workers itself. It's mainly concerned with // ensuring a consistent state of chain consensus. The reactive and network- // interfacing processes are part of other components, such as the SyncManager -// (which owns the sync scheduler and sync workers), client, the HELLO +// (which owns the sync scheduler and sync workers), ChainExchange, the HELLO // protocol, and the gossipsub block propagation layer. // // {hint/concept} The fork-choice rule as it currently stands is: "pick the diff --git a/cli/log.go b/cli/log.go index b551b5645..ed624eb8d 100644 --- a/cli/log.go +++ b/cli/log.go @@ -49,7 +49,7 @@ var logSetLevel = &cli.Command{ The system flag can be specified multiple times. - eg) log set-level --system chain --system blocksync debug + eg) log set-level --system chain --system chainxchg debug Available Levels: debug diff --git a/gen/main.go b/gen/main.go index 1a9894a7e..e7586a92a 100644 --- a/gen/main.go +++ b/gen/main.go @@ -63,7 +63,7 @@ func main() { os.Exit(1) } - err = gen.WriteTupleEncodersToFile("./chain/blocksync/cbor_gen.go", "blocksync", + err = gen.WriteTupleEncodersToFile("./chain/exchange/cbor_gen.go", "exchange", exchange.Request{}, exchange.Response{}, exchange.CompactedMessages{}, diff --git a/node/builder.go b/node/builder.go index 3749059c5..6ccab21de 100644 --- a/node/builder.go +++ b/node/builder.go @@ -103,7 +103,7 @@ const ( SetGenesisKey RunHelloKey - RunBlockSyncKey + RunChainExchangeKey RunChainGraphsync RunPeerMgrKey @@ -259,7 +259,7 @@ func Online() Option { Override(new(*dtypes.MpoolLocker), new(dtypes.MpoolLocker)), Override(RunHelloKey, modules.RunHello), - Override(RunBlockSyncKey, modules.RunBlockSync), + Override(RunChainExchangeKey, modules.RunChainExchange), Override(RunPeerMgrKey, modules.RunPeerMgr), Override(HandleIncomingBlocksKey, modules.HandleIncomingBlocks), diff --git a/node/modules/services.go b/node/modules/services.go index c6889d8ba..b54a14bb1 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -69,8 +69,9 @@ func RunPeerMgr(mctx helpers.MetricsCtx, lc fx.Lifecycle, pmgr *peermgr.PeerMgr) go pmgr.Run(helpers.LifecycleCtx(mctx, lc)) } -func RunBlockSync(h host.Host, svc exchange.Server) { - h.SetStreamHandler(exchange.BlockSyncProtocolID, svc.HandleStream) +func RunChainExchange(h host.Host, svc exchange.Server) { + h.SetStreamHandler(exchange.BlockSyncProtocolID, svc.HandleStream) // old + h.SetStreamHandler(exchange.ChainExchangeProtocolID, svc.HandleStream) // new } func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName) { From 2233751668d0aeaf0a930aa92c862620600eef4b Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 21:53:30 +0300 Subject: [PATCH 052/199] use the baseFeeLowerBound for computing repub message chains --- chain/messagepool/repub.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index f57e8c412..648466629 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -56,7 +56,11 @@ func (mp *MessagePool) republishPendingMessages() error { var chains []*msgChain for actor, mset := range pending { - next := mp.createMessageChains(actor, mset, baseFee, ts) + // We use the baseFee lower bound for createChange so that we optimistically include + // chains that might become profitable in the next 20 blocks. + // We still check the lowerBound condition for individual messages so that we don't send + // messages that will be rejected by the mpool spam protector, so this is safe to do. + next := mp.createMessageChains(actor, mset, baseFeeLowerBound, ts) chains = append(chains, next...) } From 878ffafb51d9b9251c438231e179d00d1ebb646f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Mon, 7 Sep 2020 20:20:23 +0100 Subject: [PATCH 053/199] rename other Chain{Exchange=>Bitswap}; fix ChainBlock{s=>S}ervice(). --- node/builder.go | 4 ++-- node/modules/chain.go | 4 ++-- node/modules/dtypes/storage.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/node/builder.go b/node/builder.go index 6ccab21de..128f44bd3 100644 --- a/node/builder.go +++ b/node/builder.go @@ -238,8 +238,8 @@ func Online() Option { Override(new(dtypes.ChainGCLocker), blockstore.NewGCLocker), Override(new(dtypes.ChainGCBlockstore), modules.ChainGCBlockstore), - Override(new(dtypes.ChainExchange), modules.ChainExchange), - Override(new(dtypes.ChainBlockService), modules.ChainBlockservice), + Override(new(dtypes.ChainBitswap), modules.ChainBitswap), + Override(new(dtypes.ChainBlockService), modules.ChainBlockService), // Filecoin services Override(new(*chain.Syncer), modules.NewSyncer), diff --git a/node/modules/chain.go b/node/modules/chain.go index 36257d055..1f398d0d8 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -33,7 +33,7 @@ import ( "github.com/filecoin-project/lotus/node/repo" ) -func ChainExchange(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, rt routing.Routing, bs dtypes.ChainGCBlockstore) dtypes.ChainExchange { +func ChainBitswap(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, rt routing.Routing, bs dtypes.ChainGCBlockstore) dtypes.ChainBitswap { // prefix protocol for chain bitswap // (so bitswap uses /chain/ipfs/bitswap/1.0.0 internally for chain sync stuff) bitswapNetwork := network.NewFromIpfsHost(host, rt, network.Prefix("/chain")) @@ -83,7 +83,7 @@ func ChainGCBlockstore(bs dtypes.ChainBlockstore, gcl dtypes.ChainGCLocker) dtyp return blockstore.NewGCBlockstore(bs, gcl) } -func ChainBlockservice(bs dtypes.ChainBlockstore, rem dtypes.ChainExchange) dtypes.ChainBlockService { +func ChainBlockService(bs dtypes.ChainBlockstore, rem dtypes.ChainBitswap) dtypes.ChainBlockService { return blockservice.New(bs, rem) } diff --git a/node/modules/dtypes/storage.go b/node/modules/dtypes/storage.go index b8c1c3081..13defda8d 100644 --- a/node/modules/dtypes/storage.go +++ b/node/modules/dtypes/storage.go @@ -27,7 +27,7 @@ type ChainBlockstore blockstore.Blockstore type ChainGCLocker blockstore.GCLocker type ChainGCBlockstore blockstore.GCBlockstore -type ChainExchange exchange.Interface +type ChainBitswap exchange.Interface type ChainBlockService bserv.BlockService type ClientMultiDstore *multistore.MultiStore From a8dcea142213c892576241be73ebac074ad2a740 Mon Sep 17 00:00:00 2001 From: anorth <445306+anorth@users.noreply.github.com> Date: Thu, 20 Aug 2020 15:28:42 +1000 Subject: [PATCH 054/199] Remove use of exitcode.SysErrInvalidParameters --- chain/vm/runtime.go | 2 +- chain/vm/vm.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 99333fc04..fd13c704e 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -341,7 +341,7 @@ func (rt *Runtime) Send(to address.Address, method abi.MethodNum, m vmr.CBORMars if m != nil { buf := new(bytes.Buffer) if err := m.MarshalCBOR(buf); err != nil { - rt.Abortf(exitcode.SysErrInvalidParameters, "failed to marshal input parameters: %s", err) + rt.Abortf(exitcode.ErrSerialization, "failed to marshal input parameters: %s", err) } params = buf.Bytes() } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index f51cbff29..ea18a7c43 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -40,23 +40,23 @@ var actorLog = logging.Logger("actors") var gasOnActorExec = newGasCharge("OnActorExec", 0, 0) // ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`. -func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, aerrors.ActorError) { +func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, error) { if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 { return addr, nil } act, err := state.GetActor(addr) if err != nil { - return address.Undef, aerrors.Newf(exitcode.SysErrInvalidParameters, "failed to find actor: %s", addr) + return address.Undef, xerrors.Errorf("failed to find actor: %s", addr) } if act.Code != builtin.AccountActorCodeID { - return address.Undef, aerrors.Newf(exitcode.SysErrInvalidParameters, "address %s was not for an account actor", addr) + return address.Undef, xerrors.Errorf("address %s was not for an account actor", addr) } var aast account.State if err := cst.Get(context.TODO(), act.Head, &aast); err != nil { - return address.Undef, aerrors.Absorb(err, exitcode.SysErrInvalidParameters, fmt.Sprintf("failed to get account actor state for %s", addr)) + return address.Undef, xerrors.Errorf("failed to get account actor state for %s: %w", addr, err) } return aast.Address, nil From 39755a294aaae75d5b59992292142f4d755fa750 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Sun, 6 Sep 2020 23:49:10 -0400 Subject: [PATCH 055/199] Update to specs v0.9.6 --- api/api_full.go | 18 +++++---- api/api_storage.go | 2 +- api/api_worker.go | 2 +- api/apistruct/struct.go | 19 ++++----- api/cbor_gen.go | 2 +- api/docgen/docgen.go | 6 +-- api/test/blockminer.go | 2 +- api/test/ccupgrade.go | 2 +- api/test/deals.go | 2 +- api/test/mining.go | 2 +- api/test/paych.go | 4 +- api/test/util.go | 2 +- api/test/window_post.go | 2 +- api/types.go | 2 +- api/utils.go | 2 +- build/params_2k.go | 4 +- build/params_shared_funcs.go | 2 +- build/params_shared_vals.go | 2 +- build/params_testground.go | 2 +- build/params_testnet.go | 4 +- chain/actors/aerrors/error.go | 2 +- chain/actors/aerrors/error_test.go | 2 +- chain/actors/aerrors/wrap.go | 2 +- chain/beacon/beacon.go | 2 +- chain/beacon/drand/drand.go | 2 +- chain/beacon/mock.go | 2 +- chain/events/events.go | 2 +- chain/events/events_called.go | 2 +- chain/events/events_height.go | 5 +-- chain/events/events_test.go | 4 +- chain/events/state/predicates.go | 4 +- chain/events/state/predicates_test.go | 6 +-- chain/events/tscache.go | 2 +- chain/events/tscache_test.go | 4 +- chain/gen/gen.go | 21 +++++----- chain/gen/gen_test.go | 4 +- chain/gen/genesis/genesis.go | 6 +-- chain/gen/genesis/miners.go | 6 +-- chain/gen/genesis/t02_reward.go | 2 +- chain/gen/genesis/util.go | 2 +- chain/gen/mining.go | 2 +- chain/gen/slashfilter/slashfilter.go | 2 +- chain/market/fundmgr.go | 4 +- chain/market/fundmgr_test.go | 4 +- chain/messagepool/gasguess/guessgas.go | 2 +- chain/messagepool/messagepool.go | 2 +- chain/messagepool/messagepool_test.go | 2 +- chain/messagepool/repub_test.go | 2 +- chain/messagepool/selection.go | 4 +- chain/messagepool/selection_test.go | 2 +- chain/metrics/consensus.go | 2 +- chain/stmgr/call.go | 4 +- chain/stmgr/forks.go | 2 +- chain/stmgr/forks_test.go | 4 +- chain/stmgr/stmgr.go | 4 +- chain/stmgr/utils.go | 20 +++++----- chain/store/basefee.go | 4 +- chain/store/index.go | 2 +- chain/store/index_test.go | 2 +- chain/store/store.go | 4 +- chain/store/store_test.go | 6 +-- chain/store/weight.go | 2 +- chain/sync.go | 7 ++-- chain/sync_test.go | 9 +++-- chain/syncstate.go | 2 +- chain/types/bigint.go | 2 +- chain/types/blockheader.go | 7 ++-- chain/types/blockheader_test.go | 6 +-- chain/types/cbor_gen.go | 15 +++---- chain/types/message.go | 4 +- chain/types/message_receipt.go | 2 +- chain/types/message_test.go | 2 +- chain/types/mock/chain.go | 4 +- chain/types/signature_test.go | 2 +- chain/types/signedmessage.go | 4 +- chain/types/tipset.go | 2 +- chain/types/tipset_key.go | 2 +- chain/vectors/gen/main.go | 7 ++-- chain/vectors/vector_types.go | 2 +- chain/vm/burn.go | 4 +- chain/vm/gas.go | 15 +++---- chain/vm/gas_v0.go | 11 ++--- chain/vm/invoker.go | 4 +- chain/vm/invoker_test.go | 2 +- chain/vm/mkactor.go | 4 +- chain/vm/runtime.go | 8 ++-- chain/vm/runtime_test.go | 2 +- chain/vm/syscalls.go | 13 +++--- chain/vm/vm.go | 8 ++-- chain/wallet/wallet.go | 2 +- cli/chain.go | 4 +- cli/client.go | 4 +- cli/mpool.go | 2 +- cli/multisig.go | 2 +- cli/paych_test.go | 4 +- cli/send.go | 2 +- cli/state.go | 7 ++-- cli/sync.go | 2 +- cli/wallet.go | 2 +- cmd/chain-noise/main.go | 2 +- cmd/lotus-bench/import.go | 2 +- cmd/lotus-bench/main.go | 21 +++++----- cmd/lotus-chainwatch/processor/miner.go | 16 ++++---- cmd/lotus-chainwatch/processor/power.go | 2 +- cmd/lotus-chainwatch/processor/processor.go | 2 +- cmd/lotus-chainwatch/processor/reward.go | 2 +- cmd/lotus-keygen/main.go | 2 +- cmd/lotus-pcr/main.go | 6 +-- cmd/lotus-seed/genesis.go | 4 +- cmd/lotus-seed/main.go | 4 +- cmd/lotus-seed/seed/seed.go | 6 +-- cmd/lotus-shed/genesis-verify.go | 2 +- cmd/lotus-shed/proofs.go | 4 +- cmd/lotus-storage-miner/actor.go | 4 +- cmd/lotus-storage-miner/info.go | 2 +- cmd/lotus-storage-miner/init.go | 6 +-- cmd/lotus-storage-miner/market.go | 2 +- cmd/lotus-storage-miner/proving.go | 2 +- cmd/lotus-storage-miner/sectors.go | 2 +- cmd/lotus-storage-miner/storage.go | 2 +- cmd/lotus/debug_advance.go | 2 +- conformance/driver.go | 4 +- conformance/stubs.go | 9 +++-- extern/filecoin-ffi | 2 +- extern/sector-storage/faults.go | 2 +- .../sector-storage/ffiwrapper/basicfs/fs.go | 2 +- extern/sector-storage/ffiwrapper/config.go | 2 +- .../sector-storage/ffiwrapper/partialfile.go | 2 +- extern/sector-storage/ffiwrapper/sealer.go | 2 +- .../sector-storage/ffiwrapper/sealer_cgo.go | 2 +- .../sector-storage/ffiwrapper/sealer_test.go | 4 +- extern/sector-storage/ffiwrapper/types.go | 9 +++-- .../ffiwrapper/unseal_ranges.go | 2 +- .../sector-storage/ffiwrapper/verifier_cgo.go | 15 +++---- extern/sector-storage/fr32/fr32.go | 2 +- .../sector-storage/fr32/fr32_ffi_cmp_test.go | 2 +- extern/sector-storage/fr32/fr32_test.go | 2 +- extern/sector-storage/fr32/readers.go | 2 +- extern/sector-storage/fr32/readers_test.go | 2 +- extern/sector-storage/fr32/utils.go | 2 +- extern/sector-storage/localworker.go | 2 +- extern/sector-storage/manager.go | 2 +- extern/sector-storage/manager_test.go | 2 +- extern/sector-storage/mock/mock.go | 21 +++++----- extern/sector-storage/mock/mock_test.go | 2 +- extern/sector-storage/resources.go | 2 +- extern/sector-storage/roprov.go | 2 +- extern/sector-storage/sched.go | 2 +- extern/sector-storage/sched_test.go | 2 +- extern/sector-storage/selector_alloc.go | 2 +- extern/sector-storage/selector_existing.go | 2 +- extern/sector-storage/selector_task.go | 2 +- extern/sector-storage/stores/filetype.go | 2 +- extern/sector-storage/stores/index.go | 4 +- extern/sector-storage/stores/index_locks.go | 2 +- .../sector-storage/stores/index_locks_test.go | 2 +- extern/sector-storage/stores/interface.go | 2 +- extern/sector-storage/stores/local.go | 2 +- extern/sector-storage/stores/remote.go | 2 +- extern/sector-storage/storiface/ffi.go | 2 +- extern/sector-storage/storiface/worker.go | 2 +- extern/sector-storage/testworker_test.go | 2 +- extern/sector-storage/work_tracker.go | 2 +- extern/sector-storage/zerocomm/zerocomm.go | 2 +- .../sector-storage/zerocomm/zerocomm_test.go | 2 +- extern/storage-sealing/cbor_gen.go | 2 +- extern/storage-sealing/checks.go | 7 ++-- extern/storage-sealing/constants.go | 2 +- extern/storage-sealing/events.go | 2 +- extern/storage-sealing/fsm.go | 2 +- extern/storage-sealing/fsm_events.go | 4 +- extern/storage-sealing/fsm_test.go | 2 +- extern/storage-sealing/garbage.go | 2 +- extern/storage-sealing/nullreader.go | 2 +- extern/storage-sealing/precommit_policy.go | 2 +- .../storage-sealing/precommit_policy_test.go | 2 +- extern/storage-sealing/sealing.go | 6 +-- extern/storage-sealing/states_failed.go | 4 +- extern/storage-sealing/states_sealing.go | 8 ++-- extern/storage-sealing/stats.go | 2 +- extern/storage-sealing/types.go | 6 +-- extern/storage-sealing/types_test.go | 2 +- extern/storage-sealing/upgrade_queue.go | 4 +- extern/storage-sealing/utils.go | 2 +- extern/storage-sealing/utils_test.go | 2 +- extern/test-vectors | 2 +- genesis/types.go | 2 +- go.mod | 12 ++++-- go.sum | 40 +++++++++++-------- lib/rpcenc/reader.go | 2 +- lib/sigs/bls/init.go | 2 +- lib/sigs/secp/init.go | 2 +- lib/sigs/sigs.go | 2 +- lotuspond/spawn.go | 2 +- markets/loggers/loggers.go | 2 +- markets/retrievaladapter/client.go | 2 +- markets/retrievaladapter/provider.go | 2 +- markets/storageadapter/client.go | 8 ++-- markets/storageadapter/provider.go | 6 +-- markets/utils/converters.go | 4 +- miner/miner.go | 7 ++-- miner/testminer.go | 2 +- node/hello/cbor_gen.go | 2 +- node/hello/hello.go | 4 +- node/impl/client/client.go | 4 +- node/impl/full/beacon.go | 2 +- node/impl/full/chain.go | 4 +- node/impl/full/gas.go | 6 +-- node/impl/full/multisig.go | 4 +- node/impl/full/state.go | 14 +++---- node/impl/full/wallet.go | 4 +- node/impl/remoteworker.go | 2 +- node/impl/storminer.go | 4 +- node/modules/dtypes/miner.go | 2 +- node/modules/storageminer.go | 2 +- node/node_test.go | 4 +- node/test/builder.go | 4 +- paychmgr/manager.go | 2 +- paychmgr/mock_test.go | 2 +- paychmgr/paych.go | 2 +- paychmgr/paych_test.go | 6 +-- paychmgr/paychget_test.go | 4 +- paychmgr/settle_test.go | 2 +- paychmgr/settler/settler.go | 2 +- paychmgr/simple.go | 2 +- storage/adapter_events.go | 2 +- storage/adapter_storage_miner.go | 9 +++-- storage/addresses.go | 2 +- storage/miner.go | 16 ++++---- storage/mockstorage/preseal.go | 6 +-- storage/sealing.go | 2 +- storage/sectorblocks/blocks.go | 2 +- storage/wdpost_run.go | 21 +++++----- storage/wdpost_sched.go | 2 +- tools/stats/collect.go | 2 +- tools/stats/rpc.go | 2 +- 236 files changed, 506 insertions(+), 473 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 8ae857dfd..378920374 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -2,23 +2,25 @@ package api import ( "context" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "time" "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/peer" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-multistore" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/paych" "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/lotus/chain/types" marketevents "github.com/filecoin-project/lotus/markets/loggers" @@ -300,7 +302,7 @@ type FullNode interface { // StateMinerSectors returns info about the given miner's sectors. If the filter bitfield is nil, all sectors are included. // If the filterOut boolean is set to true, any sectors in the filter are excluded. // If false, only those sectors in the filter are included. - StateMinerSectors(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error) + StateMinerSectors(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*ChainSectorInfo, error) // StateMinerActiveSectors returns info about sectors that a given miner is actively proving. StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error) // StateMinerProvingDeadline calculates the deadline at some epoch for a proving period @@ -315,11 +317,11 @@ type FullNode interface { // StateMinerPartitions loads miner partitions for the specified miner/deadline StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error) // StateMinerFaults returns a bitfield indicating the faulty sectors of the given miner - StateMinerFaults(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) + StateMinerFaults(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) // StateAllMinerFaults returns all non-expired Faults that occur within lookback epochs of the given tipset StateAllMinerFaults(ctx context.Context, lookback abi.ChainEpoch, ts types.TipSetKey) ([]*Fault, error) // StateMinerRecoveries returns a bitfield indicating the recovering sectors of the given miner - StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) + StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) // StateMinerInitialPledgeCollateral returns the precommit deposit for the specified miner's sector StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) // StateMinerInitialPledgeCollateral returns the initial pledge collateral for the specified miner's sector @@ -738,7 +740,7 @@ type CirculatingSupply struct { type MiningBaseInfo struct { MinerPower types.BigInt NetworkPower types.BigInt - Sectors []abi.SectorInfo + Sectors []proof.SectorInfo WorkerKey address.Address SectorSize abi.SectorSize PrevBeaconEntry types.BeaconEntry @@ -755,7 +757,7 @@ type BlockTemplate struct { Messages []*types.SignedMessage Epoch abi.ChainEpoch Timestamp uint64 - WinningPoStProof []abi.PoStProof + WinningPoStProof []proof.PoStProof } type DataSize struct { diff --git a/api/api_storage.go b/api/api_storage.go index 48f6e9e45..37bef2d6c 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -11,11 +11,11 @@ import ( "github.com/filecoin-project/go-fil-markets/piecestore" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/stores" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" - "github.com/filecoin-project/specs-actors/actors/abi" ) // StorageMiner is a low-level interface to the Filecoin network storage miner node diff --git a/api/api_worker.go b/api/api_worker.go index 00c4df8bc..ac1446fdd 100644 --- a/api/api_worker.go +++ b/api/api_worker.go @@ -6,10 +6,10 @@ import ( "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/build" diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index e2444f16b..e4946995d 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -12,22 +12,23 @@ import ( protocol "github.com/libp2p/go-libp2p-core/protocol" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-fil-markets/piecestore" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-multistore" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" marketevents "github.com/filecoin-project/lotus/markets/loggers" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" @@ -156,16 +157,16 @@ type FullNodeStruct struct { ClientDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"` StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"` - StateMinerSectors func(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` + StateMinerSectors func(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` StateMinerActiveSectors func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) `perm:"read"` StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"` StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) `perm:"read"` StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) ([]*miner.Deadline, error) `perm:"read"` StateMinerPartitions func(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error) `perm:"read"` - StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) `perm:"read"` + StateMinerFaults func(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) `perm:"read"` StateAllMinerFaults func(context.Context, abi.ChainEpoch, types.TipSetKey) ([]*api.Fault, error) `perm:"read"` - StateMinerRecoveries func(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) `perm:"read"` + StateMinerRecoveries func(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) `perm:"read"` StateMinerPreCommitDepositForPower func(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) `perm:"read"` StateMinerInitialPledgeCollateral func(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) `perm:"read"` StateMinerAvailableBalance func(context.Context, address.Address, types.TipSetKey) (types.BigInt, error) `perm:"read"` @@ -710,7 +711,7 @@ func (c *FullNodeStruct) StateNetworkName(ctx context.Context) (dtypes.NetworkNa return c.Internal.StateNetworkName(ctx) } -func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, filter *abi.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { +func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, filter *bitfield.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { return c.Internal.StateMinerSectors(ctx, addr, filter, filterOut, tsk) } @@ -738,7 +739,7 @@ func (c *FullNodeStruct) StateMinerPartitions(ctx context.Context, m address.Add return c.Internal.StateMinerPartitions(ctx, m, dlIdx, tsk) } -func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (abi.BitField, error) { +func (c *FullNodeStruct) StateMinerFaults(ctx context.Context, actor address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { return c.Internal.StateMinerFaults(ctx, actor, tsk) } @@ -746,7 +747,7 @@ func (c *FullNodeStruct) StateAllMinerFaults(ctx context.Context, cutoff abi.Cha return c.Internal.StateAllMinerFaults(ctx, cutoff, endTsk) } -func (c *FullNodeStruct) StateMinerRecoveries(ctx context.Context, actor address.Address, tsk types.TipSetKey) (abi.BitField, error) { +func (c *FullNodeStruct) StateMinerRecoveries(ctx context.Context, actor address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { return c.Internal.StateMinerRecoveries(ctx, actor, tsk) } diff --git a/api/cbor_gen.go b/api/cbor_gen.go index 8889e6021..7ab575b28 100644 --- a/api/cbor_gen.go +++ b/api/cbor_gen.go @@ -6,7 +6,7 @@ import ( "fmt" "io" - abi "github.com/filecoin-project/specs-actors/actors/abi" + abi "github.com/filecoin-project/go-state-types/abi" paych "github.com/filecoin-project/specs-actors/actors/builtin/paych" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index c3b4962d5..ea3e66e1e 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -28,9 +28,9 @@ import ( "github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-multistore" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/apistruct" diff --git a/api/test/blockminer.go b/api/test/blockminer.go index c6433efea..6b28a5794 100644 --- a/api/test/blockminer.go +++ b/api/test/blockminer.go @@ -7,8 +7,8 @@ import ( "testing" "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/miner" - "github.com/filecoin-project/specs-actors/actors/abi" ) type BlockMiner struct { diff --git a/api/test/ccupgrade.go b/api/test/ccupgrade.go index 3666aa3db..130b55cb8 100644 --- a/api/test/ccupgrade.go +++ b/api/test/ccupgrade.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl" diff --git a/api/test/deals.go b/api/test/deals.go index 1dcc1c8d7..12cd0607a 100644 --- a/api/test/deals.go +++ b/api/test/deals.go @@ -20,11 +20,11 @@ import ( "github.com/ipld/go-car" "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" "github.com/filecoin-project/lotus/miner" - "github.com/filecoin-project/specs-actors/actors/abi" dag "github.com/ipfs/go-merkledag" dstest "github.com/ipfs/go-merkledag/test" unixfile "github.com/ipfs/go-unixfs/file" diff --git a/api/test/mining.go b/api/test/mining.go index f912ff305..e19774a76 100644 --- a/api/test/mining.go +++ b/api/test/mining.go @@ -12,7 +12,7 @@ import ( logging "github.com/ipfs/go-log/v2" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/stretchr/testify/require" "github.com/filecoin-project/lotus/build" diff --git a/api/test/paych.go b/api/test/paych.go index b0ccc0a5c..36eb2c256 100644 --- a/api/test/paych.go +++ b/api/test/paych.go @@ -10,8 +10,8 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/ipfs/go-cid" diff --git a/api/test/util.go b/api/test/util.go index 57a6fcae3..8695e2e2e 100644 --- a/api/test/util.go +++ b/api/test/util.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/types" diff --git a/api/test/window_post.go b/api/test/window_post.go index c5c8ec071..59d7ac1d6 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -12,9 +12,9 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/mock" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/specs-actors/actors/abi" miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/api" diff --git a/api/types.go b/api/types.go index 37cc4a7fa..dc8432818 100644 --- a/api/types.go +++ b/api/types.go @@ -6,8 +6,8 @@ import ( "github.com/filecoin-project/go-address" datatransfer "github.com/filecoin-project/go-data-transfer" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/ipfs/go-cid" diff --git a/api/utils.go b/api/utils.go index 13d5c92cb..a9d02c31b 100644 --- a/api/utils.go +++ b/api/utils.go @@ -4,7 +4,7 @@ import ( "context" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" ) type SignFunc = func(context.Context, []byte) (*crypto.Signature, error) diff --git a/build/params_2k.go b/build/params_2k.go index 12005f005..98506531d 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -3,8 +3,8 @@ package build import ( - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" diff --git a/build/params_shared_funcs.go b/build/params_shared_funcs.go index cdb8e70d3..2c9ef0b94 100644 --- a/build/params_shared_funcs.go +++ b/build/params_shared_funcs.go @@ -5,7 +5,7 @@ import ( "github.com/libp2p/go-libp2p-core/protocol" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/node/modules/dtypes" diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index 2fce61ee7..7b4d4574b 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -5,7 +5,7 @@ package build import ( "math/big" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) diff --git a/build/params_testground.go b/build/params_testground.go index bdd56fbb1..476b95fee 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -10,7 +10,7 @@ package build import ( "math/big" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) diff --git a/build/params_testnet.go b/build/params_testnet.go index f422b3861..0d5602d70 100644 --- a/build/params_testnet.go +++ b/build/params_testnet.go @@ -5,8 +5,8 @@ package build import ( - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" diff --git a/chain/actors/aerrors/error.go b/chain/actors/aerrors/error.go index e687982c8..12f802c8f 100644 --- a/chain/actors/aerrors/error.go +++ b/chain/actors/aerrors/error.go @@ -3,7 +3,7 @@ package aerrors import ( "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/go-state-types/exitcode" "golang.org/x/xerrors" ) diff --git a/chain/actors/aerrors/error_test.go b/chain/actors/aerrors/error_test.go index 4d87ac396..3bfd3d042 100644 --- a/chain/actors/aerrors/error_test.go +++ b/chain/actors/aerrors/error_test.go @@ -3,8 +3,8 @@ package aerrors_test import ( "testing" + "github.com/filecoin-project/go-state-types/exitcode" . "github.com/filecoin-project/lotus/chain/actors/aerrors" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/stretchr/testify/assert" "golang.org/x/xerrors" diff --git a/chain/actors/aerrors/wrap.go b/chain/actors/aerrors/wrap.go index 338659966..0552829f9 100644 --- a/chain/actors/aerrors/wrap.go +++ b/chain/actors/aerrors/wrap.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/go-state-types/exitcode" cbor "github.com/ipfs/go-ipld-cbor" "golang.org/x/xerrors" ) diff --git a/chain/beacon/beacon.go b/chain/beacon/beacon.go index 23b062bea..5f8a18951 100644 --- a/chain/beacon/beacon.go +++ b/chain/beacon/beacon.go @@ -3,7 +3,7 @@ package beacon import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" logging "github.com/ipfs/go-log" "golang.org/x/xerrors" diff --git a/chain/beacon/drand/drand.go b/chain/beacon/drand/drand.go index 76bf01493..6af39b65f 100644 --- a/chain/beacon/drand/drand.go +++ b/chain/beacon/drand/drand.go @@ -19,7 +19,7 @@ import ( logging "github.com/ipfs/go-log" pubsub "github.com/libp2p/go-libp2p-pubsub" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/beacon" diff --git a/chain/beacon/mock.go b/chain/beacon/mock.go index dc45ae895..56a77df1c 100644 --- a/chain/beacon/mock.go +++ b/chain/beacon/mock.go @@ -6,8 +6,8 @@ import ( "encoding/binary" "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/minio/blake2b-simd" "golang.org/x/xerrors" ) diff --git a/chain/events/events.go b/chain/events/events.go index ba5899270..e35e91366 100644 --- a/chain/events/events.go +++ b/chain/events/events.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "golang.org/x/xerrors" diff --git a/chain/events/events_called.go b/chain/events/events_called.go index 2f813a1d4..753206093 100644 --- a/chain/events/events_called.go +++ b/chain/events/events_called.go @@ -5,7 +5,7 @@ import ( "math" "sync" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" "golang.org/x/xerrors" diff --git a/chain/events/events_height.go b/chain/events/events_height.go index 8317c4da4..aeca6fd15 100644 --- a/chain/events/events_height.go +++ b/chain/events/events_height.go @@ -4,10 +4,9 @@ import ( "context" "sync" - "golang.org/x/xerrors" - - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "go.opencensus.io/trace" + "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/types" ) diff --git a/chain/events/events_test.go b/chain/events/events_test.go index 58cb855e2..0e4fd34b2 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" diff --git a/chain/events/state/predicates.go b/chain/events/state/predicates.go index 2019a38eb..b30e69b48 100644 --- a/chain/events/state/predicates.go +++ b/chain/events/state/predicates.go @@ -5,8 +5,8 @@ import ( "context" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/specs-actors/actors/builtin/market" diff --git a/chain/events/state/predicates_test.go b/chain/events/state/predicates_test.go index 944b7e61c..a1dccfadc 100644 --- a/chain/events/state/predicates_test.go +++ b/chain/events/state/predicates_test.go @@ -13,11 +13,11 @@ import ( cbornode "github.com/ipfs/go-ipld-cbor" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" tutils "github.com/filecoin-project/specs-actors/support/testing" diff --git a/chain/events/tscache.go b/chain/events/tscache.go index 20935976c..d47c71480 100644 --- a/chain/events/tscache.go +++ b/chain/events/tscache.go @@ -3,7 +3,7 @@ package events import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/types" diff --git a/chain/events/tscache_test.go b/chain/events/tscache_test.go index 201221e9f..ab6336f24 100644 --- a/chain/events/tscache_test.go +++ b/chain/events/tscache_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 551c3703f..abee75dd3 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -4,15 +4,16 @@ import ( "bytes" "context" "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "io/ioutil" "sync/atomic" "time" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" @@ -46,7 +47,7 @@ const msgsPerBlock = 20 //nolint:deadcode,varcheck var log = logging.Logger("gen") -var ValidWpostForTesting = []abi.PoStProof{{ +var ValidWpostForTesting = []proof.PoStProof{{ ProofBytes: []byte("valid proof"), }} @@ -457,7 +458,7 @@ func (cg *ChainGen) NextTipSetFromMinersWithMessages(base *types.TipSet, miners func (cg *ChainGen) makeBlock(parents *types.TipSet, m address.Address, vrfticket *types.Ticket, eticket *types.ElectionProof, bvals []types.BeaconEntry, height abi.ChainEpoch, - wpost []abi.PoStProof, msgs []*types.SignedMessage) (*types.FullBlock, error) { + wpost []proof.PoStProof, msgs []*types.SignedMessage) (*types.FullBlock, error) { var ts uint64 if cg.Timestamper != nil { @@ -588,7 +589,7 @@ func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*cr type WinningPoStProver interface { GenerateCandidates(context.Context, abi.PoStRandomness, uint64) ([]uint64, error) - ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) + ComputeProof(context.Context, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) } type wppProvider struct{} @@ -597,7 +598,7 @@ func (wpp *wppProvider) GenerateCandidates(ctx context.Context, _ abi.PoStRandom return []uint64{0}, nil } -func (wpp *wppProvider) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) { +func (wpp *wppProvider) ComputeProof(context.Context, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) { return ValidWpostForTesting, nil } @@ -664,15 +665,15 @@ type genFakeVerifier struct{} var _ ffiwrapper.Verifier = (*genFakeVerifier)(nil) -func (m genFakeVerifier) VerifySeal(svi abi.SealVerifyInfo) (bool, error) { +func (m genFakeVerifier) VerifySeal(svi proof.SealVerifyInfo) (bool, error) { return true, nil } -func (m genFakeVerifier) VerifyWinningPoSt(ctx context.Context, info abi.WinningPoStVerifyInfo) (bool, error) { +func (m genFakeVerifier) VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) { panic("not supported") } -func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVerifyInfo) (bool, error) { +func (m genFakeVerifier) VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) { panic("not supported") } diff --git a/chain/gen/gen_test.go b/chain/gen/gen_test.go index 52766af7a..ebc28a990 100644 --- a/chain/gen/gen_test.go +++ b/chain/gen/gen_test.go @@ -3,8 +3,8 @@ package gen import ( "testing" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 05c7b1273..d6523cc06 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -14,13 +14,13 @@ import ( "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/specs-actors/actors/builtin/multisig" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/build" diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 1c3f717ad..6322ff9a0 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -14,15 +14,15 @@ import ( "golang.org/x/xerrors" "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/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" - "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/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/reward" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/lotus/chain/store" diff --git a/chain/gen/genesis/t02_reward.go b/chain/gen/genesis/t02_reward.go index 2f5922fd3..d499b24d0 100644 --- a/chain/gen/genesis/t02_reward.go +++ b/chain/gen/genesis/t02_reward.go @@ -3,7 +3,7 @@ package genesis import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/reward" diff --git a/chain/gen/genesis/util.go b/chain/gen/genesis/util.go index 10081c763..67a4e9579 100644 --- a/chain/gen/genesis/util.go +++ b/chain/gen/genesis/util.go @@ -4,7 +4,7 @@ import ( "context" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" diff --git a/chain/gen/mining.go b/chain/gen/mining.go index 260c96808..dd867da48 100644 --- a/chain/gen/mining.go +++ b/chain/gen/mining.go @@ -3,7 +3,7 @@ package gen import ( "context" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" diff --git a/chain/gen/slashfilter/slashfilter.go b/chain/gen/slashfilter/slashfilter.go index 0d1940421..fadd3dd27 100644 --- a/chain/gen/slashfilter/slashfilter.go +++ b/chain/gen/slashfilter/slashfilter.go @@ -9,8 +9,8 @@ import ( ds "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" ) type SlashFilter struct { diff --git a/chain/market/fundmgr.go b/chain/market/fundmgr.go index f7eab7e0a..edf73d9bd 100644 --- a/chain/market/fundmgr.go +++ b/chain/market/fundmgr.go @@ -4,8 +4,8 @@ import ( "context" "sync" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "go.uber.org/fx" "github.com/filecoin-project/specs-actors/actors/builtin" diff --git a/chain/market/fundmgr_test.go b/chain/market/fundmgr_test.go index 5e8800528..c0e69c51c 100644 --- a/chain/market/fundmgr_test.go +++ b/chain/market/fundmgr_test.go @@ -10,9 +10,9 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" tutils "github.com/filecoin-project/specs-actors/support/testing" "github.com/filecoin-project/lotus/api" diff --git a/chain/messagepool/gasguess/guessgas.go b/chain/messagepool/gasguess/guessgas.go index a787b9053..af58db7d2 100644 --- a/chain/messagepool/gasguess/guessgas.go +++ b/chain/messagepool/gasguess/guessgas.go @@ -9,7 +9,7 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" ) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 621a67ae0..111ed2848 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -11,7 +11,7 @@ import ( "sync" "time" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" "github.com/ipfs/go-cid" diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index c97c03166..25a30ff66 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/mock" @@ -14,7 +15,6 @@ import ( _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" logging "github.com/ipfs/go-log/v2" diff --git a/chain/messagepool/repub_test.go b/chain/messagepool/repub_test.go index c89367f0e..491f484f5 100644 --- a/chain/messagepool/repub_test.go +++ b/chain/messagepool/repub_test.go @@ -4,10 +4,10 @@ import ( "testing" "time" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/ipfs/go-datastore" ) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 82d470360..5b9a09f35 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -9,11 +9,11 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + tbig "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" - abig "github.com/filecoin-project/specs-actors/actors/abi/big" ) var bigBlockGasLimit = big.NewInt(build.BlockGasLimit) @@ -592,7 +592,7 @@ func (*MessagePool) getGasReward(msg *types.SignedMessage, baseFee types.BigInt) maxPremium = msg.Message.GasPremium } - gasReward := abig.Mul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit))) + gasReward := tbig.Mul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit))) return gasReward.Int } diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index d9ed3af9c..2f9833ee2 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -9,13 +9,13 @@ import ( "testing" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" diff --git a/chain/metrics/consensus.go b/chain/metrics/consensus.go index 25e299247..c3c4a10d1 100644 --- a/chain/metrics/consensus.go +++ b/chain/metrics/consensus.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" pubsub "github.com/libp2p/go-libp2p-pubsub" diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index b21fb75f2..cb9ac6d6f 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/ipfs/go-cid" "go.opencensus.io/trace" "golang.org/x/xerrors" diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index c7c7526b3..0e6fe5122 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -3,8 +3,8 @@ package stmgr import ( "context" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" ) var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree) error{} diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index caa63c879..7b7671317 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/specs-actors/actors/builtin/miner" diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index e041fe088..60af40065 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -18,8 +18,8 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/reward" diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 17f84e18d..8b95f800a 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -4,6 +4,8 @@ import ( "bytes" "context" "fmt" + saruntime "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "os" "reflect" "runtime" @@ -16,8 +18,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/specs-actors/actors/builtin/cron" @@ -29,7 +32,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/reward" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" @@ -166,7 +168,7 @@ func MinerSectorInfo(ctx context.Context, sm *StateManager, maddr address.Addres return sectorInfo, nil } -func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { +func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address, filter *bitfield.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { var mas miner.State _, err := sm.LoadActorState(ctx, maddr, &mas, ts) if err != nil { @@ -176,8 +178,8 @@ func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors, filter, filterOut) } -func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]abi.SectorInfo, error) { - var partsProving []abi.BitField +func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *StateManager, st cid.Cid, maddr address.Address, rand abi.PoStRandomness) ([]proof.SectorInfo, error) { + var partsProving []bitfield.BitField var mas *miner.State var info *miner.MinerInfo @@ -264,7 +266,7 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S return nil, xerrors.Errorf("failed to load sectors amt: %w", err) } - out := make([]abi.SectorInfo, len(ids)) + out := make([]proof.SectorInfo, len(ids)) for i, n := range ids { sid := sectors[n] @@ -275,7 +277,7 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S return nil, xerrors.Errorf("failed to find sector %d", sid) } - out[i] = abi.SectorInfo{ + out[i] = proof.SectorInfo{ SealProof: spt, SectorNumber: sinfo.SectorNumber, SealedCID: sinfo.SealedCID, @@ -390,7 +392,7 @@ func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([ return miners, nil } -func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { +func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *bitfield.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { a, err := adt.AsArray(store.ActorStore(ctx, bs), ssc) if err != nil { return nil, err @@ -614,7 +616,7 @@ func init() { } for c, m := range cidToMethods { - exports := m[1].(abi.Invokee).Exports() + exports := m[1].(saruntime.Invokee).Exports() methods := make(map[abi.MethodNum]MethodMeta, len(exports)) // Explicitly add send, it's special. diff --git a/chain/store/basefee.go b/chain/store/basefee.go index de3f90a8f..9d6322639 100644 --- a/chain/store/basefee.go +++ b/chain/store/basefee.go @@ -3,10 +3,10 @@ package store import ( "context" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "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" "github.com/ipfs/go-cid" "golang.org/x/xerrors" ) diff --git a/chain/store/index.go b/chain/store/index.go index 8f3e88417..a9da994af 100644 --- a/chain/store/index.go +++ b/chain/store/index.go @@ -5,8 +5,8 @@ import ( "os" "strconv" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" lru "github.com/hashicorp/golang-lru" "golang.org/x/xerrors" ) diff --git a/chain/store/index_test.go b/chain/store/index_test.go index 5c49c6791..63e08070c 100644 --- a/chain/store/index_test.go +++ b/chain/store/index_test.go @@ -5,11 +5,11 @@ import ( "context" "testing" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/specs-actors/actors/abi" datastore "github.com/ipfs/go-datastore" syncds "github.com/ipfs/go-datastore/sync" "github.com/stretchr/testify/assert" diff --git a/chain/store/store.go b/chain/store/store.go index 4bfd20040..398828b1a 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -11,11 +11,11 @@ import ( "strconv" "sync" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/minio/blake2b-simd" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" diff --git a/chain/store/store_test.go b/chain/store/store_test.go index 42de4c19d..1e3673f44 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -7,12 +7,12 @@ import ( datastore "github.com/ipfs/go-datastore" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "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/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/store" diff --git a/chain/store/weight.go b/chain/store/weight.go index 2e8516f57..5249df011 100644 --- a/chain/store/weight.go +++ b/chain/store/weight.go @@ -4,10 +4,10 @@ import ( "context" "math/big" + big2 "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" - big2 "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/power" cbor "github.com/ipfs/go-ipld-cbor" diff --git a/chain/sync.go b/chain/sync.go index 0bcb290f8..b99e27be0 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "os" "sort" "strconv" @@ -25,11 +26,11 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" blst "github.com/supranational/blst/bindings/go" @@ -979,7 +980,7 @@ func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.Block return xerrors.Errorf("getting winning post sector set: %w", err) } - ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(ctx, abi.WinningPoStVerifyInfo{ + ok, err := ffiwrapper.ProofVerifier.VerifyWinningPoSt(ctx, proof.WinningPoStVerifyInfo{ Randomness: rand, Proofs: h.WinPoStProof, ChallengedSectors: sectors, diff --git a/chain/sync_test.go b/chain/sync_test.go index 0bd372fcc..63188d74c 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -3,6 +3,7 @@ package chain_test import ( "context" "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "os" "testing" "time" @@ -16,8 +17,8 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" @@ -445,8 +446,8 @@ func (wpp badWpp) GenerateCandidates(context.Context, abi.PoStRandomness, uint64 return []uint64{1}, nil } -func (wpp badWpp) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) { - return []abi.PoStProof{ +func (wpp badWpp) ComputeProof(context.Context, []proof.SectorInfo, abi.PoStRandomness) ([]proof.PoStProof, error) { + return []proof.PoStProof{ { PoStProof: abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, ProofBytes: []byte("evil"), diff --git a/chain/syncstate.go b/chain/syncstate.go index aaca88303..4dc193072 100644 --- a/chain/syncstate.go +++ b/chain/syncstate.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" diff --git a/chain/types/bigint.go b/chain/types/bigint.go index 466b9c556..da4857d5b 100644 --- a/chain/types/bigint.go +++ b/chain/types/bigint.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - big2 "github.com/filecoin-project/specs-actors/actors/abi/big" + big2 "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" ) diff --git a/chain/types/blockheader.go b/chain/types/blockheader.go index 36b43c012..8095616a5 100644 --- a/chain/types/blockheader.go +++ b/chain/types/blockheader.go @@ -2,12 +2,13 @@ package types import ( "bytes" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "math/big" "github.com/minio/blake2b-simd" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" @@ -53,7 +54,7 @@ type BlockHeader struct { BeaconEntries []BeaconEntry // 3 - WinPoStProof []abi.PoStProof // 4 + WinPoStProof []proof.PoStProof // 4 Parents []cid.Cid // 5 diff --git a/chain/types/blockheader_test.go b/chain/types/blockheader_test.go index e4b545cca..4607e5b3e 100644 --- a/chain/types/blockheader_test.go +++ b/chain/types/blockheader_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" ) func testBlockHeader(t testing.TB) *BlockHeader { @@ -80,7 +80,7 @@ func TestInteropBH(t *testing.T) { t.Fatal(err) } - posts := []abi.PoStProof{ + posts := []proof.PoStProof{ {PoStProof: abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, ProofBytes: []byte{0x07}}, } diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index 35abf2828..676ae7054 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -6,9 +6,10 @@ import ( "fmt" "io" - abi "github.com/filecoin-project/specs-actors/actors/abi" - crypto "github.com/filecoin-project/specs-actors/actors/crypto" - exitcode "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + abi "github.com/filecoin-project/go-state-types/abi" + crypto "github.com/filecoin-project/go-state-types/crypto" + exitcode "github.com/filecoin-project/go-state-types/exitcode" + proof "github.com/filecoin-project/specs-actors/actors/runtime/proof" cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" @@ -58,7 +59,7 @@ func (t *BlockHeader) MarshalCBOR(w io.Writer) error { } } - // t.WinPoStProof ([]abi.PoStProof) (slice) + // t.WinPoStProof ([]proof.PoStProof) (slice) if len(t.WinPoStProof) > cbg.MaxLength { return xerrors.Errorf("Slice value in field t.WinPoStProof was too long") } @@ -243,7 +244,7 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error { t.BeaconEntries[i] = v } - // t.WinPoStProof ([]abi.PoStProof) (slice) + // t.WinPoStProof ([]proof.PoStProof) (slice) maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) if err != nil { @@ -259,12 +260,12 @@ func (t *BlockHeader) UnmarshalCBOR(r io.Reader) error { } if extra > 0 { - t.WinPoStProof = make([]abi.PoStProof, extra) + t.WinPoStProof = make([]proof.PoStProof, extra) } for i := 0; i < int(extra); i++ { - var v abi.PoStProof + var v proof.PoStProof if err := v.UnmarshalCBOR(br); err != nil { return err } diff --git a/chain/types/message.go b/chain/types/message.go index 288fcf6d9..4fead44bc 100644 --- a/chain/types/message.go +++ b/chain/types/message.go @@ -4,9 +4,9 @@ import ( "bytes" "fmt" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" xerrors "golang.org/x/xerrors" diff --git a/chain/types/message_receipt.go b/chain/types/message_receipt.go index 6671595ff..57761680d 100644 --- a/chain/types/message_receipt.go +++ b/chain/types/message_receipt.go @@ -3,7 +3,7 @@ package types import ( "bytes" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/go-state-types/exitcode" ) type MessageReceipt struct { diff --git a/chain/types/message_test.go b/chain/types/message_test.go index a7b4927e5..f57385a09 100644 --- a/chain/types/message_test.go +++ b/chain/types/message_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" ) diff --git a/chain/types/mock/chain.go b/chain/types/mock/chain.go index b535f203a..559630619 100644 --- a/chain/types/mock/chain.go +++ b/chain/types/mock/chain.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/build" diff --git a/chain/types/signature_test.go b/chain/types/signature_test.go index 751f55252..9ade3c046 100644 --- a/chain/types/signature_test.go +++ b/chain/types/signature_test.go @@ -4,7 +4,7 @@ import ( "bytes" "testing" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" ) func TestSignatureSerializeRoundTrip(t *testing.T) { diff --git a/chain/types/signedmessage.go b/chain/types/signedmessage.go index 47592feb1..17d2f5d94 100644 --- a/chain/types/signedmessage.go +++ b/chain/types/signedmessage.go @@ -3,8 +3,8 @@ package types import ( "bytes" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" ) diff --git a/chain/types/tipset.go b/chain/types/tipset.go index 4217d2a86..44d41c29d 100644 --- a/chain/types/tipset.go +++ b/chain/types/tipset.go @@ -7,7 +7,7 @@ import ( "io" "sort" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "github.com/minio/blake2b-simd" diff --git a/chain/types/tipset_key.go b/chain/types/tipset_key.go index ee1994f5a..e5bc7750d 100644 --- a/chain/types/tipset_key.go +++ b/chain/types/tipset_key.go @@ -5,7 +5,7 @@ import ( "encoding/json" "strings" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" ) diff --git a/chain/vectors/gen/main.go b/chain/vectors/gen/main.go index ce8d137e8..814bcebff 100644 --- a/chain/vectors/gen/main.go +++ b/chain/vectors/gen/main.go @@ -9,16 +9,15 @@ import ( "github.com/filecoin-project/go-address" "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/chain/vectors" "github.com/filecoin-project/lotus/chain/wallet" - "github.com/filecoin-project/specs-actors/actors/abi" - "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/verifreg" - "github.com/filecoin-project/specs-actors/actors/crypto" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" diff --git a/chain/vectors/vector_types.go b/chain/vectors/vector_types.go index 73216a049..7e014fb77 100644 --- a/chain/vectors/vector_types.go +++ b/chain/vectors/vector_types.go @@ -1,8 +1,8 @@ package vectors import ( + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/crypto" ) type HeaderVector struct { diff --git a/chain/vm/burn.go b/chain/vm/burn.go index e9b6802c1..eb0611349 100644 --- a/chain/vm/burn.go +++ b/chain/vm/burn.go @@ -1,8 +1,8 @@ package vm import ( - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" ) const ( diff --git a/chain/vm/gas.go b/chain/vm/gas.go index 72a7df8fc..23750491c 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -2,11 +2,12 @@ package vm import ( "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/filecoin-project/go-address" addr "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" vmr "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/ipfs/go-cid" @@ -77,8 +78,8 @@ type Pricelist interface { OnVerifySignature(sigType crypto.SigType, planTextSize int) (GasCharge, error) OnHashing(dataSize int) GasCharge OnComputeUnsealedSectorCid(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) GasCharge - OnVerifySeal(info abi.SealVerifyInfo) GasCharge - OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge + OnVerifySeal(info proof.SealVerifyInfo) GasCharge + OnVerifyPost(info proof.WindowPoStVerifyInfo) GasCharge OnVerifyConsensusFault() GasCharge } @@ -183,7 +184,7 @@ func (ps pricedSyscalls) ComputeUnsealedSectorCID(reg abi.RegisteredSealProof, p } // Verifies a sector seal proof. -func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error { +func (ps pricedSyscalls) VerifySeal(vi proof.SealVerifyInfo) error { ps.chargeGas(ps.pl.OnVerifySeal(vi)) defer ps.chargeGas(gasOnActorExec) @@ -191,7 +192,7 @@ func (ps pricedSyscalls) VerifySeal(vi abi.SealVerifyInfo) error { } // Verifies a proof of spacetime. -func (ps pricedSyscalls) VerifyPoSt(vi abi.WindowPoStVerifyInfo) error { +func (ps pricedSyscalls) VerifyPoSt(vi proof.WindowPoStVerifyInfo) error { ps.chargeGas(ps.pl.OnVerifyPost(vi)) defer ps.chargeGas(gasOnActorExec) @@ -215,7 +216,7 @@ func (ps pricedSyscalls) VerifyConsensusFault(h1 []byte, h2 []byte, extra []byte return ps.under.VerifyConsensusFault(h1, h2, extra) } -func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) { +func (ps pricedSyscalls) BatchVerifySeals(inp map[address.Address][]proof.SealVerifyInfo) (map[address.Address][]bool, error) { count := int64(0) for _, svis := range inp { count += int64(len(svis)) diff --git a/chain/vm/gas_v0.go b/chain/vm/gas_v0.go index f13710a1b..3d2faa60d 100644 --- a/chain/vm/gas_v0.go +++ b/chain/vm/gas_v0.go @@ -2,11 +2,12 @@ package vm import ( "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" ) type scalingCost struct { @@ -173,14 +174,14 @@ func (pl *pricelistV0) OnComputeUnsealedSectorCid(proofType abi.RegisteredSealPr } // OnVerifySeal -func (pl *pricelistV0) OnVerifySeal(info abi.SealVerifyInfo) GasCharge { +func (pl *pricelistV0) OnVerifySeal(info proof.SealVerifyInfo) GasCharge { // TODO: this needs more cost tunning, check with @lotus // this is not used return newGasCharge("OnVerifySeal", pl.verifySealBase, 0) } // OnVerifyPost -func (pl *pricelistV0) OnVerifyPost(info abi.WindowPoStVerifyInfo) GasCharge { +func (pl *pricelistV0) OnVerifyPost(info proof.WindowPoStVerifyInfo) GasCharge { sectorSize := "unknown" var proofType abi.RegisteredPoStProof diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 5b299cfef..2ec56a9db 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -6,15 +6,15 @@ import ( "fmt" "reflect" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/cron" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" diff --git a/chain/vm/invoker_test.go b/chain/vm/invoker_test.go index 55b276421..d19321c99 100644 --- a/chain/vm/invoker_test.go +++ b/chain/vm/invoker_test.go @@ -9,10 +9,10 @@ import ( "github.com/stretchr/testify/assert" cbg "github.com/whyrusleeping/cbor-gen" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/aerrors" "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-actors/actors/util/adt" ) diff --git a/chain/vm/mkactor.go b/chain/vm/mkactor.go index ef4382df1..43d2f9431 100644 --- a/chain/vm/mkactor.go +++ b/chain/vm/mkactor.go @@ -3,10 +3,10 @@ package vm import ( "context" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index fd13c704e..b353bcb34 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -9,13 +9,13 @@ import ( "time" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" vmr "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" diff --git a/chain/vm/runtime_test.go b/chain/vm/runtime_test.go index b5c75c177..2f9704394 100644 --- a/chain/vm/runtime_test.go +++ b/chain/vm/runtime_test.go @@ -8,7 +8,7 @@ import ( cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/chain/actors/aerrors" ) diff --git a/chain/vm/syscalls.go b/chain/vm/syscalls.go index 41ed9c762..9dba55131 100644 --- a/chain/vm/syscalls.go +++ b/chain/vm/syscalls.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" goruntime "runtime" "sync" @@ -14,12 +15,12 @@ import ( mh "github.com/multiformats/go-multihash" "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/sigs" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/specs-actors/actors/util/adt" @@ -213,7 +214,7 @@ func (ss *syscallShim) VerifyBlockSig(blk *types.BlockHeader) error { return nil } -func (ss *syscallShim) VerifyPoSt(proof abi.WindowPoStVerifyInfo) error { +func (ss *syscallShim) VerifyPoSt(proof proof.WindowPoStVerifyInfo) error { ok, err := ss.verifier.VerifyWindowPoSt(context.TODO(), proof) if err != nil { return err @@ -224,7 +225,7 @@ func (ss *syscallShim) VerifyPoSt(proof abi.WindowPoStVerifyInfo) error { return nil } -func (ss *syscallShim) VerifySeal(info abi.SealVerifyInfo) error { +func (ss *syscallShim) VerifySeal(info proof.SealVerifyInfo) error { //_, span := trace.StartSpan(ctx, "ValidatePoRep") //defer span.End() @@ -264,7 +265,7 @@ func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Addres var BatchSealVerifyParallelism = goruntime.NumCPU() -func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerifyInfo) (map[address.Address][]bool, error) { +func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]proof.SealVerifyInfo) (map[address.Address][]bool, error) { out := make(map[address.Address][]bool) sema := make(chan struct{}, BatchSealVerifyParallelism) @@ -276,7 +277,7 @@ func (ss *syscallShim) BatchVerifySeals(inp map[address.Address][]abi.SealVerify for i, s := range seals { wg.Add(1) - go func(ma address.Address, ix int, svi abi.SealVerifyInfo, res []bool) { + go func(ma address.Address, ix int, svi proof.SealVerifyInfo, res []bool) { defer wg.Done() sema <- struct{}{} diff --git a/chain/vm/vm.go b/chain/vm/vm.go index ea18a7c43..92a50c5cd 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -9,7 +9,7 @@ import ( bstore "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" block "github.com/ipfs/go-block-format" @@ -22,10 +22,10 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors/aerrors" diff --git a/chain/wallet/wallet.go b/chain/wallet/wallet.go index 9c069d819..7cdb1929e 100644 --- a/chain/wallet/wallet.go +++ b/chain/wallet/wallet.go @@ -6,7 +6,7 @@ import ( "strings" "sync" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" logging "github.com/ipfs/go-log/v2" "golang.org/x/xerrors" diff --git a/cli/chain.go b/cli/chain.go index 1d203639a..d00247364 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -14,8 +14,8 @@ import ( "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/specs-actors/actors/builtin/market" diff --git a/cli/client.go b/cli/client.go index 17b24ba6a..e68f98791 100644 --- a/cli/client.go +++ b/cli/client.go @@ -27,8 +27,8 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-multistore" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/lotus/api" diff --git a/cli/mpool.go b/cli/mpool.go index 587246b87..6e335a243 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -10,7 +10,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/types" ) diff --git a/cli/multisig.go b/cli/multisig.go index 57f6c2c03..576591b6c 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -11,7 +11,7 @@ import ( "strconv" "text/tabwriter" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/util/adt" diff --git a/cli/paych_test.go b/cli/paych_test.go index 9b21d8070..cccc80ff4 100644 --- a/cli/paych_test.go +++ b/cli/paych_test.go @@ -14,7 +14,7 @@ import ( "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" @@ -30,10 +30,10 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api/test" "github.com/filecoin-project/lotus/chain/wallet" builder "github.com/filecoin-project/lotus/node/test" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/stretchr/testify/require" "github.com/urfave/cli/v2" ) diff --git a/cli/send.go b/cli/send.go index d06767241..14c1b263b 100644 --- a/cli/send.go +++ b/cli/send.go @@ -12,7 +12,7 @@ import ( cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/stmgr" diff --git a/cli/state.go b/cli/state.go index a5c11cde6..8ae8bf540 100644 --- a/cli/state.go +++ b/cli/state.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime" "html/template" "io" "os" @@ -24,10 +25,10 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/exported" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -1446,7 +1447,7 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er return nil, nil } - var target abi.Invokee + var target runtime.Invokee for _, actor := range exported.BuiltinActors() { if actor.Code() == act { target = actor diff --git a/cli/sync.go b/cli/sync.go index 27957ac35..24abfc0a1 100644 --- a/cli/sync.go +++ b/cli/sync.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" cid "github.com/ipfs/go-cid" "github.com/urfave/cli/v2" diff --git a/cli/wallet.go b/cli/wallet.go index 025e3a7b6..4339a1fb6 100644 --- a/cli/wallet.go +++ b/cli/wallet.go @@ -10,9 +10,9 @@ import ( "strings" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" types "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" - "github.com/filecoin-project/specs-actors/actors/crypto" "golang.org/x/xerrors" "github.com/urfave/cli/v2" diff --git a/cmd/chain-noise/main.go b/cmd/chain-noise/main.go index 9e9ac2e49..7b9824016 100644 --- a/cmd/chain-noise/main.go +++ b/cmd/chain-noise/main.go @@ -7,7 +7,7 @@ import ( "os" "time" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" diff --git a/cmd/lotus-bench/import.go b/cmd/lotus-bench/import.go index 7400cd92e..7fe63eae1 100644 --- a/cmd/lotus-bench/import.go +++ b/cmd/lotus-bench/import.go @@ -25,8 +25,8 @@ import ( _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/ipfs/go-datastore" badger "github.com/ipfs/go-ds-badger2" diff --git a/cmd/lotus-bench/main.go b/cmd/lotus-bench/main.go index 694987f27..8545bfbd3 100644 --- a/cmd/lotus-bench/main.go +++ b/cmd/lotus-bench/main.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "io/ioutil" "math/big" "math/rand" @@ -20,11 +21,11 @@ import ( "github.com/filecoin-project/go-address" paramfetch "github.com/filecoin-project/go-paramfetch" + "github.com/filecoin-project/go-state-types/abi" lcli "github.com/filecoin-project/lotus/cli" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper/basicfs" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" @@ -235,7 +236,7 @@ var sealBenchCmd = &cli.Command{ } var sealTimings []SealingResult - var sealedSectors []abi.SectorInfo + var sealedSectors []proof.SectorInfo if robench == "" { var err error @@ -278,7 +279,7 @@ var sealBenchCmd = &cli.Command{ } for _, s := range genm.Sectors { - sealedSectors = append(sealedSectors, abi.SectorInfo{ + sealedSectors = append(sealedSectors, proof.SectorInfo{ SealedCID: s.CommR, SectorNumber: s.SectorID, SealProof: s.ProofType, @@ -303,7 +304,7 @@ var sealBenchCmd = &cli.Command{ return err } - candidates := make([]abi.SectorInfo, len(fcandidates)) + candidates := make([]proof.SectorInfo, len(fcandidates)) for i, fcandidate := range fcandidates { candidates[i] = sealedSectors[fcandidate] } @@ -374,7 +375,7 @@ var sealBenchCmd = &cli.Command{ windowpost2 := time.Now() - wpvi1 := abi.WindowPoStVerifyInfo{ + wpvi1 := proof.WindowPoStVerifyInfo{ Randomness: challenge[:], Proofs: wproof1, ChallengedSectors: sealedSectors, @@ -390,7 +391,7 @@ var sealBenchCmd = &cli.Command{ verifyWindowpost1 := time.Now() - wpvi2 := abi.WindowPoStVerifyInfo{ + wpvi2 := proof.WindowPoStVerifyInfo{ Randomness: challenge[:], Proofs: wproof2, ChallengedSectors: sealedSectors, @@ -462,10 +463,10 @@ type ParCfg struct { Commit int } -func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par ParCfg, mid abi.ActorID, sectorSize abi.SectorSize, ticketPreimage []byte, saveC2inp string, skipc2, skipunseal bool) ([]SealingResult, []abi.SectorInfo, error) { +func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par ParCfg, mid abi.ActorID, sectorSize abi.SectorSize, ticketPreimage []byte, saveC2inp string, skipc2, skipunseal bool) ([]SealingResult, []proof.SectorInfo, error) { var pieces []abi.PieceInfo sealTimings := make([]SealingResult, numSectors) - sealedSectors := make([]abi.SectorInfo, numSectors) + sealedSectors := make([]proof.SectorInfo, numSectors) preCommit2Sema := make(chan struct{}, par.PreCommit2) commitSema := make(chan struct{}, par.Commit) @@ -535,7 +536,7 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par precommit2 := time.Now() <-preCommit2Sema - sealedSectors[ix] = abi.SectorInfo{ + sealedSectors[ix] = proof.SectorInfo{ SealProof: sb.SealProofType(), SectorNumber: i, SealedCID: cids.Sealed, @@ -587,7 +588,7 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par <-commitSema if !skipc2 { - svi := abi.SealVerifyInfo{ + svi := proof.SealVerifyInfo{ SectorID: abi.SectorID{Miner: mid, Number: i}, SealedCID: cids.Sealed, SealProof: sb.SealProofType(), diff --git a/cmd/lotus-chainwatch/processor/miner.go b/cmd/lotus-chainwatch/processor/miner.go index 13f637237..1442a84bc 100644 --- a/cmd/lotus-chainwatch/processor/miner.go +++ b/cmd/lotus-chainwatch/processor/miner.go @@ -13,8 +13,8 @@ import ( "golang.org/x/sync/errgroup" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" @@ -168,11 +168,11 @@ type SectorDealEvent struct { } type PartitionStatus struct { - Terminated abi.BitField - Expired abi.BitField - Faulted abi.BitField - InRecovery abi.BitField - Recovered abi.BitField + Terminated bitfield.BitField + Expired bitfield.BitField + Faulted bitfield.BitField + InRecovery bitfield.BitField + Recovered bitfield.BitField } type minerActorInfo struct { @@ -819,7 +819,7 @@ func (p *Processor) diffPartition(prevPart, curPart miner.Partition) (*Partition } expired := bitfield.New() - var bf abi.BitField + var bf bitfield.BitField if err := terminatedEarlyArr.ForEach(&bf, func(i int64) error { // expired = all removals - termination expirations, err := bitfield.SubtractBitField(allRemovedSectors, bf) diff --git a/cmd/lotus-chainwatch/processor/power.go b/cmd/lotus-chainwatch/processor/power.go index 6fa03e943..dfd7eddd7 100644 --- a/cmd/lotus-chainwatch/processor/power.go +++ b/cmd/lotus-chainwatch/processor/power.go @@ -7,7 +7,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/util/smoothing" diff --git a/cmd/lotus-chainwatch/processor/processor.go b/cmd/lotus-chainwatch/processor/processor.go index e6c2ffb94..bce2b9fb7 100644 --- a/cmd/lotus-chainwatch/processor/processor.go +++ b/cmd/lotus-chainwatch/processor/processor.go @@ -14,7 +14,7 @@ import ( "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/lotus/api" diff --git a/cmd/lotus-chainwatch/processor/reward.go b/cmd/lotus-chainwatch/processor/reward.go index 7068c1a93..5bdb478df 100644 --- a/cmd/lotus-chainwatch/processor/reward.go +++ b/cmd/lotus-chainwatch/processor/reward.go @@ -7,7 +7,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/reward" "github.com/filecoin-project/specs-actors/actors/util/smoothing" diff --git a/cmd/lotus-keygen/main.go b/cmd/lotus-keygen/main.go index 33124107e..8e2881ae9 100644 --- a/cmd/lotus-keygen/main.go +++ b/cmd/lotus-keygen/main.go @@ -5,10 +5,10 @@ import ( "fmt" "os" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/wallet" _ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "github.com/filecoin-project/lotus/lib/sigs/secp" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/urfave/cli/v2" ) diff --git a/cmd/lotus-pcr/main.go b/cmd/lotus-pcr/main.go index a5242bf28..dc12693ca 100644 --- a/cmd/lotus-pcr/main.go +++ b/cmd/lotus-pcr/main.go @@ -20,11 +20,11 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" diff --git a/cmd/lotus-seed/genesis.go b/cmd/lotus-seed/genesis.go index f2bff4d6e..bbaea6969 100644 --- a/cmd/lotus-seed/genesis.go +++ b/cmd/lotus-seed/genesis.go @@ -15,8 +15,8 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/gen" diff --git a/cmd/lotus-seed/main.go b/cmd/lotus-seed/main.go index 48691d5ec..d365f6493 100644 --- a/cmd/lotus-seed/main.go +++ b/cmd/lotus-seed/main.go @@ -15,8 +15,8 @@ import ( "github.com/urfave/cli/v2" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" diff --git a/cmd/lotus-seed/seed/seed.go b/cmd/lotus-seed/seed/seed.go index f892709f6..5e911991d 100644 --- a/cmd/lotus-seed/seed/seed.go +++ b/cmd/lotus-seed/seed/seed.go @@ -19,11 +19,11 @@ import ( ffi "github.com/filecoin-project/filecoin-ffi" "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/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/zerocomm" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" diff --git a/cmd/lotus-shed/genesis-verify.go b/cmd/lotus-shed/genesis-verify.go index 4ab6458a9..043cb72bb 100644 --- a/cmd/lotus-shed/genesis-verify.go +++ b/cmd/lotus-shed/genesis-verify.go @@ -13,13 +13,13 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin" saacc "github.com/filecoin-project/specs-actors/actors/builtin/account" saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" diff --git a/cmd/lotus-shed/proofs.go b/cmd/lotus-shed/proofs.go index f18dc93fb..1b877d4ea 100644 --- a/cmd/lotus-shed/proofs.go +++ b/cmd/lotus-shed/proofs.go @@ -8,7 +8,7 @@ import ( ffi "github.com/filecoin-project/filecoin-ffi" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" ) @@ -82,7 +82,7 @@ var verifySealProofCmd = &cli.Command{ snum := abi.SectorNumber(cctx.Uint64("sector-id")) - ok, err := ffi.VerifySeal(abi.SealVerifyInfo{ + ok, err := ffi.VerifySeal(proof.SealVerifyInfo{ SectorID: abi.SectorID{ Miner: abi.ActorID(mid), Number: snum, diff --git a/cmd/lotus-storage-miner/actor.go b/cmd/lotus-storage-miner/actor.go index e69a338ab..c84e006d7 100644 --- a/cmd/lotus-storage-miner/actor.go +++ b/cmd/lotus-storage-miner/actor.go @@ -12,8 +12,8 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" diff --git a/cmd/lotus-storage-miner/info.go b/cmd/lotus-storage-miner/info.go index dbb93c972..55ef024f3 100644 --- a/cmd/lotus-storage-miner/info.go +++ b/cmd/lotus-storage-miner/info.go @@ -14,8 +14,8 @@ import ( cbor "github.com/ipfs/go-ipld-cbor" "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/util/adt" diff --git a/cmd/lotus-storage-miner/init.go b/cmd/lotus-storage-miner/init.go index 01569d5e9..9fbdcb8d4 100644 --- a/cmd/lotus-storage-miner/init.go +++ b/cmd/lotus-storage-miner/init.go @@ -12,7 +12,7 @@ import ( "path/filepath" "strconv" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/docker/go-units" "github.com/google/uuid" @@ -26,15 +26,15 @@ import ( "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" paramfetch "github.com/filecoin-project/go-paramfetch" + "github.com/filecoin-project/go-state-types/abi" + crypto2 "github.com/filecoin-project/go-state-types/crypto" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/market" miner2 "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" - crypto2 "github.com/filecoin-project/specs-actors/actors/crypto" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" diff --git a/cmd/lotus-storage-miner/market.go b/cmd/lotus-storage-miner/market.go index 39671f74c..1c9eac1b7 100644 --- a/cmd/lotus-storage-miner/market.go +++ b/cmd/lotus-storage-miner/market.go @@ -20,7 +20,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" diff --git a/cmd/lotus-storage-miner/proving.go b/cmd/lotus-storage-miner/proving.go index 502edb57b..b5087556d 100644 --- a/cmd/lotus-storage-miner/proving.go +++ b/cmd/lotus-storage-miner/proving.go @@ -11,7 +11,7 @@ import ( "github.com/urfave/cli/v2" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/build" diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index 8bd8ff6a5..06f09fe20 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -13,7 +13,7 @@ import ( "github.com/urfave/cli/v2" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" diff --git a/cmd/lotus-storage-miner/storage.go b/cmd/lotus-storage-miner/storage.go index 7fadcf83f..71d88de6d 100644 --- a/cmd/lotus-storage-miner/storage.go +++ b/cmd/lotus-storage-miner/storage.go @@ -18,9 +18,9 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" diff --git a/cmd/lotus/debug_advance.go b/cmd/lotus/debug_advance.go index 699182472..73eab49fc 100644 --- a/cmd/lotus/debug_advance.go +++ b/cmd/lotus/debug_advance.go @@ -7,12 +7,12 @@ import ( "time" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/crypto" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" - "github.com/filecoin-project/specs-actors/actors/crypto" "golang.org/x/xerrors" "github.com/urfave/cli/v2" diff --git a/conformance/driver.go b/conformance/driver.go index 218198a05..b6a61dac0 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -3,7 +3,7 @@ package conformance import ( "context" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" @@ -12,7 +12,7 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/test-vectors/chaos" "github.com/filecoin-project/test-vectors/schema" diff --git a/conformance/stubs.go b/conformance/stubs.go index 2fd1e7b64..5383a51f0 100644 --- a/conformance/stubs.go +++ b/conformance/stubs.go @@ -2,13 +2,14 @@ package conformance import ( "context" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/vm" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" cbor "github.com/ipfs/go-ipld-cbor" @@ -36,12 +37,12 @@ func (fss *testSyscalls) VerifySignature(_ crypto.Signature, _ address.Address, } // TODO VerifySeal this will always succeed; but we want to be able to test failures too. -func (fss *testSyscalls) VerifySeal(_ abi.SealVerifyInfo) error { +func (fss *testSyscalls) VerifySeal(_ proof.SealVerifyInfo) error { return nil } // TODO VerifyPoSt this will always succeed; but we want to be able to test failures too. -func (fss *testSyscalls) VerifyPoSt(_ abi.WindowPoStVerifyInfo) error { +func (fss *testSyscalls) VerifyPoSt(_ proof.WindowPoStVerifyInfo) error { return nil } diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 777a6fbf4..405691046 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 777a6fbf4446b1112adfd4fa5dd88e0c88974122 +Subproject commit 40569104603407c999d6c9e4c3f1228cbd4d0e5c diff --git a/extern/sector-storage/faults.go b/extern/sector-storage/faults.go index 06c823bb8..31a1a3690 100644 --- a/extern/sector-storage/faults.go +++ b/extern/sector-storage/faults.go @@ -8,8 +8,8 @@ import ( "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/abi" ) // FaultTracker TODO: Track things more actively diff --git a/extern/sector-storage/ffiwrapper/basicfs/fs.go b/extern/sector-storage/ffiwrapper/basicfs/fs.go index ae17273e9..00aa49b98 100644 --- a/extern/sector-storage/ffiwrapper/basicfs/fs.go +++ b/extern/sector-storage/ffiwrapper/basicfs/fs.go @@ -6,7 +6,7 @@ import ( "path/filepath" "sync" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/stores" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" diff --git a/extern/sector-storage/ffiwrapper/config.go b/extern/sector-storage/ffiwrapper/config.go index 707fc6746..ca32b1191 100644 --- a/extern/sector-storage/ffiwrapper/config.go +++ b/extern/sector-storage/ffiwrapper/config.go @@ -3,7 +3,7 @@ package ffiwrapper import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) type Config struct { diff --git a/extern/sector-storage/ffiwrapper/partialfile.go b/extern/sector-storage/ffiwrapper/partialfile.go index 597e33105..e19930ac1 100644 --- a/extern/sector-storage/ffiwrapper/partialfile.go +++ b/extern/sector-storage/ffiwrapper/partialfile.go @@ -10,7 +10,7 @@ import ( "golang.org/x/xerrors" rlepluslazy "github.com/filecoin-project/go-bitfield/rle" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" diff --git a/extern/sector-storage/ffiwrapper/sealer.go b/extern/sector-storage/ffiwrapper/sealer.go index c97557a37..c1b558d9a 100644 --- a/extern/sector-storage/ffiwrapper/sealer.go +++ b/extern/sector-storage/ffiwrapper/sealer.go @@ -1,7 +1,7 @@ package ffiwrapper import ( - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" logging "github.com/ipfs/go-log/v2" ) diff --git a/extern/sector-storage/ffiwrapper/sealer_cgo.go b/extern/sector-storage/ffiwrapper/sealer_cgo.go index d4f796dcb..9ab9bd5a6 100644 --- a/extern/sector-storage/ffiwrapper/sealer_cgo.go +++ b/extern/sector-storage/ffiwrapper/sealer_cgo.go @@ -17,7 +17,7 @@ import ( ffi "github.com/filecoin-project/filecoin-ffi" rlepluslazy "github.com/filecoin-project/go-bitfield/rle" commcid "github.com/filecoin-project/go-fil-commcid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/fr32" diff --git a/extern/sector-storage/ffiwrapper/sealer_test.go b/extern/sector-storage/ffiwrapper/sealer_test.go index b484b391f..d089a92b6 100644 --- a/extern/sector-storage/ffiwrapper/sealer_test.go +++ b/extern/sector-storage/ffiwrapper/sealer_test.go @@ -22,7 +22,7 @@ import ( "golang.org/x/xerrors" paramfetch "github.com/filecoin-project/go-paramfetch" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" ffi "github.com/filecoin-project/filecoin-ffi" @@ -91,7 +91,7 @@ func (s *seal) commit(t *testing.T, sb *Sealer, done func()) { t.Fatalf("%+v", err) } - ok, err := ProofVerifier.VerifySeal(abi.SealVerifyInfo{ + ok, err := ProofVerifier.VerifySeal(proof.SealVerifyInfo{ SectorID: s.id, SealedCID: s.cids.Sealed, SealProof: sealProofType, diff --git a/extern/sector-storage/ffiwrapper/types.go b/extern/sector-storage/ffiwrapper/types.go index a634134ee..daf5cdbff 100644 --- a/extern/sector-storage/ffiwrapper/types.go +++ b/extern/sector-storage/ffiwrapper/types.go @@ -2,11 +2,12 @@ package ffiwrapper import ( "context" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "io" "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper/basicfs" @@ -33,9 +34,9 @@ type Storage interface { } type Verifier interface { - VerifySeal(abi.SealVerifyInfo) (bool, error) - VerifyWinningPoSt(ctx context.Context, info abi.WinningPoStVerifyInfo) (bool, error) - VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVerifyInfo) (bool, error) + VerifySeal(proof.SealVerifyInfo) (bool, error) + VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) + VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) GenerateWinningPoStSectorChallenge(context.Context, abi.RegisteredPoStProof, abi.ActorID, abi.PoStRandomness, uint64) ([]uint64, error) } diff --git a/extern/sector-storage/ffiwrapper/unseal_ranges.go b/extern/sector-storage/ffiwrapper/unseal_ranges.go index 2e5119994..4519fc21e 100644 --- a/extern/sector-storage/ffiwrapper/unseal_ranges.go +++ b/extern/sector-storage/ffiwrapper/unseal_ranges.go @@ -5,7 +5,7 @@ import ( rlepluslazy "github.com/filecoin-project/go-bitfield/rle" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" ) diff --git a/extern/sector-storage/ffiwrapper/verifier_cgo.go b/extern/sector-storage/ffiwrapper/verifier_cgo.go index de6fc0849..bd4e7e021 100644 --- a/extern/sector-storage/ffiwrapper/verifier_cgo.go +++ b/extern/sector-storage/ffiwrapper/verifier_cgo.go @@ -4,10 +4,11 @@ package ffiwrapper import ( "context" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ffi "github.com/filecoin-project/filecoin-ffi" @@ -16,7 +17,7 @@ import ( "go.opencensus.io/trace" ) -func (sb *Sealer) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) ([]abi.PoStProof, error) { +func (sb *Sealer) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, error) { randomness[31] &= 0x3f privsectors, skipped, done, err := sb.pubSectorToPriv(ctx, minerID, sectorInfo, nil, abi.RegisteredSealProof.RegisteredWinningPoStProof) // TODO: FAULTS? if err != nil { @@ -30,7 +31,7 @@ func (sb *Sealer) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, return ffi.GenerateWinningPoSt(minerID, privsectors, randomness) } -func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) ([]abi.PoStProof, []abi.SectorID, error) { +func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) { randomness[31] &= 0x3f privsectors, skipped, done, err := sb.pubSectorToPriv(ctx, minerID, sectorInfo, nil, abi.RegisteredSealProof.RegisteredWindowPoStProof) if err != nil { @@ -42,7 +43,7 @@ func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, s return proof, skipped, err } -func (sb *Sealer) pubSectorToPriv(ctx context.Context, mid abi.ActorID, sectorInfo []abi.SectorInfo, faults []abi.SectorNumber, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error)) (ffi.SortedPrivateSectorInfo, []abi.SectorID, func(), error) { +func (sb *Sealer) pubSectorToPriv(ctx context.Context, mid abi.ActorID, sectorInfo []proof.SectorInfo, faults []abi.SectorNumber, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error)) (ffi.SortedPrivateSectorInfo, []abi.SectorID, func(), error) { fmap := map[abi.SectorNumber]struct{}{} for _, fault := range faults { fmap[fault] = struct{}{} @@ -95,11 +96,11 @@ type proofVerifier struct{} var ProofVerifier = proofVerifier{} -func (proofVerifier) VerifySeal(info abi.SealVerifyInfo) (bool, error) { +func (proofVerifier) VerifySeal(info proof.SealVerifyInfo) (bool, error) { return ffi.VerifySeal(info) } -func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info abi.WinningPoStVerifyInfo) (bool, error) { +func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) { info.Randomness[31] &= 0x3f _, span := trace.StartSpan(ctx, "VerifyWinningPoSt") defer span.End() @@ -107,7 +108,7 @@ func (proofVerifier) VerifyWinningPoSt(ctx context.Context, info abi.WinningPoSt return ffi.VerifyWinningPoSt(info) } -func (proofVerifier) VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVerifyInfo) (bool, error) { +func (proofVerifier) VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) { info.Randomness[31] &= 0x3f _, span := trace.StartSpan(ctx, "VerifyWindowPoSt") defer span.End() diff --git a/extern/sector-storage/fr32/fr32.go b/extern/sector-storage/fr32/fr32.go index b7248db7e..17e6a1142 100644 --- a/extern/sector-storage/fr32/fr32.go +++ b/extern/sector-storage/fr32/fr32.go @@ -5,7 +5,7 @@ import ( "runtime" "sync" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) var MTTresh = uint64(32 << 20) diff --git a/extern/sector-storage/fr32/fr32_ffi_cmp_test.go b/extern/sector-storage/fr32/fr32_ffi_cmp_test.go index 2a602424a..3d5679095 100644 --- a/extern/sector-storage/fr32/fr32_ffi_cmp_test.go +++ b/extern/sector-storage/fr32/fr32_ffi_cmp_test.go @@ -12,7 +12,7 @@ import ( ffi "github.com/filecoin-project/filecoin-ffi" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/stretchr/testify/require" ) diff --git a/extern/sector-storage/fr32/fr32_test.go b/extern/sector-storage/fr32/fr32_test.go index e27e7b1e3..415134272 100644 --- a/extern/sector-storage/fr32/fr32_test.go +++ b/extern/sector-storage/fr32/fr32_test.go @@ -9,7 +9,7 @@ import ( "testing" ffi "github.com/filecoin-project/filecoin-ffi" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/stretchr/testify/require" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/extern/sector-storage/fr32/readers.go b/extern/sector-storage/fr32/readers.go index 8a1bbe087..20f3e9b31 100644 --- a/extern/sector-storage/fr32/readers.go +++ b/extern/sector-storage/fr32/readers.go @@ -6,7 +6,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) type unpadReader struct { diff --git a/extern/sector-storage/fr32/readers_test.go b/extern/sector-storage/fr32/readers_test.go index e87a776ef..706af5fee 100644 --- a/extern/sector-storage/fr32/readers_test.go +++ b/extern/sector-storage/fr32/readers_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fr32" ) diff --git a/extern/sector-storage/fr32/utils.go b/extern/sector-storage/fr32/utils.go index 9f4093c40..26c348f4f 100644 --- a/extern/sector-storage/fr32/utils.go +++ b/extern/sector-storage/fr32/utils.go @@ -3,7 +3,7 @@ package fr32 import ( "math/bits" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) func subPieces(in abi.UnpaddedPieceSize) []abi.UnpaddedPieceSize { diff --git a/extern/sector-storage/localworker.go b/extern/sector-storage/localworker.go index 773ef2d3b..2c3c350f7 100644 --- a/extern/sector-storage/localworker.go +++ b/extern/sector-storage/localworker.go @@ -12,7 +12,7 @@ import ( "golang.org/x/xerrors" ffi "github.com/filecoin-project/filecoin-ffi" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" storage2 "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/extern/sector-storage/manager.go b/extern/sector-storage/manager.go index 300958e39..07e752db1 100644 --- a/extern/sector-storage/manager.go +++ b/extern/sector-storage/manager.go @@ -12,7 +12,7 @@ import ( "github.com/mitchellh/go-homedir" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/extern/sector-storage/manager_test.go b/extern/sector-storage/manager_test.go index 13ad9f8bf..ee704cb5a 100644 --- a/extern/sector-storage/manager_test.go +++ b/extern/sector-storage/manager_test.go @@ -16,7 +16,7 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/google/uuid" logging "github.com/ipfs/go-log" diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index 4afe5f096..d4588c3fa 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -5,12 +5,13 @@ import ( "context" "crypto/sha256" "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "io" "math/rand" "sync" commcid "github.com/filecoin-project/go-fil-commcid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log" @@ -265,12 +266,12 @@ func AddOpFinish(ctx context.Context) (context.Context, func()) { } } -func (mgr *SectorMgr) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) ([]abi.PoStProof, error) { +func (mgr *SectorMgr) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, error) { return generateFakePoSt(sectorInfo, abi.RegisteredSealProof.RegisteredWinningPoStProof, randomness), nil } -func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) ([]abi.PoStProof, []abi.SectorID, error) { - si := make([]abi.SectorInfo, 0, len(sectorInfo)) +func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) { + si := make([]proof.SectorInfo, 0, len(sectorInfo)) var skipped []abi.SectorID for _, info := range sectorInfo { @@ -291,7 +292,7 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI return generateFakePoSt(si, abi.RegisteredSealProof.RegisteredWindowPoStProof, randomness), skipped, nil } -func generateFakePoStProof(sectorInfo []abi.SectorInfo, randomness abi.PoStRandomness) []byte { +func generateFakePoStProof(sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) []byte { hasher := sha256.New() _, _ = hasher.Write(randomness) for _, info := range sectorInfo { @@ -304,13 +305,13 @@ func generateFakePoStProof(sectorInfo []abi.SectorInfo, randomness abi.PoStRando } -func generateFakePoSt(sectorInfo []abi.SectorInfo, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error), randomness abi.PoStRandomness) []abi.PoStProof { +func generateFakePoSt(sectorInfo []proof.SectorInfo, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error), randomness abi.PoStRandomness) []proof.PoStProof { wp, err := rpt(sectorInfo[0].SealProof) if err != nil { panic(err) } - return []abi.PoStProof{ + return []proof.PoStProof{ { PoStProof: wp, ProofBytes: generateFakePoStProof(sectorInfo, randomness), @@ -384,7 +385,7 @@ func (mgr *SectorMgr) CheckProvable(ctx context.Context, spt abi.RegisteredSealP return bad, nil } -func (m mockVerif) VerifySeal(svi abi.SealVerifyInfo) (bool, error) { +func (m mockVerif) VerifySeal(svi proof.SealVerifyInfo) (bool, error) { if len(svi.Proof) != 32 { // Real ones are longer, but this should be fine return false, nil } @@ -398,11 +399,11 @@ func (m mockVerif) VerifySeal(svi abi.SealVerifyInfo) (bool, error) { return true, nil } -func (m mockVerif) VerifyWinningPoSt(ctx context.Context, info abi.WinningPoStVerifyInfo) (bool, error) { +func (m mockVerif) VerifyWinningPoSt(ctx context.Context, info proof.WinningPoStVerifyInfo) (bool, error) { return true, nil } -func (m mockVerif) VerifyWindowPoSt(ctx context.Context, info abi.WindowPoStVerifyInfo) (bool, error) { +func (m mockVerif) VerifyWindowPoSt(ctx context.Context, info proof.WindowPoStVerifyInfo) (bool, error) { if len(info.Proofs) != 1 { return false, xerrors.Errorf("expected 1 proof entry") } diff --git a/extern/sector-storage/mock/mock_test.go b/extern/sector-storage/mock/mock_test.go index c7d43e8b9..47c060f66 100644 --- a/extern/sector-storage/mock/mock_test.go +++ b/extern/sector-storage/mock/mock_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) func TestOpFinish(t *testing.T) { diff --git a/extern/sector-storage/resources.go b/extern/sector-storage/resources.go index 2fa797267..28ab47e6f 100644 --- a/extern/sector-storage/resources.go +++ b/extern/sector-storage/resources.go @@ -1,7 +1,7 @@ package sectorstorage import ( - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" ) diff --git a/extern/sector-storage/roprov.go b/extern/sector-storage/roprov.go index fe58a8445..2b009c63b 100644 --- a/extern/sector-storage/roprov.go +++ b/extern/sector-storage/roprov.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/stores" ) diff --git a/extern/sector-storage/sched.go b/extern/sector-storage/sched.go index 831a2615f..8b8ef6d46 100644 --- a/extern/sector-storage/sched.go +++ b/extern/sector-storage/sched.go @@ -10,7 +10,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/storiface" diff --git a/extern/sector-storage/sched_test.go b/extern/sector-storage/sched_test.go index 4c39370a0..c560a58f6 100644 --- a/extern/sector-storage/sched_test.go +++ b/extern/sector-storage/sched_test.go @@ -14,7 +14,7 @@ import ( logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" diff --git a/extern/sector-storage/selector_alloc.go b/extern/sector-storage/selector_alloc.go index ca4b99bfc..b891383fb 100644 --- a/extern/sector-storage/selector_alloc.go +++ b/extern/sector-storage/selector_alloc.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" diff --git a/extern/sector-storage/selector_existing.go b/extern/sector-storage/selector_existing.go index 1e97db539..fb161f085 100644 --- a/extern/sector-storage/selector_existing.go +++ b/extern/sector-storage/selector_existing.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" diff --git a/extern/sector-storage/selector_task.go b/extern/sector-storage/selector_task.go index 5c0d65bb1..807b53103 100644 --- a/extern/sector-storage/selector_task.go +++ b/extern/sector-storage/selector_task.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" "github.com/filecoin-project/lotus/extern/sector-storage/stores" diff --git a/extern/sector-storage/stores/filetype.go b/extern/sector-storage/stores/filetype.go index 50417d968..90cc1d160 100644 --- a/extern/sector-storage/stores/filetype.go +++ b/extern/sector-storage/stores/filetype.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) const ( diff --git a/extern/sector-storage/stores/index.go b/extern/sector-storage/stores/index.go index 256dc9651..e2bd7e4ee 100644 --- a/extern/sector-storage/stores/index.go +++ b/extern/sector-storage/stores/index.go @@ -12,8 +12,8 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" ) var HeartbeatInterval = 10 * time.Second diff --git a/extern/sector-storage/stores/index_locks.go b/extern/sector-storage/stores/index_locks.go index 8bf15b950..32c963a41 100644 --- a/extern/sector-storage/stores/index_locks.go +++ b/extern/sector-storage/stores/index_locks.go @@ -6,7 +6,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) type sectorLock struct { diff --git a/extern/sector-storage/stores/index_locks_test.go b/extern/sector-storage/stores/index_locks_test.go index 5039f8815..1c550d3ca 100644 --- a/extern/sector-storage/stores/index_locks_test.go +++ b/extern/sector-storage/stores/index_locks_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) var aSector = abi.SectorID{ diff --git a/extern/sector-storage/stores/interface.go b/extern/sector-storage/stores/interface.go index d94f28e83..875754fc5 100644 --- a/extern/sector-storage/stores/interface.go +++ b/extern/sector-storage/stores/interface.go @@ -3,8 +3,8 @@ package stores import ( "context" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" - "github.com/filecoin-project/specs-actors/actors/abi" ) type PathType string diff --git a/extern/sector-storage/stores/local.go b/extern/sector-storage/stores/local.go index b308f5d86..75387acc8 100644 --- a/extern/sector-storage/stores/local.go +++ b/extern/sector-storage/stores/local.go @@ -13,7 +13,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/fsutil" ) diff --git a/extern/sector-storage/stores/remote.go b/extern/sector-storage/stores/remote.go index a88e3b947..b9d241b5f 100644 --- a/extern/sector-storage/stores/remote.go +++ b/extern/sector-storage/stores/remote.go @@ -18,7 +18,7 @@ import ( "github.com/filecoin-project/lotus/extern/sector-storage/storiface" "github.com/filecoin-project/lotus/extern/sector-storage/tarutil" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/hashicorp/go-multierror" files "github.com/ipfs/go-ipfs-files" diff --git a/extern/sector-storage/storiface/ffi.go b/extern/sector-storage/storiface/ffi.go index 6e16018f0..95d400e52 100644 --- a/extern/sector-storage/storiface/ffi.go +++ b/extern/sector-storage/storiface/ffi.go @@ -3,7 +3,7 @@ package storiface import ( "errors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) var ErrSectorNotFound = errors.New("sector not found") diff --git a/extern/sector-storage/storiface/worker.go b/extern/sector-storage/storiface/worker.go index 37e4aad1d..25e3175bd 100644 --- a/extern/sector-storage/storiface/worker.go +++ b/extern/sector-storage/storiface/worker.go @@ -3,8 +3,8 @@ package storiface import ( "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" - "github.com/filecoin-project/specs-actors/actors/abi" ) type WorkerInfo struct { diff --git a/extern/sector-storage/testworker_test.go b/extern/sector-storage/testworker_test.go index 858b76f7c..8f27401f0 100644 --- a/extern/sector-storage/testworker_test.go +++ b/extern/sector-storage/testworker_test.go @@ -6,7 +6,7 @@ import ( "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/mock" diff --git a/extern/sector-storage/work_tracker.go b/extern/sector-storage/work_tracker.go index fe176a7f7..5dc12802c 100644 --- a/extern/sector-storage/work_tracker.go +++ b/extern/sector-storage/work_tracker.go @@ -8,7 +8,7 @@ import ( "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/extern/sector-storage/sealtasks" diff --git a/extern/sector-storage/zerocomm/zerocomm.go b/extern/sector-storage/zerocomm/zerocomm.go index 9b59723a0..9855a5821 100644 --- a/extern/sector-storage/zerocomm/zerocomm.go +++ b/extern/sector-storage/zerocomm/zerocomm.go @@ -4,7 +4,7 @@ import ( "math/bits" commcid "github.com/filecoin-project/go-fil-commcid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" ) diff --git a/extern/sector-storage/zerocomm/zerocomm_test.go b/extern/sector-storage/zerocomm/zerocomm_test.go index f5f508796..393f61d64 100644 --- a/extern/sector-storage/zerocomm/zerocomm_test.go +++ b/extern/sector-storage/zerocomm/zerocomm_test.go @@ -7,7 +7,7 @@ import ( "testing" commcid "github.com/filecoin-project/go-fil-commcid" - abi "github.com/filecoin-project/specs-actors/actors/abi" + abi "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/extern/storage-sealing/cbor_gen.go b/extern/storage-sealing/cbor_gen.go index b07626187..78765d7b4 100644 --- a/extern/storage-sealing/cbor_gen.go +++ b/extern/storage-sealing/cbor_gen.go @@ -6,7 +6,7 @@ import ( "fmt" "io" - abi "github.com/filecoin-project/specs-actors/actors/abi" + abi "github.com/filecoin-project/go-state-types/abi" miner "github.com/filecoin-project/specs-actors/actors/builtin/miner" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" diff --git a/extern/storage-sealing/checks.go b/extern/storage-sealing/checks.go index 3a59ea059..28802fe9f 100644 --- a/extern/storage-sealing/checks.go +++ b/extern/storage-sealing/checks.go @@ -3,15 +3,16 @@ package sealing import ( "bytes" "context" + saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/extern/sector-storage/zerocomm" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" ) // TODO: For now we handle this by halting state execution, when we get jsonrpc reconnecting @@ -168,7 +169,7 @@ func (m *Sealing) checkCommit(ctx context.Context, si SectorInfo, proof []byte, log.Warn("on-chain sealed CID doesn't match!") } - ok, err := m.verif.VerifySeal(abi.SealVerifyInfo{ + ok, err := m.verif.VerifySeal(saproof.SealVerifyInfo{ SectorID: m.minerSector(si.SectorNumber), SealedCID: pci.Info.SealedCID, SealProof: spt, diff --git a/extern/storage-sealing/constants.go b/extern/storage-sealing/constants.go index 565a38c8e..ebb3d3347 100644 --- a/extern/storage-sealing/constants.go +++ b/extern/storage-sealing/constants.go @@ -1,7 +1,7 @@ package sealing import ( - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) diff --git a/extern/storage-sealing/events.go b/extern/storage-sealing/events.go index ba6d2a860..298063147 100644 --- a/extern/storage-sealing/events.go +++ b/extern/storage-sealing/events.go @@ -3,7 +3,7 @@ package sealing import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) // `curH`-`ts.Height` = `confidence` diff --git a/extern/storage-sealing/fsm.go b/extern/storage-sealing/fsm.go index 4b8266e8b..8edba2b68 100644 --- a/extern/storage-sealing/fsm.go +++ b/extern/storage-sealing/fsm.go @@ -12,8 +12,8 @@ import ( "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" statemachine "github.com/filecoin-project/go-statemachine" - "github.com/filecoin-project/specs-actors/actors/abi" ) func (m *Sealing) Plan(events []statemachine.Event, user interface{}) (interface{}, uint64, error) { diff --git a/extern/storage-sealing/fsm_events.go b/extern/storage-sealing/fsm_events.go index 8649e6c5e..ee95ab1c7 100644 --- a/extern/storage-sealing/fsm_events.go +++ b/extern/storage-sealing/fsm_events.go @@ -4,8 +4,8 @@ import ( "github.com/ipfs/go-cid" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" ) diff --git a/extern/storage-sealing/fsm_test.go b/extern/storage-sealing/fsm_test.go index c67decbeb..c1a846676 100644 --- a/extern/storage-sealing/fsm_test.go +++ b/extern/storage-sealing/fsm_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" logging "github.com/ipfs/go-log/v2" "github.com/stretchr/testify/require" diff --git a/extern/storage-sealing/garbage.go b/extern/storage-sealing/garbage.go index 4b95c1b67..caf371806 100644 --- a/extern/storage-sealing/garbage.go +++ b/extern/storage-sealing/garbage.go @@ -5,7 +5,7 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) func (m *Sealing) pledgeSector(ctx context.Context, sectorID abi.SectorID, existingPieceSizes []abi.UnpaddedPieceSize, sizes ...abi.UnpaddedPieceSize) ([]abi.PieceInfo, error) { diff --git a/extern/storage-sealing/nullreader.go b/extern/storage-sealing/nullreader.go index ea6dfddb0..5987a4145 100644 --- a/extern/storage-sealing/nullreader.go +++ b/extern/storage-sealing/nullreader.go @@ -3,8 +3,8 @@ package sealing import ( "io" + "github.com/filecoin-project/go-state-types/abi" nr "github.com/filecoin-project/lotus/extern/storage-sealing/lib/nullreader" - "github.com/filecoin-project/specs-actors/actors/abi" ) type NullReader struct { diff --git a/extern/storage-sealing/precommit_policy.go b/extern/storage-sealing/precommit_policy.go index 1521dfb05..93a963535 100644 --- a/extern/storage-sealing/precommit_policy.go +++ b/extern/storage-sealing/precommit_policy.go @@ -3,7 +3,7 @@ package sealing import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) diff --git a/extern/storage-sealing/precommit_policy_test.go b/extern/storage-sealing/precommit_policy_test.go index 9f9267d65..b9c3ec49b 100644 --- a/extern/storage-sealing/precommit_policy_test.go +++ b/extern/storage-sealing/precommit_policy_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" commcid "github.com/filecoin-project/go-fil-commcid" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" ) diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index e48679cc7..45b95e18c 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -16,14 +16,14 @@ import ( "github.com/filecoin-project/go-address" padreader "github.com/filecoin-project/go-padreader" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" statemachine "github.com/filecoin-project/go-statemachine" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" ) const SectorStorePrefix = "/sectors" diff --git a/extern/storage-sealing/states_failed.go b/extern/storage-sealing/states_failed.go index e313fd712..57a93a773 100644 --- a/extern/storage-sealing/states_failed.go +++ b/extern/storage-sealing/states_failed.go @@ -6,11 +6,11 @@ import ( "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-statemachine" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/lotus/extern/sector-storage/zerocomm" ) diff --git a/extern/storage-sealing/states_sealing.go b/extern/storage-sealing/states_sealing.go index 7693f26ad..5e2b72ee1 100644 --- a/extern/storage-sealing/states_sealing.go +++ b/extern/storage-sealing/states_sealing.go @@ -6,13 +6,13 @@ import ( "golang.org/x/xerrors" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-statemachine" - "github.com/filecoin-project/specs-actors/actors/abi" - "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/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-storage/storage" ) diff --git a/extern/storage-sealing/stats.go b/extern/storage-sealing/stats.go index 871c962c1..78630c216 100644 --- a/extern/storage-sealing/stats.go +++ b/extern/storage-sealing/stats.go @@ -3,7 +3,7 @@ package sealing import ( "sync" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) type statSectorState int diff --git a/extern/storage-sealing/types.go b/extern/storage-sealing/types.go index 99cce7714..c044defd3 100644 --- a/extern/storage-sealing/types.go +++ b/extern/storage-sealing/types.go @@ -6,10 +6,10 @@ import ( "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-storage/storage" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" diff --git a/extern/storage-sealing/types_test.go b/extern/storage-sealing/types_test.go index c11cc66b7..fc56620dc 100644 --- a/extern/storage-sealing/types_test.go +++ b/extern/storage-sealing/types_test.go @@ -7,7 +7,7 @@ import ( "gotest.tools/assert" cborutil "github.com/filecoin-project/go-cbor-util" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" ) diff --git a/extern/storage-sealing/upgrade_queue.go b/extern/storage-sealing/upgrade_queue.go index 870f60dbb..650fdc83d 100644 --- a/extern/storage-sealing/upgrade_queue.go +++ b/extern/storage-sealing/upgrade_queue.go @@ -5,8 +5,8 @@ import ( "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) diff --git a/extern/storage-sealing/utils.go b/extern/storage-sealing/utils.go index b507907fb..dadef227d 100644 --- a/extern/storage-sealing/utils.go +++ b/extern/storage-sealing/utils.go @@ -3,7 +3,7 @@ package sealing import ( "math/bits" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" ) func fillersFromRem(in abi.UnpaddedPieceSize) ([]abi.UnpaddedPieceSize, error) { diff --git a/extern/storage-sealing/utils_test.go b/extern/storage-sealing/utils_test.go index 1d6b6c515..e346b6dc9 100644 --- a/extern/storage-sealing/utils_test.go +++ b/extern/storage-sealing/utils_test.go @@ -3,7 +3,7 @@ package sealing import ( "testing" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/stretchr/testify/assert" ) diff --git a/extern/test-vectors b/extern/test-vectors index 84da0a5ea..ef5dba45b 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit 84da0a5ea1256a6e66bcbf73542c93e4916d6356 +Subproject commit ef5dba45b810d7090e029167cc66911ef8c42a07 diff --git a/genesis/types.go b/genesis/types.go index 13349def2..79656feac 100644 --- a/genesis/types.go +++ b/genesis/types.go @@ -4,7 +4,7 @@ import ( "encoding/json" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/peer" diff --git a/go.mod b/go.mod index cddb64d73..9b0dafa3b 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,14 @@ replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-al require ( contrib.go.opencensus.io/exporter/jaeger v0.1.0 contrib.go.opencensus.io/exporter/prometheus v0.1.0 + github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect github.com/BurntSushi/toml v0.3.1 github.com/GeertJohan/go.rice v1.0.0 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/coreos/go-systemd/v22 v22.0.0 + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.0.3 github.com/docker/go-units v0.4.0 @@ -28,16 +30,17 @@ require ( github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-data-transfer v0.6.3 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.5.9 + github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-multistore v0.0.3 - github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 + github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 + github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b - github.com/filecoin-project/specs-actors v0.9.3 - github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 + github.com/filecoin-project/specs-actors v0.9.6 + github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 github.com/filecoin-project/statediff v0.0.1 github.com/filecoin-project/test-vectors v0.0.0-20200903223506-84da0a5ea125 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 @@ -117,6 +120,7 @@ require ( github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 go.opencensus.io v0.22.4 + go.uber.org/dig v1.10.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/multierr v1.5.0 go.uber.org/zap v1.15.0 diff --git a/go.sum b/go.sum index c94136ce2..ebee7b1f4 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,8 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= +github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -65,9 +67,11 @@ github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -164,6 +168,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f h1:BOaYiTvg8p9vBUXpklC22XSK/mifLF7lG9jtmYYi3Tc= github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1:3ZQK6DMPSz/QZ73jlWxBtUhNA8xZx7LzUFSq/OfP8vk= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= @@ -246,8 +252,8 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= github.com/filecoin-project/go-fil-markets v0.5.8 h1:uwl0QNUVmmSlUQfxshpj21Dmhh6WKTQNhnb1GMfdp18= github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg= -github.com/filecoin-project/go-fil-markets v0.5.9 h1:iIO17UfIjUCiB37TRwgiBwAyfJJwHb8e8uAfu7F37gc= -github.com/filecoin-project/go-fil-markets v0.5.9/go.mod h1:/cb1IoaiHhwFEWyIAPm9yN6Z+MiPujFZBT8BGH7LwB8= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b h1:Xe+ngO0+FV1JESIz9rlyzygwIEnI8M3bDvKqljdIoJA= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= @@ -255,10 +261,16 @@ github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0 github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 h1:92PET+sx1Hb4W/8CgFwGuxaKbttwY+UNspYZTvXY0vs= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= +github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 h1:+/4aUeUoKr6AKfPE3mBhXA5spIV6UcKdTYDPNU2Tdmg= +github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak= github.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 h1:A256QonvzRaknIIAuWhe/M2dpV2otzs3NBhi5TWa/UA= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= +github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df h1:m2esXSuGBkuXlRyCsl1a/7/FkFam63o1OzIgzaHtOfI= +github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c= @@ -280,11 +292,14 @@ github.com/filecoin-project/specs-actors v0.7.3-0.20200716231407-60a2ae96d2e6/go github.com/filecoin-project/specs-actors v0.8.2/go.mod h1:Q3ACV5kBLvqPaYbthc/J1lGMJ5OwogmD9pzdtPRMdCw= github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU= github.com/filecoin-project/specs-actors v0.9.2/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA= -github.com/filecoin-project/specs-actors v0.9.3 h1:Fi75G/UQ7R4eiIwnN+S6bBQ9LqKivyJdw62jJzTi6aE= github.com/filecoin-project/specs-actors v0.9.3/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA= +github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4= +github.com/filecoin-project/specs-actors v0.9.6 h1:U3PU4jrHcmXxfEP0CC1fGETx4RrXlm5RYJeuT5eWjhI= +github.com/filecoin-project/specs-actors v0.9.6/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= -github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 h1:jLzN1hwO5WpKPu8ASbW8fs1FUCsOWNvoBXzQhv+8/E8= github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= +github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk= +github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/statediff v0.0.1 h1:lym6d5wNnzr+5Uc/6RRWx1hgwb+tCKn2mFIK0Eb1Q18= github.com/filecoin-project/statediff v0.0.1/go.mod h1:qNWauolLFEzOiA4LNWermBRVNbaZHfPcPevumZeh+hE= github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f/go.mod h1:1CGbd11KkHuyWPT+xwwCol1zl/jnlpiKD2L4fzKxaiI= @@ -539,7 +554,6 @@ github.com/ipfs/go-fs-lock v0.0.1/go.mod h1:DNBekbboPKcxs1aukPSaOtFA3QfSdi5C855v github.com/ipfs/go-fs-lock v0.0.6 h1:sn3TWwNVQqSeNjlWy6zQ1uUGAZrV3hPOyEA6y1/N2a0= github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28L7zESmM= github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= -github.com/ipfs/go-graphsync v0.1.1 h1:bFDAYS0Z48yd8ROPI6f/zIVmJxaDLA6m8cVuJPKC5fE= github.com/ipfs/go-graphsync v0.1.1/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= github.com/ipfs/go-graphsync v0.1.2 h1:25Ll9kIXCE+DY0dicvfS3KMw+U5sd01b/FJbA7KAbhg= github.com/ipfs/go-graphsync v0.1.2/go.mod h1:sLXVXm1OxtE2XYPw62MuXCdAuNwkAdsbnfrmos5odbA= @@ -652,11 +666,9 @@ github.com/ipfs/iptb-plugins v0.2.1 h1:au4HWn9/pRPbkxA08pDx2oRAs4cnbgQWgV0teYXuu github.com/ipfs/iptb-plugins v0.2.1/go.mod h1:QXMbtIWZ+jRsW8a4h13qAKU7jcM7qaittO8wOsTP0Rs= github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae h1:OV9dxl8iPMCOD8Vi/hvFwRh3JWPXqmkYSVxWr9JnEzM= github.com/ipld/go-car v0.1.1-0.20200526133713-1c7508d55aae/go.mod h1:2mvxpu4dKRnuH3mj5u6KW/tmRSCcXvy/KYiJ4nC6h4c= -github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e h1:ZISbJlM0urTANR9KRfRaqlBmyOj5uUtxs2r4Up9IXsA= github.com/ipld/go-ipld-prime v0.0.2-0.20200428162820-8b59dc292b8e/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= github.com/ipld/go-ipld-prime v0.0.4-0.20200828224805-5ff8c8b0b6ef h1:/yPelt/0CuzZsmRkYzBBnJ499JnAOGaIaAXHujx96ic= github.com/ipld/go-ipld-prime v0.0.4-0.20200828224805-5ff8c8b0b6ef/go.mod h1:uVIwe/u0H4VdKv3kaN1ck7uCb6yD9cFLS9/ELyXbsw8= -github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1 h1:K1Ysr7kgIlo7YQkPqdkA6H7BVdIugvuAz7OQUTJxLdE= github.com/ipld/go-ipld-prime-proto v0.0.0-20200428191222-c1ffdadc01e1/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= github.com/ipld/go-ipld-prime-proto v0.0.0-20200828231332-ae0aea07222b h1:ZtlW6pubN17TDaStlxgrwEXXwwUfJaXu9RobwczXato= github.com/ipld/go-ipld-prime-proto v0.0.0-20200828231332-ae0aea07222b/go.mod h1:OAV6xBmuTLsPZ+epzKkPB1e25FHk/vCtyatkdHcArLs= @@ -681,7 +693,6 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0 github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= @@ -829,7 +840,6 @@ github.com/libp2p/go-libp2p-core v0.6.1 h1:XS+Goh+QegCDojUZp00CaPMfiEADCrLjNZskW github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= -github.com/libp2p/go-libp2p-crypto v0.1.0 h1:k9MFy+o2zGDNGsaoZl0MA3iZ75qXxr9OOoAZF+sD5OQ= github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= github.com/libp2p/go-libp2p-daemon v0.2.2/go.mod h1:kyrpsLB2JeNYR2rvXSVWyY0iZuRIMhqzWR3im9BV6NQ= github.com/libp2p/go-libp2p-discovery v0.0.1/go.mod h1:ZkkF9xIFRLA1xCc7bstYFkd80gBGK8Fc1JqGoU2i+zI= @@ -855,7 +865,6 @@ github.com/libp2p/go-libp2p-kbucket v0.4.2/go.mod h1:7sCeZx2GkNK1S6lQnGUW5JYZCFP github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= -github.com/libp2p/go-libp2p-metrics v0.0.1 h1:yumdPC/P2VzINdmcKZd0pciSUCpou+s0lwYCjBbzQZU= github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I= github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= @@ -878,7 +887,6 @@ github.com/libp2p/go-libp2p-noise v0.1.1 h1:vqYQWvnIcHpIoWJKC7Al4D6Hgj0H012TuXRh github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= -github.com/libp2p/go-libp2p-peer v0.2.0 h1:EQ8kMjaCUwt/Y5uLgjT8iY2qg0mGUT0N1zUjer50DsY= github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= @@ -895,7 +903,6 @@ github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuD github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= -github.com/libp2p/go-libp2p-protocol v0.1.0 h1:HdqhEyhg0ToCaxgMhnOmUO8snQtt/kQlcjVk3UoJU3c= github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= @@ -1185,7 +1192,6 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c h1:5bFTChQxSKNwy8ALwOebjekYExl9HTT9urdawqC95tA= github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c/go.mod h1:7qN3Y0BvzRUf4LofcoJplQL10lsFDb4PYlePTVwrP28= -github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -1402,9 +1408,7 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= @@ -1502,8 +1506,9 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/dig v1.8.0 h1:1rR6hnL/bu1EVcjnRDN5kx1vbIjEJDTGhSQ2B3ddpcI= go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY= +go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/fx v1.9.0 h1:7OAz8ucp35AU8eydejpYG7QrbE8rLKzGhHbZlJi5LYY= go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw= go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo= @@ -1555,6 +1560,7 @@ golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1777,7 +1783,6 @@ golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200318150045-ba25ddc85566/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d h1:F3OmlXCzYtG9YE6tXDnUOlJBzVzHF8EcmZ1yTJlcgIk= golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3 h1:r3P/5xOq/dK1991B65Oy6E1fRF/2d/fSYZJ/fXGVfJc= golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1868,6 +1873,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/lib/rpcenc/reader.go b/lib/rpcenc/reader.go index 3f4d5c604..617c6495e 100644 --- a/lib/rpcenc/reader.go +++ b/lib/rpcenc/reader.go @@ -19,8 +19,8 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/specs-actors/actors/abi" ) var log = logging.Logger("rpcenc") diff --git a/lib/sigs/bls/init.go b/lib/sigs/bls/init.go index c63cf0b65..42633eee8 100644 --- a/lib/sigs/bls/init.go +++ b/lib/sigs/bls/init.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" blst "github.com/supranational/blst/bindings/go" diff --git a/lib/sigs/secp/init.go b/lib/sigs/secp/init.go index 1285b19b6..674bbbb28 100644 --- a/lib/sigs/secp/init.go +++ b/lib/sigs/secp/init.go @@ -5,7 +5,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-crypto" - crypto2 "github.com/filecoin-project/specs-actors/actors/crypto" + crypto2 "github.com/filecoin-project/go-state-types/crypto" "github.com/minio/blake2b-simd" "github.com/filecoin-project/lotus/lib/sigs" diff --git a/lib/sigs/sigs.go b/lib/sigs/sigs.go index 4a4fd7340..1f56846a8 100644 --- a/lib/sigs/sigs.go +++ b/lib/sigs/sigs.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "go.opencensus.io/trace" "golang.org/x/xerrors" diff --git a/lotuspond/spawn.go b/lotuspond/spawn.go index f4e8decee..5fa82a865 100644 --- a/lotuspond/spawn.go +++ b/lotuspond/spawn.go @@ -16,8 +16,8 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/chain/gen" diff --git a/markets/loggers/loggers.go b/markets/loggers/loggers.go index 6f386dbba..27a6b2c63 100644 --- a/markets/loggers/loggers.go +++ b/markets/loggers/loggers.go @@ -3,7 +3,7 @@ package marketevents import ( "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" logging "github.com/ipfs/go-log/v2" ) diff --git a/markets/retrievaladapter/client.go b/markets/retrievaladapter/client.go index e57a11bd1..de94f50a9 100644 --- a/markets/retrievaladapter/client.go +++ b/markets/retrievaladapter/client.go @@ -10,7 +10,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/shared" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/ipfs/go-cid" "github.com/multiformats/go-multiaddr" diff --git a/markets/retrievaladapter/provider.go b/markets/retrievaladapter/provider.go index f22a31ccc..443c4fb4a 100644 --- a/markets/retrievaladapter/provider.go +++ b/markets/retrievaladapter/provider.go @@ -13,7 +13,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/retrievalmarket" "github.com/filecoin-project/go-fil-markets/shared" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/ipfs/go-cid" diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 1d41ecf91..5251b1cd3 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -6,7 +6,7 @@ import ( "bytes" "context" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "golang.org/x/xerrors" @@ -14,6 +14,9 @@ import ( cborutil "github.com/filecoin-project/go-cbor-util" "github.com/filecoin-project/go-fil-markets/shared" "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events/state" @@ -24,12 +27,9 @@ import ( "github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/markets/utils" "github.com/filecoin-project/lotus/node/impl/full" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" samarket "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/ipfs/go-cid" ) diff --git a/markets/storageadapter/provider.go b/markets/storageadapter/provider.go index 1a6627529..9c4a5946e 100644 --- a/markets/storageadapter/provider.go +++ b/markets/storageadapter/provider.go @@ -14,13 +14,13 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/shared" "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" diff --git a/markets/utils/converters.go b/markets/utils/converters.go index e1089842e..05472801d 100644 --- a/markets/utils/converters.go +++ b/markets/utils/converters.go @@ -1,9 +1,9 @@ package utils import ( + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/market" peer "github.com/libp2p/go-libp2p-core/peer" "github.com/multiformats/go-multiaddr" diff --git a/miner/miner.go b/miner/miner.go index 34f1255a9..cba9e7b66 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -6,14 +6,15 @@ import ( "crypto/rand" "encoding/binary" "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "sync" "time" "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" lru "github.com/hashicorp/golang-lru" "github.com/filecoin-project/lotus/api" @@ -464,7 +465,7 @@ func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, bas } func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket, - eproof *types.ElectionProof, bvals []types.BeaconEntry, wpostProof []abi.PoStProof, msgs []*types.SignedMessage) (*types.BlockMsg, error) { + eproof *types.ElectionProof, bvals []types.BeaconEntry, wpostProof []proof.PoStProof, msgs []*types.SignedMessage) (*types.BlockMsg, error) { uts := base.TipSet.MinTimestamp() + build.BlockDelaySecs*(uint64(base.NullRounds)+1) nheight := base.TipSet.Height() + base.NullRounds + 1 diff --git a/miner/testminer.go b/miner/testminer.go index 0b1cbb12b..64e3b3a62 100644 --- a/miner/testminer.go +++ b/miner/testminer.go @@ -7,10 +7,10 @@ import ( ds "github.com/ipfs/go-datastore" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/gen" "github.com/filecoin-project/lotus/chain/gen/slashfilter" - "github.com/filecoin-project/specs-actors/actors/abi" ) type MineReq struct { diff --git a/node/hello/cbor_gen.go b/node/hello/cbor_gen.go index 48d111c6b..3b85e3a74 100644 --- a/node/hello/cbor_gen.go +++ b/node/hello/cbor_gen.go @@ -6,7 +6,7 @@ import ( "fmt" "io" - abi "github.com/filecoin-project/specs-actors/actors/abi" + abi "github.com/filecoin-project/go-state-types/abi" cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" xerrors "golang.org/x/xerrors" diff --git a/node/hello/hello.go b/node/hello/hello.go index 78da9c7e3..1b03c5cdd 100644 --- a/node/hello/hello.go +++ b/node/hello/hello.go @@ -4,10 +4,10 @@ import ( "context" "time" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" xerrors "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p-core/host" diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 3a157318e..ed1e6cd05 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -7,7 +7,7 @@ import ( "os" datatransfer "github.com/filecoin-project/go-data-transfer" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "golang.org/x/xerrors" "github.com/ipfs/go-blockservice" @@ -38,7 +38,7 @@ import ( "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-multistore" "github.com/filecoin-project/go-padreader" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/node/impl/full/beacon.go b/node/impl/full/beacon.go index 07037f6e1..725c6ff1f 100644 --- a/node/impl/full/beacon.go +++ b/node/impl/full/beacon.go @@ -4,9 +4,9 @@ import ( "context" "fmt" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/beacon" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" "go.uber.org/fx" ) diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index ce5e3822a..c5dd5c9a9 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -26,8 +26,8 @@ import ( cbg "github.com/whyrusleeping/cbor-gen" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 778c2c4eb..2aa8a39ca 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -14,10 +14,10 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "go.uber.org/fx" "golang.org/x/xerrors" diff --git a/node/impl/full/multisig.go b/node/impl/full/multisig.go index f1e3c61fd..3ece1c19a 100644 --- a/node/impl/full/multisig.go +++ b/node/impl/full/multisig.go @@ -3,13 +3,13 @@ package full import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 36721a93d..379848065 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -15,9 +15,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" - "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/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" @@ -60,7 +60,7 @@ func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, er return stmgr.GetNetworkName(ctx, a.StateManager, a.Chain.GetHeaviestTipSet().ParentState()) } -func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, filter *abi.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { +func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, filter *bitfield.BitField, filterOut bool, tsk types.TipSetKey) ([]*api.ChainSectorInfo, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) @@ -74,7 +74,7 @@ func (a *StateAPI) StateMinerActiveSectors(ctx context.Context, maddr address.Ad err := a.StateManager.WithParentStateTsk(tsk, a.StateManager.WithActor(maddr, a.StateManager.WithActorState(ctx, func(store adt.Store, mas *miner.State) error { - var allActive []abi.BitField + var allActive []bitfield.BitField err := a.StateManager.WithDeadlines( a.StateManager.WithEachDeadline( @@ -160,7 +160,7 @@ func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.A return mas.DeadlineInfo(ts.Height()).NextNotElapsed(), nil } -func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) (abi.BitField, error) { +func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { out := bitfield.New() err := a.StateManager.WithParentStateTsk(tsk, @@ -222,7 +222,7 @@ func (a *StateAPI) StateAllMinerFaults(ctx context.Context, lookback abi.ChainEp return allFaults, nil*/ } -func (a *StateAPI) StateMinerRecoveries(ctx context.Context, addr address.Address, tsk types.TipSetKey) (abi.BitField, error) { +func (a *StateAPI) StateMinerRecoveries(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { out := bitfield.New() err := a.StateManager.WithParentStateTsk(tsk, @@ -636,7 +636,7 @@ func (a *StateAPI) StateMinerSectorCount(ctx context.Context, addr address.Addre err := a.StateManager.WithParentStateTsk(tsk, a.StateManager.WithActor(addr, a.StateManager.WithActorState(ctx, func(store adt.Store, mas *miner.State) error { - var allActive []abi.BitField + var allActive []bitfield.BitField err := a.StateManager.WithDeadlines( a.StateManager.WithEachDeadline( diff --git a/node/impl/full/wallet.go b/node/impl/full/wallet.go index 440f9642f..af786085b 100644 --- a/node/impl/full/wallet.go +++ b/node/impl/full/wallet.go @@ -7,8 +7,8 @@ import ( "go.uber.org/fx" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" diff --git a/node/impl/remoteworker.go b/node/impl/remoteworker.go index 8111413ba..b6ef43c7c 100644 --- a/node/impl/remoteworker.go +++ b/node/impl/remoteworker.go @@ -8,7 +8,7 @@ import ( "github.com/filecoin-project/go-jsonrpc" "github.com/filecoin-project/go-jsonrpc/auth" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" diff --git a/node/impl/storminer.go b/node/impl/storminer.go index c688ff677..6eedc9f54 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -9,7 +9,7 @@ import ( "time" datatransfer "github.com/filecoin-project/go-data-transfer" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/host" "golang.org/x/xerrors" @@ -19,7 +19,7 @@ import ( retrievalmarket "github.com/filecoin-project/go-fil-markets/retrievalmarket" storagemarket "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-jsonrpc/auth" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/node/modules/dtypes/miner.go b/node/modules/dtypes/miner.go index d559a2de1..5bb439b4d 100644 --- a/node/modules/dtypes/miner.go +++ b/node/modules/dtypes/miner.go @@ -8,7 +8,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/storagemarket" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/extern/storage-sealing/sealiface" ) diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index f79c8a370..773df78fe 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -41,8 +41,8 @@ import ( "github.com/filecoin-project/go-jsonrpc/auth" "github.com/filecoin-project/go-multistore" paramfetch "github.com/filecoin-project/go-paramfetch" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-storedcounter" - "github.com/filecoin-project/specs-actors/actors/abi" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" diff --git a/node/node_test.go b/node/node_test.go index 31a14bc20..8cc51f629 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -7,9 +7,9 @@ import ( builder "github.com/filecoin-project/lotus/node/test" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/lib/lotuslog" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" saminer "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" diff --git a/node/test/builder.go b/node/test/builder.go index 2f98f65e0..20a54efa4 100644 --- a/node/test/builder.go +++ b/node/test/builder.go @@ -13,6 +13,8 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-jsonrpc" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-storedcounter" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" @@ -35,8 +37,6 @@ import ( testing2 "github.com/filecoin-project/lotus/node/modules/testing" "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/storage/mockstorage" - "github.com/filecoin-project/specs-actors/actors/abi" - "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/miner" "github.com/ipfs/go-datastore" diff --git a/paychmgr/manager.go b/paychmgr/manager.go index 00d796eea..4b102f062 100644 --- a/paychmgr/manager.go +++ b/paychmgr/manager.go @@ -4,7 +4,7 @@ import ( "context" "sync" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/node/modules/helpers" diff --git a/paychmgr/mock_test.go b/paychmgr/mock_test.go index d2aa047ee..bc19de223 100644 --- a/paychmgr/mock_test.go +++ b/paychmgr/mock_test.go @@ -7,7 +7,7 @@ import ( "github.com/filecoin-project/lotus/lib/sigs" - "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/go-state-types/crypto" cbornode "github.com/ipfs/go-ipld-cbor" diff --git a/paychmgr/paych.go b/paychmgr/paych.go index dd655b3e6..20d76b7fd 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -13,10 +13,10 @@ import ( "github.com/filecoin-project/go-address" cborutil "github.com/filecoin-project/go-cbor-util" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/sigs" - "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/account" "github.com/filecoin-project/specs-actors/actors/builtin/paych" diff --git a/paychmgr/paych_test.go b/paychmgr/paych_test.go index e1ae487e1..18c6655da 100644 --- a/paychmgr/paych_test.go +++ b/paychmgr/paych_test.go @@ -11,14 +11,14 @@ import ( "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/lib/sigs" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/stretchr/testify/require" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" tutils "github.com/filecoin-project/specs-actors/support/testing" "github.com/filecoin-project/specs-actors/actors/builtin/paych" diff --git a/paychmgr/paychget_test.go b/paychmgr/paychget_test.go index 07c84e764..1f3e4c396 100644 --- a/paychmgr/paychget_test.go +++ b/paychmgr/paychget_test.go @@ -9,7 +9,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/specs-actors/actors/util/adt" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/paych" cborrpc "github.com/filecoin-project/go-cbor-util" @@ -22,7 +22,7 @@ import ( "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" tutils "github.com/filecoin-project/specs-actors/support/testing" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" diff --git a/paychmgr/settle_test.go b/paychmgr/settle_test.go index f922dcccb..f17f961e2 100644 --- a/paychmgr/settle_test.go +++ b/paychmgr/settle_test.go @@ -6,7 +6,7 @@ import ( "github.com/ipfs/go-cid" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" tutils "github.com/filecoin-project/specs-actors/support/testing" ds "github.com/ipfs/go-datastore" ds_sync "github.com/ipfs/go-datastore/sync" diff --git a/paychmgr/settler/settler.go b/paychmgr/settler/settler.go index d5f8bf54e..45f24cdd9 100644 --- a/paychmgr/settler/settler.go +++ b/paychmgr/settler/settler.go @@ -12,7 +12,7 @@ import ( logging "github.com/ipfs/go-log/v2" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/paych" diff --git a/paychmgr/simple.go b/paychmgr/simple.go index 561f2dfc7..4cf579a47 100644 --- a/paychmgr/simple.go +++ b/paychmgr/simple.go @@ -10,7 +10,7 @@ import ( "golang.org/x/sync/errgroup" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/specs-actors/actors/builtin" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" diff --git a/storage/adapter_events.go b/storage/adapter_events.go index 42622e855..ff69c1e51 100644 --- a/storage/adapter_events.go +++ b/storage/adapter_events.go @@ -3,7 +3,7 @@ package storage import ( "context" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/types" diff --git a/storage/adapter_storage_miner.go b/storage/adapter_storage_miner.go index 0963b07e6..f780097a6 100644 --- a/storage/adapter_storage_miner.go +++ b/storage/adapter_storage_miner.go @@ -3,18 +3,19 @@ package storage import ( "bytes" "context" + "github.com/filecoin-project/go-bitfield" "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" @@ -198,7 +199,7 @@ func (s SealingAPIAdapter) StateSectorPreCommitInfo(ctx context.Context, maddr a return nil, err } if !ok { - var allocated abi.BitField + var allocated bitfield.BitField if err := stor.Get(ctx, state.AllocatedSectors, &allocated); err != nil { return nil, xerrors.Errorf("loading allocated sector bitfield: %w", err) } diff --git a/storage/addresses.go b/storage/addresses.go index a1c05660f..bef845367 100644 --- a/storage/addresses.go +++ b/storage/addresses.go @@ -6,7 +6,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" diff --git a/storage/miner.go b/storage/miner.go index eb548eb78..c68be87b3 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -3,6 +3,8 @@ package storage import ( "context" "errors" + "github.com/filecoin-project/go-bitfield" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "time" "github.com/ipfs/go-cid" @@ -12,11 +14,11 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/crypto" sectorstorage "github.com/filecoin-project/lotus/extern/sector-storage" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" @@ -52,7 +54,7 @@ type storageMinerApi interface { StateCall(context.Context, *types.Message, types.TipSetKey) (*api.InvocResult, error) StateMinerDeadlines(ctx context.Context, maddr address.Address, tok types.TipSetKey) ([]*miner.Deadline, error) StateMinerPartitions(context.Context, address.Address, uint64, types.TipSetKey) ([]*miner.Partition, error) - StateMinerSectors(context.Context, address.Address, *abi.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) + StateMinerSectors(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) StateSectorPreCommitInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (miner.SectorPreCommitOnChainInfo, error) StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*api.SectorLocation, error) @@ -65,8 +67,8 @@ type storageMinerApi interface { StateGetActor(ctx context.Context, actor address.Address, ts types.TipSetKey) (*types.Actor, error) StateGetReceipt(context.Context, cid.Cid, types.TipSetKey) (*types.MessageReceipt, error) StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error) - StateMinerFaults(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) - StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (abi.BitField, error) + StateMinerFaults(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) + StateMinerRecoveries(context.Context, address.Address, types.TipSetKey) (bitfield.BitField, error) StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error) MpoolPushMessage(context.Context, *types.Message, *api.MessageSendSpec) (*types.SignedMessage, error) @@ -199,9 +201,9 @@ func (wpp *StorageWpp) GenerateCandidates(ctx context.Context, randomness abi.Po return cds, nil } -func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []abi.SectorInfo, rand abi.PoStRandomness) ([]abi.PoStProof, error) { +func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []proof.SectorInfo, rand abi.PoStRandomness) ([]proof.PoStProof, error) { if build.InsecurePoStValidation { - return []abi.PoStProof{{ProofBytes: []byte("valid proof")}}, nil + return []proof.PoStProof{{ProofBytes: []byte("valid proof")}}, nil } log.Infof("Computing WinningPoSt ;%+v; %v", ssi, rand) diff --git a/storage/mockstorage/preseal.go b/storage/mockstorage/preseal.go index fd4d0d69b..da063020d 100644 --- a/storage/mockstorage/preseal.go +++ b/storage/mockstorage/preseal.go @@ -5,11 +5,11 @@ import ( "github.com/filecoin-project/go-address" commcid "github.com/filecoin-project/go-fil-commcid" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/extern/sector-storage/mock" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/market" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/wallet" diff --git a/storage/sealing.go b/storage/sealing.go index 7d7140b98..2cd454e5b 100644 --- a/storage/sealing.go +++ b/storage/sealing.go @@ -5,7 +5,7 @@ import ( "io" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" ) diff --git a/storage/sectorblocks/blocks.go b/storage/sectorblocks/blocks.go index b88ebcbae..bc8456a1f 100644 --- a/storage/sectorblocks/blocks.go +++ b/storage/sectorblocks/blocks.go @@ -15,8 +15,8 @@ import ( "golang.org/x/xerrors" cborutil "github.com/filecoin-project/go-cbor-util" + "github.com/filecoin-project/go-state-types/abi" sealing "github.com/filecoin-project/lotus/extern/storage-sealing" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/node/modules/dtypes" diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 2e0ed1c84..1fc7eeacc 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -4,16 +4,17 @@ import ( "bytes" "context" "errors" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "time" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" + "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - "github.com/filecoin-project/specs-actors/actors/crypto" "go.opencensus.io/trace" "golang.org/x/xerrors" @@ -64,7 +65,7 @@ func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *miner.Deadli }() } -func (s *WindowPoStScheduler) checkSectors(ctx context.Context, check abi.BitField) (abi.BitField, error) { +func (s *WindowPoStScheduler) checkSectors(ctx context.Context, check bitfield.BitField) (bitfield.BitField, error) { spt, err := s.proofType.RegisteredSealProof() if err != nil { return bitfield.BitField{}, xerrors.Errorf("getting seal proof type: %w", err) @@ -333,7 +334,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo Proofs: nil, } - var sinfos []abi.SectorInfo + var sinfos []proof.SectorInfo sidToPart := map[abi.SectorNumber]uint64{} skipCount := uint64(0) @@ -434,7 +435,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo return params, nil } -func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, allSectors abi.BitField, ts *types.TipSet) ([]abi.SectorInfo, error) { +func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, allSectors bitfield.BitField, ts *types.TipSet) ([]proof.SectorInfo, error) { sset, err := s.api.StateMinerSectors(ctx, s.actor, &goodSectors, false, ts.Key()) if err != nil { return nil, err @@ -444,22 +445,22 @@ func (s *WindowPoStScheduler) sectorsForProof(ctx context.Context, goodSectors, return nil, nil } - substitute := abi.SectorInfo{ + substitute := proof.SectorInfo{ SectorNumber: sset[0].ID, SealedCID: sset[0].Info.SealedCID, SealProof: sset[0].Info.SealProof, } - sectorByID := make(map[uint64]abi.SectorInfo, len(sset)) + sectorByID := make(map[uint64]proof.SectorInfo, len(sset)) for _, sector := range sset { - sectorByID[uint64(sector.ID)] = abi.SectorInfo{ + sectorByID[uint64(sector.ID)] = proof.SectorInfo{ SectorNumber: sector.ID, SealedCID: sector.Info.SealedCID, SealProof: sector.Info.SealProof, } } - proofSectors := make([]abi.SectorInfo, 0, len(sset)) + proofSectors := make([]proof.SectorInfo, 0, len(sset)) if err := allSectors.ForEach(func(sectorNo uint64) error { if info, found := sectorByID[sectorNo]; found { proofSectors = append(proofSectors, info) diff --git a/storage/wdpost_sched.go b/storage/wdpost_sched.go index 2645b3702..b238a490d 100644 --- a/storage/wdpost_sched.go +++ b/storage/wdpost_sched.go @@ -7,7 +7,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" diff --git a/tools/stats/collect.go b/tools/stats/collect.go index 3d031a415..221dc37e2 100644 --- a/tools/stats/collect.go +++ b/tools/stats/collect.go @@ -4,8 +4,8 @@ import ( "context" "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/specs-actors/actors/abi" client "github.com/influxdata/influxdb1-client/v2" ) diff --git a/tools/stats/rpc.go b/tools/stats/rpc.go index 166769fed..cfebdbddb 100644 --- a/tools/stats/rpc.go +++ b/tools/stats/rpc.go @@ -6,7 +6,7 @@ import ( "time" "github.com/filecoin-project/go-jsonrpc" - "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/go-state-types/abi" manet "github.com/multiformats/go-multiaddr/net" "golang.org/x/xerrors" From be7fb9d3df23e18a2094fb6195f2857c8e25993b Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 7 Sep 2020 02:00:13 -0400 Subject: [PATCH 056/199] Use custom markets --- go.mod | 2 +- go.sum | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 9b0dafa3b..6250a7af1 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-data-transfer v0.6.3 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b + github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 diff --git a/go.sum b/go.sum index ebee7b1f4..f0626e8ed 100644 --- a/go.sum +++ b/go.sum @@ -250,16 +250,14 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= -github.com/filecoin-project/go-fil-markets v0.5.8 h1:uwl0QNUVmmSlUQfxshpj21Dmhh6WKTQNhnb1GMfdp18= github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b h1:Xe+ngO0+FV1JESIz9rlyzygwIEnI8M3bDvKqljdIoJA= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a h1:SYWurOVYyEqajP3rr20F9UvkIpn6p9ewMk9yOg1kaVM= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= -github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 h1:92PET+sx1Hb4W/8CgFwGuxaKbttwY+UNspYZTvXY0vs= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 h1:+/4aUeUoKr6AKfPE3mBhXA5spIV6UcKdTYDPNU2Tdmg= github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak= @@ -283,7 +281,6 @@ github.com/filecoin-project/lotus v0.4.3-0.20200820203717-d1718369a182/go.mod h1 github.com/filecoin-project/lotus v0.5.8-0.20200903221953-ada5e6ae68cf/go.mod h1:wxuzS4ozpCFThia18G+J5P0Jp/DSiq9ezzJF1yvZuP4= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= -github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0 h1:E1fZ27fhKK05bhZItfTwqr1i05vXnEZJznQFEYwEEUU= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= From d678fe4bfa5b4c70bcebd46cdc38aafc452b42d1 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 7 Sep 2020 02:08:53 -0400 Subject: [PATCH 057/199] Fix tests --- api/api_full.go | 3 ++- chain/gen/gen.go | 3 ++- chain/stmgr/utils.go | 5 ++-- chain/sync.go | 3 ++- chain/sync_test.go | 3 ++- chain/types/blockheader.go | 3 ++- chain/types/blockheader_test.go | 2 ++ chain/vectors/gen/main.go | 2 ++ chain/vm/gas.go | 1 + chain/vm/gas_v0.go | 1 + chain/vm/syscalls.go | 3 ++- cli/state.go | 3 ++- cmd/lotus-bench/main.go | 25 ++++++++++--------- cmd/lotus-shed/proofs.go | 4 ++- conformance/stubs.go | 1 + .../sector-storage/ffiwrapper/sealer_test.go | 4 ++- extern/sector-storage/ffiwrapper/types.go | 3 ++- .../sector-storage/ffiwrapper/verifier_cgo.go | 1 + extern/sector-storage/mock/mock.go | 3 ++- extern/storage-sealing/checks.go | 1 + miner/miner.go | 3 ++- storage/adapter_storage_miner.go | 1 + storage/miner.go | 3 ++- storage/wdpost_run.go | 3 ++- 24 files changed, 56 insertions(+), 28 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 378920374..72bacad32 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -2,9 +2,10 @@ package api import ( "context" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "time" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p-core/peer" diff --git a/chain/gen/gen.go b/chain/gen/gen.go index abee75dd3..e6127508e 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -4,11 +4,12 @@ import ( "bytes" "context" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "io/ioutil" "sync/atomic" "time" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 8b95f800a..0cb491337 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -4,13 +4,14 @@ import ( "bytes" "context" "fmt" - saruntime "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "os" "reflect" "runtime" "strings" + saruntime "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" diff --git a/chain/sync.go b/chain/sync.go index b99e27be0..91d212e37 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -5,13 +5,14 @@ import ( "context" "errors" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "os" "sort" "strconv" "strings" "time" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/Gurpartap/async" "github.com/hashicorp/go-multierror" "github.com/ipfs/go-cid" diff --git a/chain/sync_test.go b/chain/sync_test.go index 63188d74c..16e0d2ffb 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -3,11 +3,12 @@ package chain_test import ( "context" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "os" "testing" "time" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" diff --git a/chain/types/blockheader.go b/chain/types/blockheader.go index 8095616a5..0ec33fe42 100644 --- a/chain/types/blockheader.go +++ b/chain/types/blockheader.go @@ -2,9 +2,10 @@ package types import ( "bytes" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "math/big" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/minio/blake2b-simd" "github.com/filecoin-project/go-state-types/abi" diff --git a/chain/types/blockheader_test.go b/chain/types/blockheader_test.go index 4607e5b3e..f5faac3b3 100644 --- a/chain/types/blockheader_test.go +++ b/chain/types/blockheader_test.go @@ -7,6 +7,8 @@ import ( "reflect" "testing" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + cid "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" diff --git a/chain/vectors/gen/main.go b/chain/vectors/gen/main.go index 814bcebff..ecc2498b9 100644 --- a/chain/vectors/gen/main.go +++ b/chain/vectors/gen/main.go @@ -6,6 +6,8 @@ import ( "math/rand" "os" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/go-address" "golang.org/x/xerrors" diff --git a/chain/vm/gas.go b/chain/vm/gas.go index 23750491c..12acf6a21 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -2,6 +2,7 @@ package vm import ( "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/filecoin-project/go-address" diff --git a/chain/vm/gas_v0.go b/chain/vm/gas_v0.go index 3d2faa60d..e5ded440e 100644 --- a/chain/vm/gas_v0.go +++ b/chain/vm/gas_v0.go @@ -2,6 +2,7 @@ package vm import ( "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/filecoin-project/go-state-types/abi" diff --git a/chain/vm/syscalls.go b/chain/vm/syscalls.go index 9dba55131..3e221f61f 100644 --- a/chain/vm/syscalls.go +++ b/chain/vm/syscalls.go @@ -4,10 +4,11 @@ import ( "bytes" "context" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" goruntime "runtime" "sync" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/go-address" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" diff --git a/cli/state.go b/cli/state.go index 8ae8bf540..f84375782 100644 --- a/cli/state.go +++ b/cli/state.go @@ -5,7 +5,6 @@ import ( "context" "encoding/json" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime" "html/template" "io" "os" @@ -15,6 +14,8 @@ import ( "strings" "time" + "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/multiformats/go-multiaddr" "github.com/ipfs/go-cid" diff --git a/cmd/lotus-bench/main.go b/cmd/lotus-bench/main.go index 8545bfbd3..431bfdd44 100644 --- a/cmd/lotus-bench/main.go +++ b/cmd/lotus-bench/main.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "io/ioutil" "math/big" "math/rand" @@ -12,6 +11,8 @@ import ( "path/filepath" "time" + saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/docker/go-units" logging "github.com/ipfs/go-log/v2" "github.com/minio/blake2b-simd" @@ -236,7 +237,7 @@ var sealBenchCmd = &cli.Command{ } var sealTimings []SealingResult - var sealedSectors []proof.SectorInfo + var sealedSectors []saproof.SectorInfo if robench == "" { var err error @@ -279,7 +280,7 @@ var sealBenchCmd = &cli.Command{ } for _, s := range genm.Sectors { - sealedSectors = append(sealedSectors, proof.SectorInfo{ + sealedSectors = append(sealedSectors, saproof.SectorInfo{ SealedCID: s.CommR, SectorNumber: s.SectorID, SealProof: s.ProofType, @@ -304,7 +305,7 @@ var sealBenchCmd = &cli.Command{ return err } - candidates := make([]proof.SectorInfo, len(fcandidates)) + candidates := make([]saproof.SectorInfo, len(fcandidates)) for i, fcandidate := range fcandidates { candidates[i] = sealedSectors[fcandidate] } @@ -327,7 +328,7 @@ var sealBenchCmd = &cli.Command{ winnningpost2 := time.Now() - pvi1 := abi.WinningPoStVerifyInfo{ + pvi1 := saproof.WinningPoStVerifyInfo{ Randomness: abi.PoStRandomness(challenge[:]), Proofs: proof1, ChallengedSectors: candidates, @@ -343,7 +344,7 @@ var sealBenchCmd = &cli.Command{ verifyWinningPost1 := time.Now() - pvi2 := abi.WinningPoStVerifyInfo{ + pvi2 := saproof.WinningPoStVerifyInfo{ Randomness: abi.PoStRandomness(challenge[:]), Proofs: proof2, ChallengedSectors: candidates, @@ -375,7 +376,7 @@ var sealBenchCmd = &cli.Command{ windowpost2 := time.Now() - wpvi1 := proof.WindowPoStVerifyInfo{ + wpvi1 := saproof.WindowPoStVerifyInfo{ Randomness: challenge[:], Proofs: wproof1, ChallengedSectors: sealedSectors, @@ -391,7 +392,7 @@ var sealBenchCmd = &cli.Command{ verifyWindowpost1 := time.Now() - wpvi2 := proof.WindowPoStVerifyInfo{ + wpvi2 := saproof.WindowPoStVerifyInfo{ Randomness: challenge[:], Proofs: wproof2, ChallengedSectors: sealedSectors, @@ -463,10 +464,10 @@ type ParCfg struct { Commit int } -func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par ParCfg, mid abi.ActorID, sectorSize abi.SectorSize, ticketPreimage []byte, saveC2inp string, skipc2, skipunseal bool) ([]SealingResult, []proof.SectorInfo, error) { +func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par ParCfg, mid abi.ActorID, sectorSize abi.SectorSize, ticketPreimage []byte, saveC2inp string, skipc2, skipunseal bool) ([]SealingResult, []saproof.SectorInfo, error) { var pieces []abi.PieceInfo sealTimings := make([]SealingResult, numSectors) - sealedSectors := make([]proof.SectorInfo, numSectors) + sealedSectors := make([]saproof.SectorInfo, numSectors) preCommit2Sema := make(chan struct{}, par.PreCommit2) commitSema := make(chan struct{}, par.Commit) @@ -536,7 +537,7 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par precommit2 := time.Now() <-preCommit2Sema - sealedSectors[ix] = proof.SectorInfo{ + sealedSectors[ix] = saproof.SectorInfo{ SealProof: sb.SealProofType(), SectorNumber: i, SealedCID: cids.Sealed, @@ -588,7 +589,7 @@ func runSeals(sb *ffiwrapper.Sealer, sbfs *basicfs.Provider, numSectors int, par <-commitSema if !skipc2 { - svi := proof.SealVerifyInfo{ + svi := saproof.SealVerifyInfo{ SectorID: abi.SectorID{Miner: mid, Number: i}, SealedCID: cids.Sealed, SealProof: sb.SealProofType(), diff --git a/cmd/lotus-shed/proofs.go b/cmd/lotus-shed/proofs.go index 1b877d4ea..2379d8599 100644 --- a/cmd/lotus-shed/proofs.go +++ b/cmd/lotus-shed/proofs.go @@ -4,6 +4,8 @@ import ( "encoding/hex" "fmt" + saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/urfave/cli/v2" ffi "github.com/filecoin-project/filecoin-ffi" @@ -82,7 +84,7 @@ var verifySealProofCmd = &cli.Command{ snum := abi.SectorNumber(cctx.Uint64("sector-id")) - ok, err := ffi.VerifySeal(proof.SealVerifyInfo{ + ok, err := ffi.VerifySeal(saproof.SealVerifyInfo{ SectorID: abi.SectorID{ Miner: abi.ActorID(mid), Number: snum, diff --git a/conformance/stubs.go b/conformance/stubs.go index 5383a51f0..a7100892f 100644 --- a/conformance/stubs.go +++ b/conformance/stubs.go @@ -2,6 +2,7 @@ package conformance import ( "context" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/filecoin-project/go-address" diff --git a/extern/sector-storage/ffiwrapper/sealer_test.go b/extern/sector-storage/ffiwrapper/sealer_test.go index d089a92b6..ae1ede7eb 100644 --- a/extern/sector-storage/ffiwrapper/sealer_test.go +++ b/extern/sector-storage/ffiwrapper/sealer_test.go @@ -15,6 +15,8 @@ import ( "testing" "time" + saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log" @@ -91,7 +93,7 @@ func (s *seal) commit(t *testing.T, sb *Sealer, done func()) { t.Fatalf("%+v", err) } - ok, err := ProofVerifier.VerifySeal(proof.SealVerifyInfo{ + ok, err := ProofVerifier.VerifySeal(saproof.SealVerifyInfo{ SectorID: s.id, SealedCID: s.cids.Sealed, SealProof: sealProofType, diff --git a/extern/sector-storage/ffiwrapper/types.go b/extern/sector-storage/ffiwrapper/types.go index daf5cdbff..318dbd2b0 100644 --- a/extern/sector-storage/ffiwrapper/types.go +++ b/extern/sector-storage/ffiwrapper/types.go @@ -2,9 +2,10 @@ package ffiwrapper import ( "context" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "io" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-state-types/abi" diff --git a/extern/sector-storage/ffiwrapper/verifier_cgo.go b/extern/sector-storage/ffiwrapper/verifier_cgo.go index bd4e7e021..0af12da0b 100644 --- a/extern/sector-storage/ffiwrapper/verifier_cgo.go +++ b/extern/sector-storage/ffiwrapper/verifier_cgo.go @@ -4,6 +4,7 @@ package ffiwrapper import ( "context" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "golang.org/x/xerrors" diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index d4588c3fa..b70350ef8 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -5,11 +5,12 @@ import ( "context" "crypto/sha256" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "io" "math/rand" "sync" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + commcid "github.com/filecoin-project/go-fil-commcid" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-storage/storage" diff --git a/extern/storage-sealing/checks.go b/extern/storage-sealing/checks.go index 28802fe9f..906c9c106 100644 --- a/extern/storage-sealing/checks.go +++ b/extern/storage-sealing/checks.go @@ -3,6 +3,7 @@ package sealing import ( "bytes" "context" + saproof "github.com/filecoin-project/specs-actors/actors/runtime/proof" "golang.org/x/xerrors" diff --git a/miner/miner.go b/miner/miner.go index cba9e7b66..6d3595d58 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -6,10 +6,11 @@ import ( "crypto/rand" "encoding/binary" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "sync" "time" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/lotus/chain/gen/slashfilter" "github.com/filecoin-project/go-address" diff --git a/storage/adapter_storage_miner.go b/storage/adapter_storage_miner.go index f780097a6..2869e48e5 100644 --- a/storage/adapter_storage_miner.go +++ b/storage/adapter_storage_miner.go @@ -3,6 +3,7 @@ package storage import ( "bytes" "context" + "github.com/filecoin-project/go-bitfield" "github.com/ipfs/go-cid" diff --git a/storage/miner.go b/storage/miner.go index c68be87b3..a9728433b 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -3,9 +3,10 @@ package storage import ( "context" "errors" + "time" + "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/specs-actors/actors/runtime/proof" - "time" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 1fc7eeacc..51d71e331 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -4,9 +4,10 @@ import ( "bytes" "context" "errors" - "github.com/filecoin-project/specs-actors/actors/runtime/proof" "time" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" + "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/go-address" From 2db4b57013ecbc55968796fe8da241aa3b6f9f4b Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Thu, 3 Sep 2020 22:34:59 -0700 Subject: [PATCH 058/199] feat(markets): upgrade markets 0.6.0 --- api/api_full.go | 3 ++ api/apistruct/struct.go | 41 ++++++++++++++----------- cli/paych.go | 12 ++++++++ go.mod | 2 +- go.sum | 4 +-- markets/retrievaladapter/client.go | 48 +++++++++++++++++++----------- node/impl/client/client.go | 4 +++ node/modules/client.go | 5 ++-- 8 files changed, 78 insertions(+), 41 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 72bacad32..1cc6837be 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -273,6 +273,9 @@ type FullNode interface { // ClientListTransfers returns the status of all ongoing transfers of data ClientListDataTransfers(ctx context.Context) ([]DataTransferChannel, error) ClientDataTransferUpdates(ctx context.Context) (<-chan DataTransferChannel, error) + // ClientRetrieveTryRestartInsufficientFunds attempts to restart stalled retrievals on a given payment channel + // which are stuck due to insufficient funds + ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error // ClientUnimport removes references to the specified file from filestore //ClientUnimport(path string) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index e4946995d..3cf9a0add 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -137,24 +137,25 @@ type FullNodeStruct struct { WalletImport func(context.Context, *types.KeyInfo) (address.Address, error) `perm:"admin"` WalletDelete func(context.Context, address.Address) error `perm:"write"` - ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"` - ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"` - ClientRemoveImport func(ctx context.Context, importID multistore.StoreID) error `perm:"admin"` - ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"` - ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"` - ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"` - ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"` - ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"` - ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"` - ClientGetDealUpdates func(ctx context.Context) (<-chan api.DealInfo, error) `perm:"read"` - ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"` - ClientRetrieveWithEvents func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"` - ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"` - ClientCalcCommP func(ctx context.Context, inpath string) (*api.CommPRet, error) `perm:"read"` - ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"` - ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"` - ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"` - ClientDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"` + ClientImport func(ctx context.Context, ref api.FileRef) (*api.ImportRes, error) `perm:"admin"` + ClientListImports func(ctx context.Context) ([]api.Import, error) `perm:"write"` + ClientRemoveImport func(ctx context.Context, importID multistore.StoreID) error `perm:"admin"` + ClientHasLocal func(ctx context.Context, root cid.Cid) (bool, error) `perm:"write"` + ClientFindData func(ctx context.Context, root cid.Cid, piece *cid.Cid) ([]api.QueryOffer, error) `perm:"read"` + ClientMinerQueryOffer func(ctx context.Context, miner address.Address, root cid.Cid, piece *cid.Cid) (api.QueryOffer, error) `perm:"read"` + ClientStartDeal func(ctx context.Context, params *api.StartDealParams) (*cid.Cid, error) `perm:"admin"` + ClientGetDealInfo func(context.Context, cid.Cid) (*api.DealInfo, error) `perm:"read"` + ClientListDeals func(ctx context.Context) ([]api.DealInfo, error) `perm:"write"` + ClientGetDealUpdates func(ctx context.Context) (<-chan api.DealInfo, error) `perm:"read"` + ClientRetrieve func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) error `perm:"admin"` + ClientRetrieveWithEvents func(ctx context.Context, order api.RetrievalOrder, ref *api.FileRef) (<-chan marketevents.RetrievalEvent, error) `perm:"admin"` + ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*storagemarket.SignedStorageAsk, error) `perm:"read"` + ClientCalcCommP func(ctx context.Context, inpath string) (*api.CommPRet, error) `perm:"read"` + ClientGenCar func(ctx context.Context, ref api.FileRef, outpath string) error `perm:"write"` + ClientDealSize func(ctx context.Context, root cid.Cid) (api.DataSize, error) `perm:"read"` + ClientListDataTransfers func(ctx context.Context) ([]api.DataTransferChannel, error) `perm:"write"` + ClientDataTransferUpdates func(ctx context.Context) (<-chan api.DataTransferChannel, error) `perm:"write"` + ClientRetrieveTryRestartInsufficientFunds func(ctx context.Context, paymentChannel address.Address) error `perm:"write"` StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"` StateMinerSectors func(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` @@ -495,6 +496,10 @@ func (c *FullNodeStruct) ClientDataTransferUpdates(ctx context.Context) (<-chan return c.Internal.ClientDataTransferUpdates(ctx) } +func (c *FullNodeStruct) ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error { + return c.Internal.ClientRetrieveTryRestartInsufficientFunds(ctx, paymentChannel) +} + func (c *FullNodeStruct) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, tsk types.TipSetKey) (types.BigInt, error) { return c.Internal.GasEstimateGasPremium(ctx, nblocksincl, sender, gaslimit, tsk) } diff --git a/cli/paych.go b/cli/paych.go index 6e2104551..bcd8e33f0 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -36,6 +36,14 @@ var paychAddFundsCmd = &cli.Command{ Name: "add-funds", Usage: "Add funds to the payment channel between fromAddress and toAddress. Creates the payment channel if it doesn't already exist.", ArgsUsage: "[fromAddress toAddress amount]", + Flags: []cli.Flag{ + + &cli.BoolFlag{ + Name: "restart-retrievals", + Usage: "restart stalled retrieval deals on this payment channel", + Value: true, + }, + }, Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 3 { return ShowHelp(cctx, fmt.Errorf("must pass three arguments: ")) @@ -78,6 +86,10 @@ var paychAddFundsCmd = &cli.Command{ } fmt.Fprintln(cctx.App.Writer, chAddr) + restartRetrievals := cctx.Bool("restart-retrievals") + if restartRetrievals { + return api.ClientRetrieveTryRestartInsufficientFunds(ctx, chAddr) + } return nil }, } diff --git a/go.mod b/go.mod index 6250a7af1..9b0dafa3b 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-data-transfer v0.6.3 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a + github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 diff --git a/go.sum b/go.sum index f0626e8ed..9b370c970 100644 --- a/go.sum +++ b/go.sum @@ -251,8 +251,8 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a h1:SYWurOVYyEqajP3rr20F9UvkIpn6p9ewMk9yOg1kaVM= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b h1:Xe+ngO0+FV1JESIz9rlyzygwIEnI8M3bDvKqljdIoJA= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= diff --git a/markets/retrievaladapter/client.go b/markets/retrievaladapter/client.go index de94f50a9..cdb4caa12 100644 --- a/markets/retrievaladapter/client.go +++ b/markets/retrievaladapter/client.go @@ -3,8 +3,6 @@ package retrievaladapter import ( "context" - "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/go-address" @@ -17,20 +15,18 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/impl/full" payapi "github.com/filecoin-project/lotus/node/impl/paych" - "github.com/filecoin-project/lotus/paychmgr" ) type retrievalClientNode struct { chainAPI full.ChainAPI - pmgr *paychmgr.Manager payAPI payapi.PaychAPI stateAPI full.StateAPI } // NewRetrievalClientNode returns a new node adapter for a retrieval client that talks to the // Lotus Node -func NewRetrievalClientNode(pmgr *paychmgr.Manager, payAPI payapi.PaychAPI, chainAPI full.ChainAPI, stateAPI full.StateAPI) retrievalmarket.RetrievalClientNode { - return &retrievalClientNode{pmgr: pmgr, payAPI: payAPI, chainAPI: chainAPI, stateAPI: stateAPI} +func NewRetrievalClientNode(payAPI payapi.PaychAPI, chainAPI full.ChainAPI, stateAPI full.StateAPI) retrievalmarket.RetrievalClientNode { + return &retrievalClientNode{payAPI: payAPI, chainAPI: chainAPI, stateAPI: stateAPI} } // GetOrCreatePaymentChannel sets up a new payment channel if one does not exist @@ -39,14 +35,18 @@ func NewRetrievalClientNode(pmgr *paychmgr.Manager, payAPI payapi.PaychAPI, chai func (rcn *retrievalClientNode) GetOrCreatePaymentChannel(ctx context.Context, clientAddress address.Address, minerAddress address.Address, clientFundsAvailable abi.TokenAmount, tok shared.TipSetToken) (address.Address, cid.Cid, error) { // TODO: respect the provided TipSetToken (a serialized TipSetKey) when // querying the chain - return rcn.pmgr.GetPaych(ctx, clientAddress, minerAddress, clientFundsAvailable) + ci, err := rcn.payAPI.PaychGet(ctx, clientAddress, minerAddress, clientFundsAvailable) + if err != nil { + return address.Undef, cid.Undef, err + } + return ci.Channel, ci.WaitSentinel, nil } // Allocate late creates a lane within a payment channel so that calls to // CreatePaymentVoucher will automatically make vouchers only for the difference // in total -func (rcn *retrievalClientNode) AllocateLane(paymentChannel address.Address) (uint64, error) { - return rcn.pmgr.AllocateLane(paymentChannel) +func (rcn *retrievalClientNode) AllocateLane(ctx context.Context, paymentChannel address.Address) (uint64, error) { + return rcn.payAPI.PaychAllocateLane(ctx, paymentChannel) } // CreatePaymentVoucher creates a new payment voucher in the given lane for a @@ -60,7 +60,7 @@ func (rcn *retrievalClientNode) CreatePaymentVoucher(ctx context.Context, paymen return nil, err } if voucher.Voucher == nil { - return nil, xerrors.Errorf("Could not create voucher - shortfall: %d", voucher.Shortfall) + return nil, retrievalmarket.NewShortfallError(voucher.Shortfall) } return voucher.Voucher, nil } @@ -74,15 +74,29 @@ func (rcn *retrievalClientNode) GetChainHead(ctx context.Context) (shared.TipSet return head.Key().Bytes(), head.Height(), nil } -// WaitForPaymentChannelAddFunds waits messageCID to appear on chain. If it doesn't appear within -// defaultMsgWaitTimeout it returns error -func (rcn *retrievalClientNode) WaitForPaymentChannelAddFunds(messageCID cid.Cid) error { - _, err := rcn.payAPI.PaychMgr.GetPaychWaitReady(context.TODO(), messageCID) - return err +func (rcn *retrievalClientNode) WaitForPaymentChannelReady(ctx context.Context, messageCID cid.Cid) (address.Address, error) { + return rcn.payAPI.PaychGetWaitReady(ctx, messageCID) } -func (rcn *retrievalClientNode) WaitForPaymentChannelCreation(messageCID cid.Cid) (address.Address, error) { - return rcn.payAPI.PaychMgr.GetPaychWaitReady(context.TODO(), messageCID) +func (rcn *retrievalClientNode) CheckAvailableFunds(ctx context.Context, paymentChannel address.Address) (retrievalmarket.ChannelAvailableFunds, error) { + // this doesn't actually work potentially -- the looked up from/to may pull up data for a different payment channel if for some reason the + // given address is settling + ci, err := rcn.payAPI.PaychMgr.GetChannelInfo(paymentChannel) + if err != nil { + return retrievalmarket.ChannelAvailableFunds{}, err + } + // assuming this is outbound... again, this is not a final implementation, pending PaychAvailableFundsByAddress + channelAvailableFunds, err := rcn.payAPI.PaychAvailableFunds(ci.Control, ci.Target) + if err != nil { + return retrievalmarket.ChannelAvailableFunds{}, err + } + return retrievalmarket.ChannelAvailableFunds{ + ConfirmedAmt: channelAvailableFunds.ConfirmedAmt, + PendingAmt: channelAvailableFunds.PendingAmt, + PendingWaitSentinel: channelAvailableFunds.PendingWaitSentinel, + QueuedAmt: channelAvailableFunds.QueuedAmt, + VoucherReedeemedAmt: channelAvailableFunds.VoucherReedeemedAmt, + }, nil } func (rcn *retrievalClientNode) GetKnownAddresses(ctx context.Context, p retrievalmarket.RetrievalPeer, encodedTs shared.TipSetToken) ([]multiaddr.Multiaddr, error) { diff --git a/node/impl/client/client.go b/node/impl/client/client.go index ed1e6cd05..d12a4ae73 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -847,3 +847,7 @@ func newDealInfo(v storagemarket.ClientDeal) api.DealInfo { CreationTime: v.CreationTime.Time(), } } + +func (a *API) ClientRetrieveTryRestartInsufficientFunds(ctx context.Context, paymentChannel address.Address) error { + return a.Retrieval.TryRestartInsufficientFunds(paymentChannel) +} diff --git a/node/modules/client.go b/node/modules/client.go index bf534350e..63633c0e3 100644 --- a/node/modules/client.go +++ b/node/modules/client.go @@ -35,7 +35,6 @@ import ( "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/node/repo/importmgr" "github.com/filecoin-project/lotus/node/repo/retrievalstoremgr" - "github.com/filecoin-project/lotus/paychmgr" ) func ClientMultiDatastore(lc fx.Lifecycle, r repo.LockedRepo) (dtypes.ClientMultiDstore, error) { @@ -130,8 +129,8 @@ func StorageClient(lc fx.Lifecycle, h host.Host, ibs dtypes.ClientBlockstore, md } // RetrievalClient creates a new retrieval client attached to the client blockstore -func RetrievalClient(lc fx.Lifecycle, h host.Host, mds dtypes.ClientMultiDstore, dt dtypes.ClientDataTransfer, pmgr *paychmgr.Manager, payAPI payapi.PaychAPI, resolver retrievalmarket.PeerResolver, ds dtypes.MetadataDS, chainAPI full.ChainAPI, stateAPI full.StateAPI) (retrievalmarket.RetrievalClient, error) { - adapter := retrievaladapter.NewRetrievalClientNode(pmgr, payAPI, chainAPI, stateAPI) +func RetrievalClient(lc fx.Lifecycle, h host.Host, mds dtypes.ClientMultiDstore, dt dtypes.ClientDataTransfer, payAPI payapi.PaychAPI, resolver retrievalmarket.PeerResolver, ds dtypes.MetadataDS, chainAPI full.ChainAPI, stateAPI full.StateAPI) (retrievalmarket.RetrievalClient, error) { + adapter := retrievaladapter.NewRetrievalClientNode(payAPI, chainAPI, stateAPI) network := rmnet.NewFromLibp2pHost(h) sc := storedcounter.New(ds, datastore.NewKey("/retr")) client, err := retrievalimpl.NewClient(network, mds, dt, adapter, resolver, namespace.Wrap(ds, datastore.NewKey("/retrievals/client")), sc) From 5ad8e23eae0a386622a3121d4e6ebaf2dc64e091 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Mon, 7 Sep 2020 05:33:35 -0700 Subject: [PATCH 059/199] feat(markets): use new api --- markets/retrievaladapter/client.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/markets/retrievaladapter/client.go b/markets/retrievaladapter/client.go index cdb4caa12..17c56c167 100644 --- a/markets/retrievaladapter/client.go +++ b/markets/retrievaladapter/client.go @@ -79,14 +79,8 @@ func (rcn *retrievalClientNode) WaitForPaymentChannelReady(ctx context.Context, } func (rcn *retrievalClientNode) CheckAvailableFunds(ctx context.Context, paymentChannel address.Address) (retrievalmarket.ChannelAvailableFunds, error) { - // this doesn't actually work potentially -- the looked up from/to may pull up data for a different payment channel if for some reason the - // given address is settling - ci, err := rcn.payAPI.PaychMgr.GetChannelInfo(paymentChannel) - if err != nil { - return retrievalmarket.ChannelAvailableFunds{}, err - } - // assuming this is outbound... again, this is not a final implementation, pending PaychAvailableFundsByAddress - channelAvailableFunds, err := rcn.payAPI.PaychAvailableFunds(ci.Control, ci.Target) + + channelAvailableFunds, err := rcn.payAPI.PaychAvailableFunds(paymentChannel) if err != nil { return retrievalmarket.ChannelAvailableFunds{}, err } From 04e34b8ca7e2f842f97cff879d641c30b9efa0ef Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Mon, 7 Sep 2020 05:35:29 -0700 Subject: [PATCH 060/199] docs(apidocs): run docsgen --- documentation/en/api-methods.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index dd5c13815..64f0d272a 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -46,6 +46,7 @@ * [ClientQueryAsk](#ClientQueryAsk) * [ClientRemoveImport](#ClientRemoveImport) * [ClientRetrieve](#ClientRetrieve) + * [ClientRetrieveTryRestartInsufficientFunds](#ClientRetrieveTryRestartInsufficientFunds) * [ClientRetrieveWithEvents](#ClientRetrieveWithEvents) * [ClientStartDeal](#ClientStartDeal) * [Gas](#Gas) @@ -1159,6 +1160,22 @@ Inputs: Response: `{}` +### ClientRetrieveTryRestartInsufficientFunds +ClientRetrieveTryRestartInsufficientFunds attempts to restart stalled retrievals on a given payment channel +which are stuck due to insufficient funds + + +Perms: write + +Inputs: +```json +[ + "t01234" +] +``` + +Response: `{}` + ### ClientRetrieveWithEvents ClientRetrieveWithEvents initiates the retrieval of a file, as specified in the order, and provides a channel of status updates. From 4367d74102ab2b512286976b850cf5b784935730 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 7 Sep 2020 15:40:30 -0400 Subject: [PATCH 061/199] Update statediff and test-vectors --- go.mod | 9 +++------ go.sum | 12 ++++++++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 9b0dafa3b..7fb165921 100644 --- a/go.mod +++ b/go.mod @@ -7,14 +7,12 @@ replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-al require ( contrib.go.opencensus.io/exporter/jaeger v0.1.0 contrib.go.opencensus.io/exporter/prometheus v0.1.0 - github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect github.com/BurntSushi/toml v0.3.1 github.com/GeertJohan/go.rice v1.0.0 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/coreos/go-systemd/v22 v22.0.0 - github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.0.3 github.com/docker/go-units v0.4.0 @@ -30,7 +28,7 @@ require ( github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-data-transfer v0.6.3 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b + github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 @@ -41,8 +39,8 @@ require ( github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/specs-actors v0.9.6 github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 - github.com/filecoin-project/statediff v0.0.1 - github.com/filecoin-project/test-vectors v0.0.0-20200903223506-84da0a5ea125 + github.com/filecoin-project/statediff v0.0.2-0.20200907191002-32528b7e977a + github.com/filecoin-project/test-vectors v0.0.0-20200907193218-2c0739eccce6 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 github.com/google/uuid v1.1.1 @@ -120,7 +118,6 @@ require ( github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 go.opencensus.io v0.22.4 - go.uber.org/dig v1.10.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/multierr v1.5.0 go.uber.org/zap v1.15.0 diff --git a/go.sum b/go.sum index 9b370c970..57f693bfd 100644 --- a/go.sum +++ b/go.sum @@ -223,6 +223,7 @@ github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGj github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef h1:MtQRSnJLsQOOlmsd/Ua5KWXimpxcaa715h6FUh/eJPY= github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef/go.mod h1:SMj5VK1pYgqC8FXVEtOBRTc+9AIrYu+C+K3tAXi2Rk8= +github.com/filecoin-project/chain-validation v0.0.6-0.20200907020853-f4e4e7417fea/go.mod h1:pKcH/ShsOvCpO2qnsGFzEJ0NMJdBenPRk4Uu/xpIEkY= 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.3 h1:eVfbdjEbpbzIrbiSa+PiGUY+oDK9HnUn+M1R/ggoHf8= @@ -251,8 +252,8 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b h1:Xe+ngO0+FV1JESIz9rlyzygwIEnI8M3bDvKqljdIoJA= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a h1:SYWurOVYyEqajP3rr20F9UvkIpn6p9ewMk9yOg1kaVM= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= @@ -279,6 +280,7 @@ github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= github.com/filecoin-project/lotus v0.4.3-0.20200820203717-d1718369a182/go.mod h1:biFZPQ/YyQGfkHUmHMiaNf2hnD6zm1+OAXPQYQ61Zkg= github.com/filecoin-project/lotus v0.5.8-0.20200903221953-ada5e6ae68cf/go.mod h1:wxuzS4ozpCFThia18G+J5P0Jp/DSiq9ezzJF1yvZuP4= +github.com/filecoin-project/lotus v0.5.11-0.20200907070510-420a8706da6d/go.mod h1:SVrkI6GQzqSeSuaZ6KsHih4Dh800q9HSFQCtBnyMYBI= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= @@ -299,6 +301,8 @@ github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/statediff v0.0.1 h1:lym6d5wNnzr+5Uc/6RRWx1hgwb+tCKn2mFIK0Eb1Q18= github.com/filecoin-project/statediff v0.0.1/go.mod h1:qNWauolLFEzOiA4LNWermBRVNbaZHfPcPevumZeh+hE= +github.com/filecoin-project/statediff v0.0.2-0.20200907191002-32528b7e977a h1:Dw2SjBspGlJq4nEi+Kkb7gpx7ZRJeZnWOzd3xYJ6gEs= +github.com/filecoin-project/statediff v0.0.2-0.20200907191002-32528b7e977a/go.mod h1:ISu0/NV2mFX8kmLgDQIWVR5uBsMx+Au1TlIT9UsFRR8= github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f/go.mod h1:1CGbd11KkHuyWPT+xwwCol1zl/jnlpiKD2L4fzKxaiI= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= @@ -690,6 +694,7 @@ github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0 github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= @@ -1189,6 +1194,7 @@ github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJE github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c h1:5bFTChQxSKNwy8ALwOebjekYExl9HTT9urdawqC95tA= github.com/nikkolasg/hexjson v0.0.0-20181101101858-78e39397e00c/go.mod h1:7qN3Y0BvzRUf4LofcoJplQL10lsFDb4PYlePTVwrP28= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg= github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -1405,7 +1411,9 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= From 529002c2b74df6b0d99ec207818f84770a4128ec Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 7 Sep 2020 15:47:30 -0400 Subject: [PATCH 062/199] Update to markets master --- go.mod | 7 +++++-- go.sum | 8 ++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 7fb165921..86b76f50d 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,14 @@ replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-al require ( contrib.go.opencensus.io/exporter/jaeger v0.1.0 contrib.go.opencensus.io/exporter/prometheus v0.1.0 + github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect github.com/BurntSushi/toml v0.3.1 github.com/GeertJohan/go.rice v1.0.0 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/coreos/go-systemd/v22 v22.0.0 + github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.0.3 github.com/docker/go-units v0.4.0 @@ -28,7 +30,7 @@ require ( github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-data-transfer v0.6.3 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a + github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 @@ -39,7 +41,7 @@ require ( github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/specs-actors v0.9.6 github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 - github.com/filecoin-project/statediff v0.0.2-0.20200907191002-32528b7e977a + github.com/filecoin-project/statediff v0.0.1 github.com/filecoin-project/test-vectors v0.0.0-20200907193218-2c0739eccce6 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 @@ -118,6 +120,7 @@ require ( github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 go.opencensus.io v0.22.4 + go.uber.org/dig v1.10.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/multierr v1.5.0 go.uber.org/zap v1.15.0 diff --git a/go.sum b/go.sum index 57f693bfd..c0a367217 100644 --- a/go.sum +++ b/go.sum @@ -223,7 +223,6 @@ github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGj github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef h1:MtQRSnJLsQOOlmsd/Ua5KWXimpxcaa715h6FUh/eJPY= github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef/go.mod h1:SMj5VK1pYgqC8FXVEtOBRTc+9AIrYu+C+K3tAXi2Rk8= -github.com/filecoin-project/chain-validation v0.0.6-0.20200907020853-f4e4e7417fea/go.mod h1:pKcH/ShsOvCpO2qnsGFzEJ0NMJdBenPRk4Uu/xpIEkY= 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.3 h1:eVfbdjEbpbzIrbiSa+PiGUY+oDK9HnUn+M1R/ggoHf8= @@ -252,8 +251,8 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a h1:SYWurOVYyEqajP3rr20F9UvkIpn6p9ewMk9yOg1kaVM= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b h1:Xe+ngO0+FV1JESIz9rlyzygwIEnI8M3bDvKqljdIoJA= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= @@ -280,7 +279,6 @@ github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= github.com/filecoin-project/lotus v0.4.3-0.20200820203717-d1718369a182/go.mod h1:biFZPQ/YyQGfkHUmHMiaNf2hnD6zm1+OAXPQYQ61Zkg= github.com/filecoin-project/lotus v0.5.8-0.20200903221953-ada5e6ae68cf/go.mod h1:wxuzS4ozpCFThia18G+J5P0Jp/DSiq9ezzJF1yvZuP4= -github.com/filecoin-project/lotus v0.5.11-0.20200907070510-420a8706da6d/go.mod h1:SVrkI6GQzqSeSuaZ6KsHih4Dh800q9HSFQCtBnyMYBI= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= @@ -301,8 +299,6 @@ github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/statediff v0.0.1 h1:lym6d5wNnzr+5Uc/6RRWx1hgwb+tCKn2mFIK0Eb1Q18= github.com/filecoin-project/statediff v0.0.1/go.mod h1:qNWauolLFEzOiA4LNWermBRVNbaZHfPcPevumZeh+hE= -github.com/filecoin-project/statediff v0.0.2-0.20200907191002-32528b7e977a h1:Dw2SjBspGlJq4nEi+Kkb7gpx7ZRJeZnWOzd3xYJ6gEs= -github.com/filecoin-project/statediff v0.0.2-0.20200907191002-32528b7e977a/go.mod h1:ISu0/NV2mFX8kmLgDQIWVR5uBsMx+Au1TlIT9UsFRR8= github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f/go.mod h1:1CGbd11KkHuyWPT+xwwCol1zl/jnlpiKD2L4fzKxaiI= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= From 5654322f54e7495d080807fc65f64133f09a4cc4 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 7 Sep 2020 11:19:45 -0700 Subject: [PATCH 063/199] introduce logic to perform base fee tamping around the upgrade time Signed-off-by: Jakub Sztandera --- build/params_testnet.go | 3 +++ chain/store/basefee.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/build/params_testnet.go b/build/params_testnet.go index 0d5602d70..92d9eba48 100644 --- a/build/params_testnet.go +++ b/build/params_testnet.go @@ -12,6 +12,9 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/power" ) +const UpgradeBreezeHeight = 42000 +const BreezeGasTampingDuration = 120 + func init() { power.ConsensusMinerMinPower = big.NewInt(10 << 40) miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ diff --git a/chain/store/basefee.go b/chain/store/basefee.go index 9d6322639..69970dd96 100644 --- a/chain/store/basefee.go +++ b/chain/store/basefee.go @@ -40,6 +40,10 @@ func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int } func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi.TokenAmount, error) { + if ts.Height() > build.UpgradeBreezeHeight && ts.Height() < build.UpgradeBreezeHeight+build.BreezeGasTampingDuration { + return abi.NewTokenAmount(100), nil + } + zero := abi.NewTokenAmount(0) // totalLimit is sum of GasLimits of unique messages in a tipset From 502d3fb335305bdb0bdaa1e3d555bef83b0d21e9 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 7 Sep 2020 11:46:46 -0700 Subject: [PATCH 064/199] set values for test networks Signed-off-by: Jakub Sztandera --- build/params_2k.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/params_2k.go b/build/params_2k.go index 98506531d..a24e4421c 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -10,6 +10,9 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" ) +const UpgradeBreezeHeight = 0 +const BreezeGasTampingDuration = 0 + func init() { power.ConsensusMinerMinPower = big.NewInt(2048) miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ From 5d5c964d06b5dd1659a9ca2ceb441c24865319ba Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 7 Sep 2020 11:51:33 -0700 Subject: [PATCH 065/199] set correct upgrade height Signed-off-by: Jakub Sztandera --- build/params_testnet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/params_testnet.go b/build/params_testnet.go index 92d9eba48..4a7523287 100644 --- a/build/params_testnet.go +++ b/build/params_testnet.go @@ -12,7 +12,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/power" ) -const UpgradeBreezeHeight = 42000 +const UpgradeBreezeHeight = 41280 const BreezeGasTampingDuration = 120 func init() { From baaec9db878d01618fc10f7e4e6baf9ecfe6ef49 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Mon, 7 Sep 2020 21:31:07 +0200 Subject: [PATCH 066/199] Fix testground build Signed-off-by: Jakub Sztandera --- build/params_testground.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/params_testground.go b/build/params_testground.go index 476b95fee..06d4aecc5 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -69,4 +69,7 @@ var ( PackingEfficiencyNum int64 = 4 PackingEfficiencyDenom int64 = 5 + + UpgradeBreezeHeight abi.ChainEpoch = 0 + BreezeGasTampingDuration abi.ChainEpoch = 0 ) From 97fddc45d930cfe8d5427195353e310c30de7852 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 22:15:17 +0300 Subject: [PATCH 067/199] temporarily allow negative perfoming chains Signed-off-by: Jakub Sztandera --- chain/messagepool/messagepool.go | 6 +++++- chain/messagepool/repub.go | 2 +- chain/messagepool/selection.go | 26 +++++++++++++------------- chain/messagepool/selection_test.go | 5 +++++ 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 111ed2848..0b9b22336 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -81,6 +81,10 @@ const ( localUpdates = "update" ) +// this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go +// away in the next fork. +var allowNegativeChains = true + func init() { // if the republish interval is too short compared to the pubsub timecache, adjust it minInterval := pubsub.TimeCacheDuration + time.Duration(build.PropagationDelaySecs) @@ -389,7 +393,7 @@ func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.T // Note that for local messages, we always add them so that they can be accepted and republished // automatically. publish := local - if len(curTs.Blocks()) > 0 { + if !allowNegativeChains && len(curTs.Blocks()) > 0 { baseFee := curTs.Blocks()[0].ParentBaseFee baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index 648466629..bde035985 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -100,7 +100,7 @@ loop: // check the baseFee lower bound -- only republish messages that can be included in the chain // within the next 20 blocks. for _, m := range chain.msgs { - if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { + if !allowNegativeChains && m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { chain.Invalidate() continue loop } diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 5b9a09f35..bd5a40705 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -100,7 +100,7 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 return chains[i].Before(chains[j]) }) - if len(chains) != 0 && chains[0].gasPerf < 0 { + if !allowNegativeChains && len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf) return result, nil } @@ -153,7 +153,7 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 last := len(chains) for i, chain := range chains { // did we run out of performing chains? - if chain.gasPerf < 0 { + if !allowNegativeChains && chain.gasPerf < 0 { break } @@ -217,7 +217,7 @@ tailLoop: for gasLimit >= minGas && last < len(chains) { // trim if necessary if chains[last].gasLimit > gasLimit { - chains[last].Trim(gasLimit, mp, baseFee, false) + chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains) } // push down if it hasn't been invalidated @@ -243,7 +243,7 @@ tailLoop: } // if gasPerf < 0 we have no more profitable chains - if chain.gasPerf < 0 { + if !allowNegativeChains && chain.gasPerf < 0 { break tailLoop } @@ -284,7 +284,7 @@ tailLoop: } // dependencies fit, just trim it - chain.Trim(gasLimit-depGasLimit, mp, baseFee, false) + chain.Trim(gasLimit-depGasLimit, mp, baseFee, allowNegativeChains) last += i continue tailLoop } @@ -349,7 +349,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S return chains[i].Before(chains[j]) }) - if len(chains) != 0 && chains[0].gasPerf < 0 { + if !allowNegativeChains && len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf) return result, nil } @@ -360,7 +360,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S last := len(chains) for i, chain := range chains { // did we run out of performing chains? - if chain.gasPerf < 0 { + if !allowNegativeChains && chain.gasPerf < 0 { break } @@ -389,7 +389,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S tailLoop: for gasLimit >= minGas && last < len(chains) { // trim - chains[last].Trim(gasLimit, mp, baseFee, false) + chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains) // push down if it hasn't been invalidated if chains[last].valid { @@ -409,7 +409,7 @@ tailLoop: } // if gasPerf < 0 we have no more profitable chains - if chain.gasPerf < 0 { + if !allowNegativeChains && chain.gasPerf < 0 { break tailLoop } @@ -471,7 +471,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui return chains[i].Before(chains[j]) }) - if len(chains) != 0 && chains[0].gasPerf < 0 { + if !allowNegativeChains && len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all priority messages in mpool have negative gas performance", "bestGasPerf", chains[0].gasPerf) return nil, gasLimit } @@ -479,7 +479,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui // 3. Merge chains until the block limit, as long as they have non-negative gas performance last := len(chains) for i, chain := range chains { - if chain.gasPerf < 0 { + if !allowNegativeChains && chain.gasPerf < 0 { break } @@ -497,7 +497,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui tailLoop: for gasLimit >= minGas && last < len(chains) { // trim, discarding negative performing messages - chains[last].Trim(gasLimit, mp, baseFee, false) + chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains) // push down if it hasn't been invalidated if chains[last].valid { @@ -517,7 +517,7 @@ tailLoop: } // if gasPerf < 0 we have no more profitable chains - if chain.gasPerf < 0 { + if !allowNegativeChains && chain.gasPerf < 0 { break tailLoop } diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 2f9833ee2..4db4267bd 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -729,6 +729,11 @@ func TestPriorityMessageSelection2(t *testing.T) { } func TestPriorityMessageSelection3(t *testing.T) { + allowNegativeChains = false + defer func() { + allowNegativeChains = true + }() + mp, tma := makeTestMpool() // the actors From 172ff846fd72981adcca5fd32a6b2e45eb20d896 Mon Sep 17 00:00:00 2001 From: vyzo Date: Mon, 7 Sep 2020 22:28:23 +0300 Subject: [PATCH 068/199] decouple negative chain selection from base fee lower bound validation Signed-off-by: Jakub Sztandera --- chain/messagepool/messagepool.go | 4 ++-- chain/messagepool/selection.go | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 0b9b22336..09b888101 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -83,7 +83,7 @@ const ( // this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go // away in the next fork. -var allowNegativeChains = true +var strictBaseFeeValidation = false func init() { // if the republish interval is too short compared to the pubsub timecache, adjust it @@ -393,7 +393,7 @@ func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.T // Note that for local messages, we always add them so that they can be accepted and republished // automatically. publish := local - if !allowNegativeChains && len(curTs.Blocks()) > 0 { + if strictBaseFeeValidation && len(curTs.Blocks()) > 0 { baseFee := curTs.Blocks()[0].ParentBaseFee baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index bd5a40705..669b81b54 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -18,6 +18,10 @@ import ( var bigBlockGasLimit = big.NewInt(build.BlockGasLimit) +// this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go +// away in the next fork. +var allowNegativeChains = true + const MaxBlocks = 15 type msgChain struct { From 835b7eb6f76b7fe1f3fbdecc6afbdf923501e877 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Mon, 7 Sep 2020 21:41:23 +0200 Subject: [PATCH 069/199] Make allowNegativeChains a function Signed-off-by: Jakub Sztandera --- chain/messagepool/repub.go | 2 +- chain/messagepool/selection.go | 31 ++++++++++++++++------------- chain/messagepool/selection_test.go | 5 +---- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index bde035985..d1b1116c5 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -100,7 +100,7 @@ loop: // check the baseFee lower bound -- only republish messages that can be included in the chain // within the next 20 blocks. for _, m := range chain.msgs { - if !allowNegativeChains && m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { + if !allowNegativeChains(ts.Height()) && m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { chain.Invalidate() continue loop } diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 669b81b54..4655c8f88 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -14,13 +14,16 @@ import ( "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" + "github.com/filecoin-project/specs-actors/actors/abi" ) var bigBlockGasLimit = big.NewInt(build.BlockGasLimit) // this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go // away in the next fork. -var allowNegativeChains = true +func allowNegativeChains(epoch abi.ChainEpoch) bool { + return epoch < 100000000000 +} const MaxBlocks = 15 @@ -104,7 +107,7 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 return chains[i].Before(chains[j]) }) - if !allowNegativeChains && len(chains) != 0 && chains[0].gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf) return result, nil } @@ -157,7 +160,7 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 last := len(chains) for i, chain := range chains { // did we run out of performing chains? - if !allowNegativeChains && chain.gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { break } @@ -221,7 +224,7 @@ tailLoop: for gasLimit >= minGas && last < len(chains) { // trim if necessary if chains[last].gasLimit > gasLimit { - chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains) + chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains(curTs.Height())) } // push down if it hasn't been invalidated @@ -247,7 +250,7 @@ tailLoop: } // if gasPerf < 0 we have no more profitable chains - if !allowNegativeChains && chain.gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { break tailLoop } @@ -288,7 +291,7 @@ tailLoop: } // dependencies fit, just trim it - chain.Trim(gasLimit-depGasLimit, mp, baseFee, allowNegativeChains) + chain.Trim(gasLimit-depGasLimit, mp, baseFee, allowNegativeChains(curTs.Height())) last += i continue tailLoop } @@ -353,7 +356,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S return chains[i].Before(chains[j]) }) - if !allowNegativeChains && len(chains) != 0 && chains[0].gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all messages in mpool have non-positive gas performance", "bestGasPerf", chains[0].gasPerf) return result, nil } @@ -364,7 +367,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S last := len(chains) for i, chain := range chains { // did we run out of performing chains? - if !allowNegativeChains && chain.gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { break } @@ -393,7 +396,7 @@ func (mp *MessagePool) selectMessagesGreedy(curTs, ts *types.TipSet) ([]*types.S tailLoop: for gasLimit >= minGas && last < len(chains) { // trim - chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains) + chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains(curTs.Height())) // push down if it hasn't been invalidated if chains[last].valid { @@ -413,7 +416,7 @@ tailLoop: } // if gasPerf < 0 we have no more profitable chains - if !allowNegativeChains && chain.gasPerf < 0 { + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { break tailLoop } @@ -475,7 +478,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui return chains[i].Before(chains[j]) }) - if !allowNegativeChains && len(chains) != 0 && chains[0].gasPerf < 0 { + if !allowNegativeChains(ts.Height()) && len(chains) != 0 && chains[0].gasPerf < 0 { log.Warnw("all priority messages in mpool have negative gas performance", "bestGasPerf", chains[0].gasPerf) return nil, gasLimit } @@ -483,7 +486,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui // 3. Merge chains until the block limit, as long as they have non-negative gas performance last := len(chains) for i, chain := range chains { - if !allowNegativeChains && chain.gasPerf < 0 { + if !allowNegativeChains(ts.Height()) && chain.gasPerf < 0 { break } @@ -501,7 +504,7 @@ func (mp *MessagePool) selectPriorityMessages(pending map[address.Address]map[ui tailLoop: for gasLimit >= minGas && last < len(chains) { // trim, discarding negative performing messages - chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains) + chains[last].Trim(gasLimit, mp, baseFee, allowNegativeChains(ts.Height())) // push down if it hasn't been invalidated if chains[last].valid { @@ -521,7 +524,7 @@ tailLoop: } // if gasPerf < 0 we have no more profitable chains - if !allowNegativeChains && chain.gasPerf < 0 { + if !allowNegativeChains(ts.Height()) && chain.gasPerf < 0 { break tailLoop } diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 4db4267bd..489a41eab 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -729,10 +729,7 @@ func TestPriorityMessageSelection2(t *testing.T) { } func TestPriorityMessageSelection3(t *testing.T) { - allowNegativeChains = false - defer func() { - allowNegativeChains = true - }() + t.Skip("reenable after removing allow negative") mp, tma := makeTestMpool() From ce0e9594dfb6507463c153c2c2a3070856497951 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Mon, 7 Sep 2020 22:19:13 +0200 Subject: [PATCH 070/199] Update to go-state-types Signed-off-by: Jakub Sztandera --- chain/messagepool/selection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 4655c8f88..8a0f94bd5 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -9,12 +9,12 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" tbig "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" - "github.com/filecoin-project/specs-actors/actors/abi" ) var bigBlockGasLimit = big.NewInt(build.BlockGasLimit) From 704db225d1eae6f0b723bcce06b326e5a2fde78b Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Mon, 7 Sep 2020 22:45:06 +0200 Subject: [PATCH 071/199] Update the fork point Signed-off-by: Jakub Sztandera --- chain/messagepool/selection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 8a0f94bd5..792d4ca50 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -22,7 +22,7 @@ var bigBlockGasLimit = big.NewInt(build.BlockGasLimit) // this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go // away in the next fork. func allowNegativeChains(epoch abi.ChainEpoch) bool { - return epoch < 100000000000 + return epoch < build.BreezeGasTampingDuration+5 } const MaxBlocks = 15 From 46ee2eeded7007838b4c18b754ce16d60e6c2adf Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Mon, 7 Sep 2020 23:07:33 +0200 Subject: [PATCH 072/199] Upgrade to correct fork treshold Signed-off-by: Jakub Sztandera --- chain/messagepool/selection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 792d4ca50..454540dbd 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -22,7 +22,7 @@ var bigBlockGasLimit = big.NewInt(build.BlockGasLimit) // this is *temporary* mutilation until we have implemented uncapped miner penalties -- it will go // away in the next fork. func allowNegativeChains(epoch abi.ChainEpoch) bool { - return epoch < build.BreezeGasTampingDuration+5 + return epoch < build.UpgradeBreezeHeight+5 } const MaxBlocks = 15 From 6eea5dd1093dc9d3e7a1c0bebe62e53fbd8441b2 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 7 Sep 2020 16:01:09 -0400 Subject: [PATCH 073/199] Update to specs 0.9.7 and markets 0.6.0 --- chain/gen/genesis/genesis.go | 7 +++++++ chain/gen/genesis/miners.go | 5 +++++ chain/stmgr/call.go | 2 ++ chain/stmgr/stmgr.go | 11 +++++++++++ chain/stmgr/utils.go | 1 + chain/vm/runtime.go | 4 ++++ chain/vm/vm.go | 10 ++++++++++ go.mod | 4 ++-- go.sum | 6 ++++-- node/impl/full/state.go | 8 +++++++- 10 files changed, 53 insertions(+), 5 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index d6523cc06..80c49efa1 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -6,6 +6,8 @@ import ( "encoding/json" "fmt" + "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" cbor "github.com/ipfs/go-ipld-cbor" @@ -404,6 +406,10 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci verifNeeds := make(map[address.Address]abi.PaddedPieceSize) var sum abi.PaddedPieceSize + nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion { + return runtime.NetworkVersion0 + } + vmopt := vm.VMOpts{ StateBase: stateroot, Epoch: 0, @@ -411,6 +417,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci Bstore: cs.Blockstore(), Syscalls: mkFakedSigSyscalls(cs.VMSys()), CircSupplyCalc: nil, + NtwkVersion: nwv, BaseFee: types.NewInt(0), } vm, err := vm.NewVM(&vmopt) diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 6322ff9a0..98fa3d72b 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -61,6 +61,10 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid return big.Zero(), nil } + nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion { + return runtime.NetworkVersion0 + } + vmopt := &vm.VMOpts{ StateBase: sroot, Epoch: 0, @@ -68,6 +72,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid Bstore: cs.Blockstore(), Syscalls: mkFakedSigSyscalls(cs.VMSys()), CircSupplyCalc: csc, + NtwkVersion: nwv, BaseFee: types.NewInt(0), } diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index cb9ac6d6f..4b83842b4 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -29,6 +29,7 @@ func (sm *StateManager) CallRaw(ctx context.Context, msg *types.Message, bstate Bstore: sm.cs.Blockstore(), Syscalls: sm.cs.VMSys(), CircSupplyCalc: sm.GetCirculatingSupply, + NtwkVersion: sm.GetNtwkVersion, BaseFee: types.NewInt(0), } @@ -130,6 +131,7 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, pri Bstore: sm.cs.Blockstore(), Syscalls: sm.cs.VMSys(), CircSupplyCalc: sm.GetCirculatingSupply, + NtwkVersion: sm.GetNtwkVersion, BaseFee: ts.Blocks()[0].ParentBaseFee, } vmi, err := vm.NewVM(vmopt) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 60af40065..660d4c6a4 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -5,6 +5,8 @@ import ( "fmt" "sync" + "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/builtin/power" "github.com/filecoin-project/specs-actors/actors/builtin/multisig" @@ -154,6 +156,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp Bstore: sm.cs.Blockstore(), Syscalls: sm.cs.VMSys(), CircSupplyCalc: sm.GetCirculatingSupply, + NtwkVersion: sm.GetNtwkVersion, BaseFee: baseFee, } @@ -1120,3 +1123,11 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha return csi.FilCirculating, nil } + +func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) runtime.NetworkVersion { + if build.UpgradeBreezeHeight == 0 || height <= build.UpgradeBreezeHeight { + return runtime.NetworkVersion0 + } + + return runtime.NetworkVersion1 +} diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 0cb491337..ab7f4f472 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -446,6 +446,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, Bstore: sm.cs.Blockstore(), Syscalls: sm.cs.VMSys(), CircSupplyCalc: sm.GetCirculatingSupply, + NtwkVersion: sm.GetNtwkVersion, BaseFee: ts.Blocks()[0].ParentBaseFee, } vmi, err := vm.NewVM(vmopt) diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index b353bcb34..043ea3a45 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -56,6 +56,10 @@ type Runtime struct { lastGasCharge *types.GasTrace } +func (rt *Runtime) NetworkVersion() vmr.NetworkVersion { + return rt.vm.GetNtwkVersion(rt.ctx, rt.CurrEpoch()) +} + func (rt *Runtime) TotalFilCircSupply() abi.TokenAmount { cs, err := rt.vm.GetCircSupply(rt.ctx) if err != nil { diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 92a50c5cd..eb6c2f354 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -7,6 +7,8 @@ import ( "reflect" "time" + "github.com/filecoin-project/specs-actors/actors/runtime" + bstore "github.com/filecoin-project/lotus/lib/blockstore" "github.com/filecoin-project/go-state-types/big" @@ -140,6 +142,7 @@ func (vm *UnsafeVM) MakeRuntime(ctx context.Context, msg *types.Message, origin } type CircSupplyCalculator func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) +type NtwkVersionGetter func(context.Context, abi.ChainEpoch) runtime.NetworkVersion type VM struct { cstate *state.StateTree @@ -150,6 +153,7 @@ type VM struct { inv *Invoker rand Rand circSupplyCalc CircSupplyCalculator + ntwkVersion NtwkVersionGetter baseFee abi.TokenAmount Syscalls SyscallBuilder @@ -162,6 +166,7 @@ type VMOpts struct { Bstore bstore.Blockstore Syscalls SyscallBuilder CircSupplyCalc CircSupplyCalculator + NtwkVersion NtwkVersionGetter BaseFee abi.TokenAmount } @@ -182,6 +187,7 @@ func NewVM(opts *VMOpts) (*VM, error) { inv: NewInvoker(), rand: opts.Rand, // TODO: Probably should be a syscall circSupplyCalc: opts.CircSupplyCalc, + ntwkVersion: opts.NtwkVersion, Syscalls: opts.Syscalls, baseFee: opts.BaseFee, }, nil @@ -716,6 +722,10 @@ func (vm *VM) SetInvoker(i *Invoker) { vm.inv = i } +func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) runtime.NetworkVersion { + return vm.ntwkVersion(ctx, ce) +} + func (vm *VM) GetCircSupply(ctx context.Context) (abi.TokenAmount, error) { return vm.circSupplyCalc(ctx, vm.blockHeight, vm.cstate) } diff --git a/go.mod b/go.mod index 86b76f50d..2f3dc6a54 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-data-transfer v0.6.3 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b + github.com/filecoin-project/go-fil-markets v0.6.0 github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 @@ -39,7 +39,7 @@ require ( github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b - github.com/filecoin-project/specs-actors v0.9.6 + github.com/filecoin-project/specs-actors v0.9.7 github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 github.com/filecoin-project/statediff v0.0.1 github.com/filecoin-project/test-vectors v0.0.0-20200907193218-2c0739eccce6 diff --git a/go.sum b/go.sum index c0a367217..afd23c0c5 100644 --- a/go.sum +++ b/go.sum @@ -251,8 +251,8 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b h1:Xe+ngO0+FV1JESIz9rlyzygwIEnI8M3bDvKqljdIoJA= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907031006-9d489e10498b/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= +github.com/filecoin-project/go-fil-markets v0.6.0 h1:gfxMweUHo4u+2BZh2Q7/7+cV0/ttikuJfhkkxLRsE2Q= +github.com/filecoin-project/go-fil-markets v0.6.0/go.mod h1:LhSFYLkjaoe0vFRKABGYyw1Jz+9jCpF1sPA7yOftLTw= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= @@ -293,6 +293,8 @@ github.com/filecoin-project/specs-actors v0.9.3/go.mod h1:YasnVUOUha0DN5wB+twl+V github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4= github.com/filecoin-project/specs-actors v0.9.6 h1:U3PU4jrHcmXxfEP0CC1fGETx4RrXlm5RYJeuT5eWjhI= github.com/filecoin-project/specs-actors v0.9.6/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= +github.com/filecoin-project/specs-actors v0.9.7 h1:7PAZ8kdqwBdmgf/23FCkQZLCXcVu02XJrkpkhBikiA8= +github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk= diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 379848065..c068bab93 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -1150,7 +1150,13 @@ func (a *StateAPI) StateDealProviderCollateralBounds(ctx context.Context, size a return api.DealCollateralBounds{}, xerrors.Errorf("getting total circulating supply: %w", err) } - min, max := market.DealProviderCollateralBounds(size, verified, powerState.ThisEpochQualityAdjPower, rewardState.ThisEpochBaselinePower, circ.FilCirculating) + min, max := market.DealProviderCollateralBounds(size, + verified, + powerState.TotalRawBytePower, + powerState.ThisEpochQualityAdjPower, + rewardState.ThisEpochBaselinePower, + circ.FilCirculating, + a.StateManager.GetNtwkVersion(ctx, ts.Height())) return api.DealCollateralBounds{ Min: types.BigDiv(types.BigMul(min, dealProviderCollateralNum), dealProviderCollateralDen), Max: max, From 45011c0fadce1243167c2bd9deca451340cc69db Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 7 Sep 2020 17:43:14 -0400 Subject: [PATCH 074/199] Use latest version if no upgrade height is specified --- chain/gen/genesis/genesis.go | 2 +- chain/gen/genesis/miners.go | 2 +- chain/stmgr/stmgr.go | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 80c49efa1..ac22b5b19 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -407,7 +407,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci var sum abi.PaddedPieceSize nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion { - return runtime.NetworkVersion0 + return runtime.NetworkVersion1 } vmopt := vm.VMOpts{ diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 98fa3d72b..d8441c66c 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -62,7 +62,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid } nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion { - return runtime.NetworkVersion0 + return runtime.NetworkVersion1 } vmopt := &vm.VMOpts{ diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 660d4c6a4..5679991ae 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -1125,7 +1125,11 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha } func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) runtime.NetworkVersion { - if build.UpgradeBreezeHeight == 0 || height <= build.UpgradeBreezeHeight { + if build.UpgradeBreezeHeight == 0 { + return runtime.NetworkVersion1 + } + + if height <= build.UpgradeBreezeHeight { return runtime.NetworkVersion0 } From 97af576f6aa5caefe16afd54da757ca2a7a0b53f Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Fri, 4 Sep 2020 20:01:36 -0700 Subject: [PATCH 075/199] Implement faucet funds reallocation logic use all committed sectors instead of power give all miners who had at least a sector on friday a base amount include genesis miner in redistribution drop back to 1,000,000 --- chain/stmgr/forks.go | 302 ++++++++++++++++++++++++++++++++++++- cmd/lotus-shed/balances.go | 242 +++++++++++++++++++++++++++++ cmd/lotus-shed/main.go | 1 + 3 files changed, 544 insertions(+), 1 deletion(-) create mode 100644 cmd/lotus-shed/balances.go diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index 0e6fe5122..bcc93b70e 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -3,11 +3,23 @@ package stmgr import ( "context" + "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/lotus/build" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/power" + "github.com/filecoin-project/specs-actors/actors/util/adt" + cbor "github.com/ipfs/go-ipld-cbor" + "golang.org/x/xerrors" ) -var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree) error{} +var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree) error{ + 42000: UpgradeFaucetBurnRecovery, +} func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree, height abi.ChainEpoch) (err error) { f, ok := ForksAtHeight[height] @@ -20,3 +32,291 @@ func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree return nil } + +type forEachTree interface { + ForEach(func(address.Address, *types.Actor) error) error +} + +func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmount) error { + fromAct, err := tree.GetActor(from) + if err != nil { + return xerrors.Errorf("failed to get 'from' actor for transfer: %w", err) + } + + fromAct.Balance = types.BigSub(fromAct.Balance, amt) + if fromAct.Balance.Sign() < 0 { + return xerrors.Errorf("(sanity) deducted more funds from target account than it had (%s, %s)", from, types.FIL(amt)) + } + + if err := tree.SetActor(from, fromAct); err != nil { + return xerrors.Errorf("failed to persist from actor: %w", err) + } + + toAct, err := tree.GetActor(to) + if err != nil { + return xerrors.Errorf("failed to get 'to' actor for transfer: %w", err) + } + + toAct.Balance = types.BigAdd(toAct.Balance, amt) + + if err := tree.SetActor(to, toAct); err != nil { + return xerrors.Errorf("failed to persist to actor: %w", err) + } + + return nil +} + +func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types.StateTree) error { + // Some initial parameters + FundsForMiners := types.FromFil(1_000_000) + LookbackEpoch := abi.ChainEpoch(32000) + AccountCap := types.FromFil(0) + BaseMinerBalance := types.FromFil(20) + DesiredReimbursementBalance := types.FromFil(5_000_000) + + isSystemAccount := func(addr address.Address) (bool, error) { + id, err := address.IDFromAddress(addr) + if err != nil { + return false, xerrors.Errorf("id address: %w", err) + } + + if id < 1000 { + return true, nil + } + return false, nil + } + + minerFundsAlloc := func(pow, tpow abi.StoragePower) abi.TokenAmount { + return types.BigDiv(types.BigMul(pow, FundsForMiners), tpow) + } + + // Grab lookback state for account checks + lbts, err := sm.ChainStore().GetTipsetByHeight(ctx, LookbackEpoch, nil, false) + if err != nil { + return xerrors.Errorf("failed to get tipset at lookback height: %w", err) + } + + var lbtree *state.StateTree + if err = sm.WithStateTree(lbts.ParentState(), func(state *state.StateTree) error { + lbtree = state + return nil + }); err != nil { + return xerrors.Errorf("loading state tree failed: %w") + } + + ReserveAddress, err := address.NewFromString("t090") + if err != nil { + return xerrors.Errorf("failed to parse reserve address: %w", err) + } + + fetree, ok := tree.(forEachTree) + if !ok { + return xerrors.Errorf("fork transition state tree doesnt support ForEach (%T)", tree) + } + + type transfer struct { + From address.Address + To address.Address + Amt abi.TokenAmount + } + + var transfers []transfer + + // Take all excess funds away, put them into the reserve account + err = fetree.ForEach(func(addr address.Address, act *types.Actor) error { + switch act.Code { + case builtin.AccountActorCodeID, builtin.MultisigActorCodeID, builtin.PaymentChannelActorCodeID: + sysAcc, err := isSystemAccount(addr) + if err != nil { + return xerrors.Errorf("checking system account: %w", err) + } + + if !sysAcc { + transfers = append(transfers, transfer{ + From: addr, + To: ReserveAddress, + Amt: act.Balance, + }) + } + case builtin.StorageMinerActorCodeID: + var st miner.State + if err := sm.WithActorState(ctx, &st)(act); err != nil { + return xerrors.Errorf("failed to load miner state: %w", err) + } + + var available abi.TokenAmount + { + defer func() { + if err := recover(); err != nil { + log.Warnf("Get available balance failed (%s, %s, %s): %s", addr, act.Head, act.Balance, err) + } + available = abi.NewTokenAmount(0) + }() + // this panics if the miner doesnt have enough funds to cover their locked pledge + available = st.GetAvailableBalance(act.Balance) + } + + transfers = append(transfers, transfer{ + From: addr, + To: ReserveAddress, + Amt: available, + }) + } + return nil + }) + if err != nil { + return xerrors.Errorf("foreach over state tree failed: %w", err) + } + + // Execute transfers from previous step + for _, t := range transfers { + if err := doTransfer(tree, t.From, t.To, t.Amt); err != nil { + return xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err) + } + } + + // pull up power table to give miners back some funds proportional to their power + var ps power.State + powAct, err := tree.GetActor(builtin.StoragePowerActorAddr) + if err != nil { + return xerrors.Errorf("failed to load power actor: %w", err) + } + + cst := cbor.NewCborStore(sm.ChainStore().Blockstore()) + if err := cst.Get(ctx, powAct.Head, &ps); err != nil { + return xerrors.Errorf("failed to get power actor state: %w", err) + } + + totalPower := ps.TotalBytesCommitted + + var transfersBack []transfer + // Now, we return some funds to places where they are needed + err = fetree.ForEach(func(addr address.Address, act *types.Actor) error { + lbact, err := lbtree.GetActor(addr) + if err != nil { + if !xerrors.Is(err, types.ErrActorNotFound) { + return xerrors.Errorf("failed to get actor in lookback state") + } + } + + prevBalance := abi.NewTokenAmount(0) + if lbact != nil { + prevBalance = lbact.Balance + } + + switch act.Code { + case builtin.AccountActorCodeID, builtin.MultisigActorCodeID, builtin.PaymentChannelActorCodeID: + nbalance := big.Min(prevBalance, AccountCap) + if nbalance.Sign() != 0 { + transfersBack = append(transfersBack, transfer{ + From: ReserveAddress, + To: addr, + Amt: nbalance, + }) + } + case builtin.StorageMinerActorCodeID: + var st miner.State + if err := sm.WithActorState(ctx, &st)(act); err != nil { + return xerrors.Errorf("failed to load miner state: %w", err) + } + + var minfo miner.MinerInfo + if err := cst.Get(ctx, st.Info, &minfo); err != nil { + return xerrors.Errorf("failed to get miner info: %w", err) + } + + sectorsArr, err := adt.AsArray(sm.ChainStore().Store(ctx), st.Sectors) + if err != nil { + return xerrors.Errorf("failed to load sectors array: %w", err) + } + + slen := sectorsArr.Length() + + power := types.BigMul(types.NewInt(slen), types.NewInt(uint64(minfo.SectorSize))) + + mfunds := minerFundsAlloc(power, totalPower) + transfersBack = append(transfersBack, transfer{ + From: ReserveAddress, + To: minfo.Worker, + Amt: mfunds, + }) + + // Now make sure to give each miner who had power at the lookback some FIL + lbact, err := lbtree.GetActor(addr) + if err == nil { + var lbst miner.State + if err := sm.WithActorState(ctx, &lbst)(lbact); err != nil { + return xerrors.Errorf("failed to load miner state: %w", err) + } + + lbsectors, err := adt.AsArray(sm.ChainStore().Store(ctx), lbst.Sectors) + if err != nil { + return xerrors.Errorf("failed to load lb sectors array: %w", err) + } + + if lbsectors.Length() > 0 { + transfersBack = append(transfersBack, transfer{ + From: ReserveAddress, + To: minfo.Worker, + Amt: BaseMinerBalance, + }) + } + + } else { + log.Warnf("failed to get miner in lookback state: %s", err) + } + } + return nil + }) + if err != nil { + return xerrors.Errorf("foreach over state tree failed: %w", err) + } + + for _, t := range transfersBack { + if err := doTransfer(tree, t.From, t.To, t.Amt); err != nil { + return xerrors.Errorf("transfer %s %s->%s failed: %w", t.Amt, t.From, t.To, err) + } + } + + // transfer all burnt funds back to the reserve account + burntAct, err := tree.GetActor(builtin.BurntFundsActorAddr) + if err != nil { + return xerrors.Errorf("failed to load burnt funds actor: %w", err) + } + if err := doTransfer(tree, builtin.BurntFundsActorAddr, ReserveAddress, burntAct.Balance); err != nil { + return xerrors.Errorf("failed to unburn funds: %w", err) + } + + // Top up the reimbursement service + reimbAddr, err := address.NewFromString("t0111") + if err != nil { + return xerrors.Errorf("failed to parse reimbursement service address") + } + + reimb, err := tree.GetActor(reimbAddr) + if err != nil { + return xerrors.Errorf("failed to load reimbursement account actor: %w", err) + } + + difference := types.BigSub(DesiredReimbursementBalance, reimb.Balance) + if err := doTransfer(tree, ReserveAddress, reimbAddr, difference); err != nil { + return xerrors.Errorf("failed to top up reimbursement account: %w", err) + } + + // Now, a final sanity check to make sure the balances all check out + total := abi.NewTokenAmount(0) + err = fetree.ForEach(func(addr address.Address, act *types.Actor) error { + total = types.BigAdd(total, act.Balance) + return nil + }) + if err != nil { + return xerrors.Errorf("checking final state balance failed: %w", err) + } + + exp := types.FromFil(build.FilBase) + if !exp.Equals(total) { + return xerrors.Errorf("resultant state tree account balance was not correct: %s", total) + } + + return nil +} diff --git a/cmd/lotus-shed/balances.go b/cmd/lotus-shed/balances.go new file mode 100644 index 000000000..ae6640488 --- /dev/null +++ b/cmd/lotus-shed/balances.go @@ -0,0 +1,242 @@ +package main + +import ( + "context" + "fmt" + + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "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/lotus/chain/state" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" + "github.com/filecoin-project/lotus/lib/blockstore" + "github.com/filecoin-project/lotus/node/repo" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/util/adt" +) + +type accountInfo struct { + Address address.Address + Balance types.FIL + Type string + Power abi.StoragePower + Worker address.Address + Owner address.Address + InitialPledge types.FIL + PreCommits types.FIL + LockedFunds types.FIL + Sectors uint64 +} + +var auditsCmd = &cli.Command{ + Name: "audits", + Description: "a collection of utilities for auditing the filecoin chain", + Subcommands: []*cli.Command{ + chainBalanceCmd, + chainBalanceStateCmd, + }, +} + +var chainBalanceCmd = &cli.Command{ + Name: "chain-balances", + Description: "Produces a csv file of all account balances", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "tipset", + Usage: "specify tipset to start from", + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + ts, err := lcli.LoadTipSet(ctx, cctx, api) + if err != nil { + return err + } + + tsk := ts.Key() + actors, err := api.StateListActors(ctx, tsk) + if err != nil { + return err + } + + var infos []accountInfo + for _, addr := range actors { + act, err := api.StateGetActor(ctx, addr, tsk) + if err != nil { + return err + } + + ai := accountInfo{ + Address: addr, + Balance: types.FIL(act.Balance), + Type: string(act.Code.Hash()[2:]), + } + + if act.Code == builtin.StorageMinerActorCodeID { + pow, err := api.StateMinerPower(ctx, addr, tsk) + if err != nil { + return xerrors.Errorf("failed to get power: %w", err) + } + + ai.Power = pow.MinerPower.RawBytePower + info, err := api.StateMinerInfo(ctx, addr, tsk) + if err != nil { + return xerrors.Errorf("failed to get miner info: %w", err) + } + ai.Worker = info.Worker + ai.Owner = info.Owner + + } + infos = append(infos, ai) + } + + fmt.Printf("Address,Balance,Type,Power,Worker,Owner\n") + for _, acc := range infos { + fmt.Printf("%s,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Power, acc.Worker, acc.Owner) + } + return nil + }, +} + +var chainBalanceStateCmd = &cli.Command{ + Name: "stateroot-balances", + Description: "Produces a csv file of all account balances from a given stateroot", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + &cli.BoolFlag{ + Name: "miner-info", + }, + }, + Action: func(cctx *cli.Context) error { + ctx := context.TODO() + + if !cctx.Args().Present() { + return fmt.Errorf("must pass state root") + } + + sroot, err := cid.Decode(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to parse input: %w", err) + } + + fsrepo, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return err + } + + lkrepo, err := fsrepo.Lock(repo.FullNode) + if err != nil { + return err + } + + defer lkrepo.Close() //nolint:errcheck + + ds, err := lkrepo.Datastore("/chain") + if err != nil { + return err + } + + mds, err := lkrepo.Datastore("/metadata") + if err != nil { + return err + } + + bs := blockstore.NewBlockstore(ds) + + cs := store.NewChainStore(bs, mds, vm.Syscalls(ffiwrapper.ProofVerifier)) + + cst := cbor.NewCborStore(bs) + + sm := stmgr.NewStateManager(cs) + + tree, err := state.LoadStateTree(cst, sroot) + if err != nil { + return err + } + + minerInfo := cctx.Bool("miner-info") + + var infos []accountInfo + err = tree.ForEach(func(addr address.Address, act *types.Actor) error { + + ai := accountInfo{ + Address: addr, + Balance: types.FIL(act.Balance), + Type: string(act.Code.Hash()[2:]), + Power: big.NewInt(0), + LockedFunds: types.FIL(big.NewInt(0)), + InitialPledge: types.FIL(big.NewInt(0)), + PreCommits: types.FIL(big.NewInt(0)), + } + + if act.Code == builtin.StorageMinerActorCodeID && minerInfo { + pow, _, err := stmgr.GetPowerRaw(ctx, sm, sroot, addr) + if err != nil { + return xerrors.Errorf("failed to get power: %w", err) + } + + ai.Power = pow.RawBytePower + + var st miner.State + if err := cst.Get(ctx, act.Head, &st); err != nil { + return xerrors.Errorf("failed to read miner state: %w", err) + } + + sectors, err := adt.AsArray(cs.Store(ctx), st.Sectors) + if err != nil { + return xerrors.Errorf("failed to load sector set: %w", err) + } + + ai.InitialPledge = types.FIL(st.InitialPledgeRequirement) + ai.LockedFunds = types.FIL(st.LockedFunds) + ai.PreCommits = types.FIL(st.PreCommitDeposits) + ai.Sectors = sectors.Length() + + var minfo miner.MinerInfo + if err := cst.Get(ctx, st.Info, &minfo); err != nil { + return xerrors.Errorf("failed to read miner info: %w", err) + } + + ai.Worker = minfo.Worker + ai.Owner = minfo.Owner + } + infos = append(infos, ai) + return nil + }) + + if minerInfo { + fmt.Printf("Address,Balance,Type,Sectors,Worker,Owner,InitialPledge,Locked,PreCommits\n") + for _, acc := range infos { + fmt.Printf("%s,%s,%s,%d,%s,%s,%s,%s,%s\n", acc.Address, acc.Balance, acc.Type, acc.Sectors, acc.Worker, acc.Owner, acc.InitialPledge, acc.LockedFunds, acc.PreCommits) + } + } else { + fmt.Printf("Address,Balance,Type\n") + for _, acc := range infos { + fmt.Printf("%s,%s,%s\n", acc.Address, acc.Balance, acc.Type) + } + } + + return nil + }, +} diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index fb931decf..2d0d7c3a0 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -23,6 +23,7 @@ func main() { noncefix, bigIntParseCmd, staterootCmd, + auditsCmd, importCarCmd, commpToCidCmd, fetchParamCmd, From 26ec0716b97112510070a522178d8ecb4759b083 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 7 Sep 2020 16:12:44 -0700 Subject: [PATCH 076/199] fix lint errors --- chain/stmgr/forks.go | 2 +- cmd/lotus-shed/balances.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index bcc93b70e..92dce2761 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -101,7 +101,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types lbtree = state return nil }); err != nil { - return xerrors.Errorf("loading state tree failed: %w") + return xerrors.Errorf("loading state tree failed: %w", err) } ReserveAddress, err := address.NewFromString("t090") diff --git a/cmd/lotus-shed/balances.go b/cmd/lotus-shed/balances.go index ae6640488..aad321783 100644 --- a/cmd/lotus-shed/balances.go +++ b/cmd/lotus-shed/balances.go @@ -224,6 +224,9 @@ var chainBalanceStateCmd = &cli.Command{ infos = append(infos, ai) return nil }) + if err != nil { + return xerrors.Errorf("failed to loop over actors: %w", err) + } if minerInfo { fmt.Printf("Address,Balance,Type,Sectors,Worker,Owner,InitialPledge,Locked,PreCommits\n") From 80a4beace64a2633bbf47bea3a60c958a03f642b Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Mon, 7 Sep 2020 18:40:46 -0400 Subject: [PATCH 077/199] Lotus version v.0.6.0 --- CHANGELOG.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ build/version.go | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccefeda10..1bdcfc318 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,72 @@ # Lotus changelog +# 0.6.0 / 2020-09-07 + +This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are: + +- Tweaking of some cryptoecon parameters in specs-actors 0.9.7 (https://github.com/filecoin-project/specs-actors/releases/tag/v0.9.7) +- Rebalancing FIL distribution to make testnet FIL scarce, which prevents base fee spikes and sets better expectations for mainnet + +This release also introduces many improvements to Lotus! Among them are a new version of go-fil-markets that supports non-blocking retrieval, various spam reduction measures in the messagepool and p2p logic, and UX improvements to payment channels, dealmaking, and state inspection. + +## Changes + +#### Core Lotus and dependencies + +- Implement faucet funds reallocation logic (https://github.com/filecoin-project/lotus/pull/3632) +- Network upgrade: Upgrade to correct fork threshold (https://github.com/filecoin-project/lotus/pull/3628) +- Update to specs 0.9.7 and markets 0.6.0 (https://github.com/filecoin-project/lotus/pull/3627) +- Network upgrade: Perform base fee tamping (https://github.com/filecoin-project/lotus/pull/3623) +- Chain events: if cache best() is nil, return chain head (https://github.com/filecoin-project/lotus/pull/3611) +- Update to specs actors v0.9.6 (https://github.com/filecoin-project/lotus/pull/3603) + +#### Messagepool + +- Temporarily allow negative chains (https://github.com/filecoin-project/lotus/pull/3625) +- Improve publish/republish logic (https://github.com/filecoin-project/lotus/pull/3592) +- Fix selection bug; priority messages were not included if other chains were negative (https://github.com/filecoin-project/lotus/pull/3580) +- Add defensive check for minimum GasFeeCap for inclusion within the next 20 blocks (https://github.com/filecoin-project/lotus/pull/3579) +- Add additional info about gas premium (https://github.com/filecoin-project/lotus/pull/3578) +- Fix GasPremium capping logic (https://github.com/filecoin-project/lotus/pull/3552) + +#### Payment channels + +- Get available funds by address or by from/to (https://github.com/filecoin-project/lotus/pull/3547) +- Create `lotus paych status` command (https://github.com/filecoin-project/lotus/pull/3523) +- Rename CLI command from "paych get" to "paych add-funds" (https://github.com/filecoin-project/lotus/pull/3520) + +#### Peer-to-peer + +- Only subscribe to pubsub topics once we are synced (https://github.com/filecoin-project/lotus/pull/3602) +- Reduce mpool add failure log spam (https://github.com/filecoin-project/lotus/pull/3562) +- Republish messages even if the chains have negative performance(https://github.com/filecoin-project/lotus/pull/3557) +- Adjust gossipsub gossip factor (https://github.com/filecoin-project/lotus/pull/3556) +- Integrate pubsub Random Early Drop (https://github.com/filecoin-project/lotus/pull/3518) + +#### Miscellaneous + +- Fix panic in OnDealExpiredSlashed (https://github.com/filecoin-project/lotus/pull/3553) +- Robustify state manager against holes in actor method numbers (https://github.com/filecoin-project/lotus/pull/3538) + +#### UX + +- VM: Fix an error message (https://github.com/filecoin-project/lotus/pull/3608) +- Documentation: Batch replacement,update lotus-storage-miner to lotus-miner (https://github.com/filecoin-project/lotus/pull/3571) +- CLI: Robust actor lookup (https://github.com/filecoin-project/lotus/pull/3535) +- Add agent flag to net peers (https://github.com/filecoin-project/lotus/pull/3534) +- Add watch option to storage-deals list (https://github.com/filecoin-project/lotus/pull/3527) + +#### Testing & tooling + +- Decommission chain-validation (https://github.com/filecoin-project/lotus/pull/3606) +- Metrics: add expected height metric (https://github.com/filecoin-project/lotus/pull/3586) +- PCR: Use current tipset during refund (https://github.com/filecoin-project/lotus/pull/3570) +- Lotus-shed: Add math command (https://github.com/filecoin-project/lotus/pull/3568) +- PCR: Add tipset aggergation (https://github.com/filecoin-project/lotus/pull/3565)- Fix broken paych tests (https://github.com/filecoin-project/lotus/pull/3551) +- Make chain export ~1000x times faster (https://github.com/filecoin-project/lotus/pull/3533) +- Chainwatch: Stop SyncIncomingBlocks from leaking into chainwatch processing; No panics during processing (https://github.com/filecoin-project/lotus/pull/3526) +- Conformance: various changes (https://github.com/filecoin-project/lotus/pull/3521) + # 0.5.10 / 2020-09-03 This patch includes a crucial fix to the message pool selection logic, strongly disfavouring messages that might cause a miner penalty. diff --git a/build/version.go b/build/version.go index a3c5d1552..65ae0987d 100644 --- a/build/version.go +++ b/build/version.go @@ -25,7 +25,7 @@ func buildType() string { } // BuildVersion is the local build version, set by build system -const BuildVersion = "0.5.10" +const BuildVersion = "0.6.0" func UserVersion() string { return BuildVersion + buildType() + CurrentCommit From d1cf4453270b241227d293fc4a0d00fc6cd1db1c Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 7 Sep 2020 16:18:22 -0700 Subject: [PATCH 078/199] use defined constant for fork height --- chain/stmgr/forks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index 92dce2761..769cae7c0 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -18,7 +18,7 @@ import ( ) var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree) error{ - 42000: UpgradeFaucetBurnRecovery, + build.UpgradeBreezeHeight: UpgradeFaucetBurnRecovery, } func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree, height abi.ChainEpoch) (err error) { From c77f5f62528228c5e0ec9998a41b3bd006a7a55f Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 8 Sep 2020 00:32:26 -0400 Subject: [PATCH 079/199] Revert "only subscribe to pubsub topics once we are synced" --- chain/store/store.go | 31 ++------------ chain/sync_test.go | 3 -- node/modules/services.go | 91 +++++++--------------------------------- node/test/builder.go | 3 -- 4 files changed, 17 insertions(+), 111 deletions(-) diff --git a/chain/store/store.go b/chain/store/store.go index 398828b1a..e0a997686 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -5,7 +5,6 @@ import ( "context" "encoding/binary" "encoding/json" - "errors" "io" "os" "strconv" @@ -52,8 +51,6 @@ var blockValidationCacheKeyPrefix = dstore.NewKey("blockValidation") var DefaultTipSetCacheSize = 8192 var DefaultMsgMetaCacheSize = 2048 -var ErrNotifieeDone = errors.New("notifee is done and should be removed") - func init() { if s := os.Getenv("LOTUS_CHAIN_TIPSET_CACHE"); s != "" { tscs, err := strconv.Atoi(s) @@ -361,33 +358,11 @@ func (cs *ChainStore) reorgWorker(ctx context.Context, initialNotifees []ReorgNo apply[i], apply[opp] = apply[opp], apply[i] } - var toremove map[int]struct{} - for i, hcf := range notifees { - err := hcf(revert, apply) - if err != nil { - if err == ErrNotifieeDone { - if toremove == nil { - toremove = make(map[int]struct{}) - } - toremove[i] = struct{}{} - } else { - log.Error("head change func errored (BAD): ", err) - } + for _, hcf := range notifees { + if err := hcf(revert, apply); err != nil { + log.Error("head change func errored (BAD): ", err) } } - - if len(toremove) > 0 { - newNotifees := make([]ReorgNotifee, 0, len(notifees)-len(toremove)) - for i, hcf := range notifees { - _, remove := toremove[i] - if remove { - continue - } - newNotifees = append(newNotifees, hcf) - } - notifees = newNotifees - } - case <-ctx.Done(): return } diff --git a/chain/sync_test.go b/chain/sync_test.go index 16e0d2ffb..f91929a02 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -34,7 +34,6 @@ import ( "github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/node/impl" "github.com/filecoin-project/lotus/node/modules" - "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/repo" ) @@ -234,7 +233,6 @@ func (tu *syncTestUtil) addSourceNode(gen int) { node.Repo(sourceRepo), node.MockHost(tu.mn), node.Test(), - node.Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(true)), node.Override(new(modules.Genesis), modules.LoadGenesis(genesis)), ) @@ -267,7 +265,6 @@ func (tu *syncTestUtil) addClientNode() int { node.Repo(repo.NewMemory(nil)), node.MockHost(tu.mn), node.Test(), - node.Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(true)), node.Override(new(modules.Genesis), modules.LoadGenesis(tu.genesis)), ) diff --git a/node/modules/services.go b/node/modules/services.go index 22d99fa54..fc7486abe 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -1,8 +1,6 @@ package modules import ( - "time" - "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" eventbus "github.com/libp2p/go-eventbus" @@ -24,7 +22,6 @@ import ( "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/sub" - "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/peermgr" "github.com/filecoin-project/lotus/node/hello" "github.com/filecoin-project/lotus/node/modules/dtypes" @@ -76,45 +73,14 @@ func RunBlockSync(h host.Host, svc *blocksync.BlockSyncService) { h.SetStreamHandler(blocksync.BlockSyncProtocolID, svc.HandleStream) } -func waitForSync(stmgr *stmgr.StateManager, epochs int, subscribe func()) { - nearsync := uint64(epochs) * uint64(build.BlockDelaySecs) * uint64(time.Second) //nolint - - // early check, are we synced at start up? - ts := stmgr.ChainStore().GetHeaviestTipSet() - timestamp := ts.MinTimestamp() - now := uint64(build.Clock.Now().UnixNano()) - if timestamp > now-nearsync { - subscribe() - return - } - - // we are not synced, subscribe to head changes and wait for sync - stmgr.ChainStore().SubscribeHeadChanges(func(rev, app []*types.TipSet) error { - if len(app) == 0 { - return nil - } - - latest := app[0].MinTimestamp() - for _, ts := range app[1:] { - timestamp := ts.MinTimestamp() - if timestamp > latest { - latest = timestamp - } - } - - now := uint64(build.Clock.Now().UnixNano()) - if latest > now-nearsync { - subscribe() - return store.ErrNotifieeDone - } - - return nil - }) -} - -func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName, bootstrapper dtypes.Bootstrapper) { +func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, s *chain.Syncer, bserv dtypes.ChainBlockService, chain *store.ChainStore, stmgr *stmgr.StateManager, h host.Host, nn dtypes.NetworkName) { ctx := helpers.LifecycleCtx(mctx, lc) + blocksub, err := ps.Subscribe(build.BlocksTopic(nn)) //nolint + if err != nil { + panic(err) + } + v := sub.NewBlockValidator( h.ID(), chain, stmgr, func(p peer.ID) { @@ -126,53 +92,24 @@ func HandleIncomingBlocks(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.P panic(err) } - subscribe := func() { - log.Infof("subscribing to pubsub topic %s", build.BlocksTopic(nn)) - - blocksub, err := ps.Subscribe(build.BlocksTopic(nn)) //nolint - if err != nil { - panic(err) - } - - go sub.HandleIncomingBlocks(ctx, blocksub, s, bserv, h.ConnManager()) - } - - if bootstrapper { - subscribe() - return - } - - // wait until we are synced within 10 blocks - waitForSync(stmgr, 10, subscribe) + go sub.HandleIncomingBlocks(ctx, blocksub, s, bserv, h.ConnManager()) } -func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, stmgr *stmgr.StateManager, mpool *messagepool.MessagePool, h host.Host, nn dtypes.NetworkName, bootstrapper dtypes.Bootstrapper) { +func HandleIncomingMessages(mctx helpers.MetricsCtx, lc fx.Lifecycle, ps *pubsub.PubSub, mpool *messagepool.MessagePool, h host.Host, nn dtypes.NetworkName) { ctx := helpers.LifecycleCtx(mctx, lc) + msgsub, err := ps.Subscribe(build.MessagesTopic(nn)) //nolint:staticcheck + if err != nil { + panic(err) + } + v := sub.NewMessageValidator(h.ID(), mpool) if err := ps.RegisterTopicValidator(build.MessagesTopic(nn), v.Validate); err != nil { panic(err) } - subscribe := func() { - log.Infof("subscribing to pubsub topic %s", build.MessagesTopic(nn)) - - msgsub, err := ps.Subscribe(build.MessagesTopic(nn)) //nolint - if err != nil { - panic(err) - } - - go sub.HandleIncomingMessages(ctx, mpool, msgsub) - } - - if bootstrapper { - subscribe() - return - } - - // wait until we are synced within 1 block - waitForSync(stmgr, 1, subscribe) + go sub.HandleIncomingMessages(ctx, mpool, msgsub) } func NewLocalDiscovery(ds dtypes.MetadataDS) *discovery.Local { diff --git a/node/test/builder.go b/node/test/builder.go index 20a54efa4..de2071e7a 100644 --- a/node/test/builder.go +++ b/node/test/builder.go @@ -33,7 +33,6 @@ import ( miner2 "github.com/filecoin-project/lotus/miner" "github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/node/modules" - "github.com/filecoin-project/lotus/node/modules/dtypes" testing2 "github.com/filecoin-project/lotus/node/modules/testing" "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/storage/mockstorage" @@ -371,8 +370,6 @@ func MockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), - node.Override(new(dtypes.Bootstrapper), dtypes.Bootstrapper(true)), - genesis, ) if err != nil { From f91f665f3f989e90874f2ff3145a8872bca93da8 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 8 Sep 2020 01:14:17 -0400 Subject: [PATCH 080/199] Update test-vectors --- extern/test-vectors | 2 +- go.mod | 3 --- go.sum | 5 +++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/extern/test-vectors b/extern/test-vectors index ef5dba45b..2c0739ecc 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit ef5dba45b810d7090e029167cc66911ef8c42a07 +Subproject commit 2c0739eccce6ea5703dcea2df564efcb6cf79fee diff --git a/go.mod b/go.mod index 2f3dc6a54..9904e9e5f 100644 --- a/go.mod +++ b/go.mod @@ -7,14 +7,12 @@ replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-al require ( contrib.go.opencensus.io/exporter/jaeger v0.1.0 contrib.go.opencensus.io/exporter/prometheus v0.1.0 - github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect github.com/BurntSushi/toml v0.3.1 github.com/GeertJohan/go.rice v1.0.0 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/coreos/go-systemd/v22 v22.0.0 - github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.0.3 github.com/docker/go-units v0.4.0 @@ -120,7 +118,6 @@ require ( github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 go.opencensus.io v0.22.4 - go.uber.org/dig v1.10.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/multierr v1.5.0 go.uber.org/zap v1.15.0 diff --git a/go.sum b/go.sum index afd23c0c5..d163f4db8 100644 --- a/go.sum +++ b/go.sum @@ -223,6 +223,7 @@ github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGj github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef h1:MtQRSnJLsQOOlmsd/Ua5KWXimpxcaa715h6FUh/eJPY= github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef/go.mod h1:SMj5VK1pYgqC8FXVEtOBRTc+9AIrYu+C+K3tAXi2Rk8= +github.com/filecoin-project/chain-validation v0.0.6-0.20200907020853-f4e4e7417fea/go.mod h1:pKcH/ShsOvCpO2qnsGFzEJ0NMJdBenPRk4Uu/xpIEkY= 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.3 h1:eVfbdjEbpbzIrbiSa+PiGUY+oDK9HnUn+M1R/ggoHf8= @@ -250,7 +251,7 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= -github.com/filecoin-project/go-fil-markets v0.5.8/go.mod h1:6ZX1vbZbnukbVQ8tCB/MmEizuW/bmRX7SpGAltU3KVg= +github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= github.com/filecoin-project/go-fil-markets v0.6.0 h1:gfxMweUHo4u+2BZh2Q7/7+cV0/ttikuJfhkkxLRsE2Q= github.com/filecoin-project/go-fil-markets v0.6.0/go.mod h1:LhSFYLkjaoe0vFRKABGYyw1Jz+9jCpF1sPA7yOftLTw= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= @@ -278,7 +279,7 @@ github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZO github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= github.com/filecoin-project/lotus v0.4.3-0.20200820203717-d1718369a182/go.mod h1:biFZPQ/YyQGfkHUmHMiaNf2hnD6zm1+OAXPQYQ61Zkg= -github.com/filecoin-project/lotus v0.5.8-0.20200903221953-ada5e6ae68cf/go.mod h1:wxuzS4ozpCFThia18G+J5P0Jp/DSiq9ezzJF1yvZuP4= +github.com/filecoin-project/lotus v0.5.11-0.20200907070510-420a8706da6d/go.mod h1:SVrkI6GQzqSeSuaZ6KsHih4Dh800q9HSFQCtBnyMYBI= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= From 043e62ab6338a3672e50773c1072c951719f1aab Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 8 Sep 2020 08:59:05 +0200 Subject: [PATCH 081/199] Don't use latency as initital estimate for blocksync Signed-off-by: Jakub Sztandera --- chain/blocksync/peer_tracker.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/chain/blocksync/peer_tracker.go b/chain/blocksync/peer_tracker.go index f1f6ede07..b6ff932c2 100644 --- a/chain/blocksync/peer_tracker.go +++ b/chain/blocksync/peer_tracker.go @@ -72,16 +72,7 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID { var costI, costJ float64 getPeerInitLat := func(p peer.ID) float64 { - var res float64 - if bpt.pmgr != nil { - if lat, ok := bpt.pmgr.GetPeerLatency(p); ok { - res = float64(lat) - } - } - if res == 0 { - res = float64(bpt.avgGlobalTime) - } - return res * newPeerMul + return float64(bpt.avgGlobalTime) * newPeerMul } if pi.successes+pi.failures > 0 { From 93176c91f4c20c8f11fdfeae5ee0c0807f60c13e Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 8 Sep 2020 09:06:31 +0200 Subject: [PATCH 082/199] Track time in relation to request size Signed-off-by: Jakub Sztandera --- chain/blocksync/client.go | 6 +++--- chain/blocksync/peer_tracker.go | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/chain/blocksync/client.go b/chain/blocksync/client.go index 38e1f6d2c..5c7fe4251 100644 --- a/chain/blocksync/client.go +++ b/chain/blocksync/client.go @@ -385,7 +385,7 @@ func (client *BlockSync) sendRequestToPeer( _ = stream.SetWriteDeadline(time.Now().Add(WRITE_REQ_DEADLINE)) if err := cborutil.WriteCborRPC(stream, req); err != nil { _ = stream.SetWriteDeadline(time.Time{}) - client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart)) + client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart), req.Length) // FIXME: Should we also remove peer here? return nil, err } @@ -398,7 +398,7 @@ func (client *BlockSync) sendRequestToPeer( bufio.NewReader(incrt.New(stream, READ_RES_MIN_SPEED, READ_RES_DEADLINE)), &res) if err != nil { - client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart)) + client.peerTracker.logFailure(peer, build.Clock.Since(connectionStart), req.Length) return nil, xerrors.Errorf("failed to read blocksync response: %w", err) } @@ -412,7 +412,7 @@ func (client *BlockSync) sendRequestToPeer( ) } - client.peerTracker.logSuccess(peer, build.Clock.Since(connectionStart)) + client.peerTracker.logSuccess(peer, build.Clock.Since(connectionStart), uint64(len(res.Chain))) // FIXME: We should really log a success only after we validate the response. // It might be a bit hard to do. return &res, nil diff --git a/chain/blocksync/peer_tracker.go b/chain/blocksync/peer_tracker.go index b6ff932c2..5ef8f9c6f 100644 --- a/chain/blocksync/peer_tracker.go +++ b/chain/blocksync/peer_tracker.go @@ -98,8 +98,8 @@ func (bpt *bsPeerTracker) prefSortedPeers() []peer.ID { const ( // xInvAlpha = (N+1)/2 - localInvAlpha = 5 // 86% of the value is the last 9 - globalInvAlpha = 20 // 86% of the value is the last 39 + localInvAlpha = 10 // 86% of the value is the last 19 + globalInvAlpha = 25 // 86% of the value is the last 49 ) func (bpt *bsPeerTracker) logGlobalSuccess(dur time.Duration) { @@ -124,7 +124,7 @@ func logTime(pi *peerStats, dur time.Duration) { } -func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) { +func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration, reqSize uint64) { bpt.lk.Lock() defer bpt.lk.Unlock() @@ -136,10 +136,10 @@ func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration) { } pi.successes++ - logTime(pi, dur) + logTime(pi, dur/time.Duration(reqSize)) } -func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) { +func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration, reqSize uint64) { bpt.lk.Lock() defer bpt.lk.Unlock() @@ -151,7 +151,7 @@ func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration) { } pi.failures++ - logTime(pi, dur) + logTime(pi, dur/time.Duration(reqSize)) } func (bpt *bsPeerTracker) removePeer(p peer.ID) { From e9e067eebf95422c5c5da7c0b022330a42ec9e0e Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Tue, 8 Sep 2020 03:09:41 -0400 Subject: [PATCH 083/199] Lotus version 0.6.1 --- CHANGELOG.md | 9 +++++++++ build/version.go | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bdcfc318..15bfe8334 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Lotus changelog +# 0.6.1 / 2020-09-08 + +This optional release introduces a minor improvement to the sync process, ensuring nodes don't fall behind and then resync. + +## Changes + +- Update `test-vectors` (https://github.com/filecoin-project/lotus/pull/3645) +- Revert "only subscribe to pubsub topics once we are synced" (https://github.com/filecoin-project/lotus/pull/3643) + # 0.6.0 / 2020-09-07 This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are: diff --git a/build/version.go b/build/version.go index 65ae0987d..adaade907 100644 --- a/build/version.go +++ b/build/version.go @@ -25,7 +25,7 @@ func buildType() string { } // BuildVersion is the local build version, set by build system -const BuildVersion = "0.6.0" +const BuildVersion = "0.6.1" func UserVersion() string { return BuildVersion + buildType() + CurrentCommit From 27fa9969f3474e9fd0cee228398bb472006aff41 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 8 Sep 2020 10:21:40 +0300 Subject: [PATCH 084/199] fix isChainNearSync check in block validator --- chain/sub/incoming.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index 5c28aa835..2684f1d5e 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "sync" - "time" "golang.org/x/xerrors" @@ -369,8 +368,8 @@ func (bv *BlockValidator) decodeAndCheckBlock(msg *pubsub.Message) (*types.Block func (bv *BlockValidator) isChainNearSynced() bool { ts := bv.chain.GetHeaviestTipSet() timestamp := ts.MinTimestamp() - now := build.Clock.Now().UnixNano() - cutoff := uint64(now) - uint64(6*time.Hour) + now := build.Clock.Now().Unix() + cutoff := uint64(now) - uint64(6*3600) // 6 hours return timestamp > cutoff } From 37ec1a978e10cc1c0702382c1d1fb2f7c54a5cfe Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 8 Sep 2020 10:39:16 +0300 Subject: [PATCH 085/199] nicer check using Time objects --- chain/sub/incoming.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index 2684f1d5e..34dde227f 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "sync" + "time" "golang.org/x/xerrors" @@ -368,9 +369,8 @@ func (bv *BlockValidator) decodeAndCheckBlock(msg *pubsub.Message) (*types.Block func (bv *BlockValidator) isChainNearSynced() bool { ts := bv.chain.GetHeaviestTipSet() timestamp := ts.MinTimestamp() - now := build.Clock.Now().Unix() - cutoff := uint64(now) - uint64(6*3600) // 6 hours - return timestamp > cutoff + timestampTime := time.Unix(int64(timestamp), 0) + return build.Clock.Since(timestampTime) < 6*time.Hour } func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error { From 74e577610aa344484a476fd3ba31d5828e3b7ecb Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 8 Sep 2020 10:18:51 +0200 Subject: [PATCH 086/199] Forward peers from hello to blocksync Signed-off-by: Jakub Sztandera --- chain/blocksync/client.go | 5 ++++- chain/blocksync/peer_tracker.go | 29 +++++++++++++++++++++++++++-- lib/peermgr/peermgr.go | 25 +++++++++++++++++++++---- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/chain/blocksync/client.go b/chain/blocksync/client.go index 5c7fe4251..893759f6a 100644 --- a/chain/blocksync/client.go +++ b/chain/blocksync/client.go @@ -11,6 +11,7 @@ import ( inet "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" "go.opencensus.io/trace" + "go.uber.org/fx" "golang.org/x/xerrors" cborutil "github.com/filecoin-project/go-cbor-util" @@ -36,12 +37,13 @@ type BlockSync struct { } func NewClient( + lc fx.Lifecycle, host host.Host, pmgr peermgr.MaybePeerMgr, ) *BlockSync { return &BlockSync{ host: host, - peerTracker: newPeerTracker(pmgr.Mgr), + peerTracker: newPeerTracker(lc, host, pmgr.Mgr), } } @@ -360,6 +362,7 @@ func (client *BlockSync) sendRequestToPeer( supported, err := client.host.Peerstore().SupportsProtocols(peer, BlockSyncProtocolID) if err != nil { + client.RemovePeer(peer) return nil, xerrors.Errorf("failed to get protocols for peer: %w", err) } if len(supported) == 0 || supported[0] != BlockSyncProtocolID { diff --git a/chain/blocksync/peer_tracker.go b/chain/blocksync/peer_tracker.go index 5ef8f9c6f..3a9d9089b 100644 --- a/chain/blocksync/peer_tracker.go +++ b/chain/blocksync/peer_tracker.go @@ -3,11 +3,14 @@ package blocksync // FIXME: This needs to be reviewed. import ( + "context" "sort" "sync" "time" + host "github.com/libp2p/go-libp2p-core/host" "github.com/libp2p/go-libp2p-core/peer" + "go.uber.org/fx" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/lib/peermgr" @@ -29,11 +32,33 @@ type bsPeerTracker struct { pmgr *peermgr.PeerMgr } -func newPeerTracker(pmgr *peermgr.PeerMgr) *bsPeerTracker { - return &bsPeerTracker{ +func newPeerTracker(lc fx.Lifecycle, h host.Host, pmgr *peermgr.PeerMgr) *bsPeerTracker { + bsPt := &bsPeerTracker{ peers: make(map[peer.ID]*peerStats), pmgr: pmgr, } + + sub, err := h.EventBus().Subscribe(new(peermgr.NewFilPeer)) + if err != nil { + panic(err) + } + go func() { + var newPeer interface{} + ok := true + for ok { + newPeer, ok = <-sub.Out() + log.Warnf("new peer from hello in tracker: %s", newPeer.(peermgr.NewFilPeer).Id) + bsPt.addPeer(newPeer.(peermgr.NewFilPeer).Id) + } + }() + + lc.Append(fx.Hook{ + OnStop: func(ctx context.Context) error { + return sub.Close() + }, + }) + + return bsPt } func (bpt *bsPeerTracker) addPeer(p peer.ID) { diff --git a/lib/peermgr/peermgr.go b/lib/peermgr/peermgr.go index 80b05e8ce..a80e516c0 100644 --- a/lib/peermgr/peermgr.go +++ b/lib/peermgr/peermgr.go @@ -10,7 +10,10 @@ import ( "github.com/filecoin-project/lotus/node/modules/dtypes" "go.opencensus.io/stats" "go.uber.org/fx" + "go.uber.org/multierr" + "golang.org/x/xerrors" + "github.com/libp2p/go-libp2p-core/event" host "github.com/libp2p/go-libp2p-core/host" net "github.com/libp2p/go-libp2p-core/network" peer "github.com/libp2p/go-libp2p-core/peer" @@ -50,12 +53,17 @@ type PeerMgr struct { h host.Host dht *dht.IpfsDHT - notifee *net.NotifyBundle + notifee *net.NotifyBundle + filPeerEmitter event.Emitter done chan struct{} } -func NewPeerMgr(lc fx.Lifecycle, h host.Host, dht *dht.IpfsDHT, bootstrap dtypes.BootstrapPeers) *PeerMgr { +type NewFilPeer struct { + Id peer.ID +} + +func NewPeerMgr(lc fx.Lifecycle, h host.Host, dht *dht.IpfsDHT, bootstrap dtypes.BootstrapPeers) (*PeerMgr, error) { pm := &PeerMgr{ h: h, dht: dht, @@ -69,10 +77,18 @@ func NewPeerMgr(lc fx.Lifecycle, h host.Host, dht *dht.IpfsDHT, bootstrap dtypes done: make(chan struct{}), } + emitter, err := h.EventBus().Emitter(new(NewFilPeer)) + if err != nil { + return nil, xerrors.Errorf("creating NewFilPeer emitter: %w", err) + } + pm.filPeerEmitter = emitter lc.Append(fx.Hook{ OnStop: func(ctx context.Context) error { - return pm.Stop(ctx) + return multierr.Combine( + pm.filPeerEmitter.Close(), + pm.Stop(ctx), + ) }, }) @@ -84,10 +100,11 @@ func NewPeerMgr(lc fx.Lifecycle, h host.Host, dht *dht.IpfsDHT, bootstrap dtypes h.Network().Notify(pm.notifee) - return pm + return pm, nil } func (pmgr *PeerMgr) AddFilecoinPeer(p peer.ID) { + pmgr.filPeerEmitter.Emit(NewFilPeer{Id: p}) pmgr.peersLk.Lock() defer pmgr.peersLk.Unlock() pmgr.peers[p] = time.Duration(0) From ba9678bd610ade808547497e3efff6ce7487370c Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 8 Sep 2020 12:11:30 +0200 Subject: [PATCH 087/199] Use for to iterate over channel Signed-off-by: Jakub Sztandera --- chain/blocksync/peer_tracker.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/chain/blocksync/peer_tracker.go b/chain/blocksync/peer_tracker.go index 3a9d9089b..7c30b92a2 100644 --- a/chain/blocksync/peer_tracker.go +++ b/chain/blocksync/peer_tracker.go @@ -42,12 +42,9 @@ func newPeerTracker(lc fx.Lifecycle, h host.Host, pmgr *peermgr.PeerMgr) *bsPeer if err != nil { panic(err) } + go func() { - var newPeer interface{} - ok := true - for ok { - newPeer, ok = <-sub.Out() - log.Warnf("new peer from hello in tracker: %s", newPeer.(peermgr.NewFilPeer).Id) + for newPeer := range sub.Out() { bsPt.addPeer(newPeer.(peermgr.NewFilPeer).Id) } }() From 4fce0181ab303043d7c660f33b2263b48adb922e Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 8 Sep 2020 12:18:48 +0200 Subject: [PATCH 088/199] Ignore the linter Signed-off-by: Jakub Sztandera --- lib/peermgr/peermgr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/peermgr/peermgr.go b/lib/peermgr/peermgr.go index a80e516c0..2f9d34674 100644 --- a/lib/peermgr/peermgr.go +++ b/lib/peermgr/peermgr.go @@ -104,7 +104,7 @@ func NewPeerMgr(lc fx.Lifecycle, h host.Host, dht *dht.IpfsDHT, bootstrap dtypes } func (pmgr *PeerMgr) AddFilecoinPeer(p peer.ID) { - pmgr.filPeerEmitter.Emit(NewFilPeer{Id: p}) + _ = pmgr.filPeerEmitter.Emit(NewFilPeer{Id: p}) //nolint:errcheck pmgr.peersLk.Lock() defer pmgr.peersLk.Unlock() pmgr.peers[p] = time.Duration(0) From b66058e417b4ff391b9fd6def9f4daa0517e216f Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 8 Sep 2020 12:19:37 +0200 Subject: [PATCH 089/199] Add 0 guard Signed-off-by: Jakub Sztandera --- chain/blocksync/peer_tracker.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/chain/blocksync/peer_tracker.go b/chain/blocksync/peer_tracker.go index 7c30b92a2..bb350aa51 100644 --- a/chain/blocksync/peer_tracker.go +++ b/chain/blocksync/peer_tracker.go @@ -158,6 +158,9 @@ func (bpt *bsPeerTracker) logSuccess(p peer.ID, dur time.Duration, reqSize uint6 } pi.successes++ + if reqSize == 0 { + reqSize = 1 + } logTime(pi, dur/time.Duration(reqSize)) } @@ -173,6 +176,9 @@ func (bpt *bsPeerTracker) logFailure(p peer.ID, dur time.Duration, reqSize uint6 } pi.failures++ + if reqSize == 0 { + reqSize = 1 + } logTime(pi, dur/time.Duration(reqSize)) } From 8bbdf2e7cbfdedd67a046af81069602372e7821c Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 8 Sep 2020 12:33:36 +0200 Subject: [PATCH 090/199] fix: storage manager - bail out on undefined unsealed cid --- extern/sector-storage/manager.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/extern/sector-storage/manager.go b/extern/sector-storage/manager.go index 07e752db1..d94647fec 100644 --- a/extern/sector-storage/manager.go +++ b/extern/sector-storage/manager.go @@ -217,16 +217,11 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return xerrors.Errorf("read piece: checking for already existing unsealed sector: %w", err) } + var readOk bool var selector WorkerSelector if len(best) == 0 { // new selector = newAllocSelector(m.index, stores.FTUnsealed, stores.PathSealing) } else { // append to existing - selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false) - } - - var readOk bool - - if len(best) > 0 { // There is unsealed sector, see if we can read from it selector = newExistingSelector(m.index, sector, stores.FTUnsealed, false) @@ -257,6 +252,9 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return nil } + if unsealed == cid.Undef { + return xerrors.Errorf("cannot unseal piece (sector: %d, offset: %d size: %d) - unsealed cid is undefined", sector, offset, size) + } err = m.sched.Schedule(ctx, sector, sealtasks.TTUnseal, selector, unsealFetch, func(ctx context.Context, w Worker) error { return w.UnsealPiece(ctx, sector, offset, size, ticket, unsealed) }) From 17c15a74a2597c191781579da303c1ece42b27ba Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Tue, 8 Sep 2020 13:50:56 +0200 Subject: [PATCH 091/199] fix: return true from Sealer.ReadPiece() on success --- extern/sector-storage/ffiwrapper/sealer_cgo.go | 2 +- extern/sector-storage/manager.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extern/sector-storage/ffiwrapper/sealer_cgo.go b/extern/sector-storage/ffiwrapper/sealer_cgo.go index 9ab9bd5a6..9bc2680ed 100644 --- a/extern/sector-storage/ffiwrapper/sealer_cgo.go +++ b/extern/sector-storage/ffiwrapper/sealer_cgo.go @@ -410,7 +410,7 @@ func (sb *Sealer) ReadPiece(ctx context.Context, writer io.Writer, sector abi.Se return false, xerrors.Errorf("closing partial file: %w", err) } - return false, nil + return true, nil } func (sb *Sealer) SealPreCommit1(ctx context.Context, sector abi.SectorID, ticket abi.SealRandomness, pieces []abi.PieceInfo) (out storage.PreCommit1Out, err error) { diff --git a/extern/sector-storage/manager.go b/extern/sector-storage/manager.go index d94647fec..fe9bf5d45 100644 --- a/extern/sector-storage/manager.go +++ b/extern/sector-storage/manager.go @@ -272,7 +272,7 @@ func (m *Manager) ReadPiece(ctx context.Context, sink io.Writer, sector abi.Sect return xerrors.Errorf("reading piece from sealed sector: %w", err) } - if readOk { + if !readOk { return xerrors.Errorf("failed to read unsealed piece") } From 26ff59698321da24ad06cdc68210c429c687e318 Mon Sep 17 00:00:00 2001 From: vyzo Date: Tue, 8 Sep 2020 19:02:05 +0300 Subject: [PATCH 092/199] fix very minor bug in repub baseFeeLowerBound messages will not be accepted if the GasFeeCap is less than minimumBaseFee, but it doesn't hurt to be correct. --- chain/messagepool/repub.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index d1b1116c5..fd0324d0a 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -27,7 +27,11 @@ func (mp *MessagePool) republishPendingMessages() error { mp.curTsLk.Unlock() return xerrors.Errorf("computing basefee: %w", err) } + baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) + if baseFeeLowerBoundFactor.LessThan(minimumBaseFee) { + baseFeeLowerBound = minimumBaseFee + } pending := make(map[address.Address]map[uint64]*types.SignedMessage) mp.lk.Lock() From 1d67e38f784aea57de9ecb2240520b747849c42e Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Tue, 8 Sep 2020 18:35:10 +0200 Subject: [PATCH 093/199] add niceSleep 1 second when drand errors --- miner/miner.go | 1 + 1 file changed, 1 insertion(+) diff --git a/miner/miner.go b/miner/miner.go index 6d3595d58..9c11dcc46 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -189,6 +189,7 @@ func (m *Miner) mine(ctx context.Context) { _, err = m.api.BeaconGetEntry(ctx, prebase.TipSet.Height()+prebase.NullRounds+1) if err != nil { log.Errorf("failed getting beacon entry: %s", err) + m.niceSleep(time.Second) continue } From 46d3769a4474ef2c4c3c0f4ce55db72695b1d176 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 8 Sep 2020 20:13:16 +0200 Subject: [PATCH 094/199] Add peer to peer manager before fetching the tipset Signed-off-by: Jakub Sztandera --- node/hello/hello.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/node/hello/hello.go b/node/hello/hello.go index 1b03c5cdd..05d53de06 100644 --- a/node/hello/hello.go +++ b/node/hello/hello.go @@ -104,6 +104,10 @@ func (hs *Service) HandleStream(s inet.Stream) { build.Clock.Sleep(time.Millisecond * 300) } + if hs.pmgr != nil { + hs.pmgr.AddFilecoinPeer(s.Conn().RemotePeer()) + } + ts, err := hs.syncer.FetchTipSet(context.Background(), s.Conn().RemotePeer(), types.NewTipSetKey(hmsg.HeaviestTipSet...)) if err != nil { log.Errorf("failed to fetch tipset from peer during hello: %+v", err) @@ -117,9 +121,6 @@ func (hs *Service) HandleStream(s inet.Stream) { log.Infof("Got new tipset through Hello: %s from %s", ts.Cids(), s.Conn().RemotePeer()) hs.syncer.InformNewHead(s.Conn().RemotePeer(), ts) } - if hs.pmgr != nil { - hs.pmgr.AddFilecoinPeer(s.Conn().RemotePeer()) - } } From 44f4372ca3115f5c926bef3239927d14b8adad55 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 8 Sep 2020 20:42:20 +0200 Subject: [PATCH 095/199] Add StageFetchingMessages to sync status Signed-off-by: Jakub Sztandera --- api/api_full.go | 21 +++++++++++++++++++++ chain/sync.go | 3 +++ chain/syncstate.go | 18 ------------------ cli/sync.go | 5 ++--- tools/stats/rpc.go | 5 ++--- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 1cc6837be..9d1d7ab63 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -2,6 +2,7 @@ package api import ( "context" + "fmt" "time" "github.com/filecoin-project/specs-actors/actors/runtime/proof" @@ -709,8 +710,28 @@ const ( StageMessages StageSyncComplete StageSyncErrored + StageFetchingMessages ) +func (v SyncStateStage) String() string { + switch v { + case StageHeaders: + return "header sync" + case StagePersistHeaders: + return "persisting headers" + case StageMessages: + return "message sync" + case StageSyncComplete: + return "complete" + case StageSyncErrored: + return "error" + case StageFetchingMessages: + return "fetching messages" + default: + return fmt.Sprintf("", v) + } +} + type MpoolChange int const ( diff --git a/chain/sync.go b/chain/sync.go index 91d212e37..173866259 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -1439,6 +1439,7 @@ func (syncer *Syncer) syncMessagesAndCheckState(ctx context.Context, headers []* // fills out each of the given tipsets with messages and calls the callback with it func (syncer *Syncer) iterFullTipsets(ctx context.Context, headers []*types.TipSet, cb func(context.Context, *store.FullTipSet) error) error { + ss := extractSyncState(ctx) ctx, span := trace.StartSpan(ctx, "iterFullTipsets") defer span.End() @@ -1466,6 +1467,7 @@ mainLoop: nextI := (i + 1) - batchSize // want to fetch batchSize values, 'i' points to last one we want to fetch, so its 'inclusive' of our request, thus we need to add one to our request start index + ss.SetStage(api.StageFetchingMessages) var bstout []*blocksync.CompactedMessages for len(bstout) < batchSize { next := headers[nextI] @@ -1485,6 +1487,7 @@ mainLoop: bstout = append(bstout, bstips...) nextI += len(bstips) } + ss.SetStage(api.StageMessages) for bsi := 0; bsi < len(bstout); bsi++ { // temp storage so we don't persist data we dont want to diff --git a/chain/syncstate.go b/chain/syncstate.go index 4dc193072..06cd5d91e 100644 --- a/chain/syncstate.go +++ b/chain/syncstate.go @@ -1,7 +1,6 @@ package chain import ( - "fmt" "sync" "time" @@ -12,23 +11,6 @@ import ( "github.com/filecoin-project/lotus/chain/types" ) -func SyncStageString(v api.SyncStateStage) string { - switch v { - case api.StageHeaders: - return "header sync" - case api.StagePersistHeaders: - return "persisting headers" - case api.StageMessages: - return "message sync" - case api.StageSyncComplete: - return "complete" - case api.StageSyncErrored: - return "error" - default: - return fmt.Sprintf("", v) - } -} - type SyncerState struct { lk sync.Mutex Target *types.TipSet diff --git a/cli/sync.go b/cli/sync.go index 24abfc0a1..a92cd9437 100644 --- a/cli/sync.go +++ b/cli/sync.go @@ -11,7 +11,6 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain" ) var syncCmd = &cli.Command{ @@ -61,7 +60,7 @@ var syncStatusCmd = &cli.Command{ fmt.Printf("\tBase:\t%s\n", base) fmt.Printf("\tTarget:\t%s (%d)\n", target, theight) fmt.Printf("\tHeight diff:\t%d\n", heightDiff) - fmt.Printf("\tStage: %s\n", chain.SyncStageString(ss.Stage)) + fmt.Printf("\tStage: %s\n", ss.Stage) fmt.Printf("\tHeight: %d\n", ss.Height) if ss.End.IsZero() { if !ss.Start.IsZero() { @@ -186,7 +185,7 @@ func SyncWait(ctx context.Context, napi api.FullNode) error { theight = ss.Target.Height() } - fmt.Printf("\r\x1b[2KWorker %d: Target Height: %d\tTarget: %s\tState: %s\tHeight: %d", working, theight, target, chain.SyncStageString(ss.Stage), ss.Height) + fmt.Printf("\r\x1b[2KWorker %d: Target Height: %d\tTarget: %s\tState: %s\tHeight: %d", working, theight, target, ss.Stage, ss.Height) if time.Now().Unix()-int64(head.MinTimestamp()) < int64(build.BlockDelaySecs) { fmt.Println("\nDone!") diff --git a/tools/stats/rpc.go b/tools/stats/rpc.go index cfebdbddb..b01c07a35 100644 --- a/tools/stats/rpc.go +++ b/tools/stats/rpc.go @@ -14,7 +14,6 @@ import ( "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api/client" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/node/repo" @@ -72,7 +71,7 @@ sync_complete: "target_height", w.Target.Height(), "height", w.Height, "error", w.Message, - "stage", chain.SyncStageString(w.Stage), + "stage", w.Stage.String(), ) } else { log.Infow( @@ -82,7 +81,7 @@ sync_complete: "target", w.Target.Key(), "target_height", w.Target.Height(), "height", w.Height, - "stage", chain.SyncStageString(w.Stage), + "stage", w.Stage.String(), ) } From 38863d30256968bbb7a8c3ee4ca3fcc7a410bb2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Tue, 8 Sep 2020 20:54:37 +0200 Subject: [PATCH 096/199] build: Separate API versions per node type --- api/docgen/docgen.go | 2 +- api/test/test.go | 2 ++ build/version.go | 39 ++++++++++++++++++++++++++++++--- cmd/lotus-seal-worker/main.go | 6 +++-- cmd/lotus-seal-worker/rpc.go | 2 +- cmd/lotus-storage-miner/init.go | 4 ++-- cmd/lotus-storage-miner/main.go | 2 ++ cmd/lotus-storage-miner/run.go | 4 ++-- cmd/lotus/main.go | 2 ++ node/impl/common/common.go | 7 +++++- 10 files changed, 58 insertions(+), 12 deletions(-) diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index ea3e66e1e..d00643a02 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -105,7 +105,7 @@ func init() { addExample(network.Connected) addExample(dtypes.NetworkName("lotus")) addExample(api.SyncStateStage(1)) - addExample(build.APIVersion) + addExample(build.FullAPIVersion) addExample(api.PCHInbound) addExample(time.Minute) addExample(datatransfer.TransferID(3)) diff --git a/api/test/test.go b/api/test/test.go index 98a9a2e48..409274ff1 100644 --- a/api/test/test.go +++ b/api/test/test.go @@ -65,6 +65,8 @@ func TestApis(t *testing.T, b APIBuilder) { var OneMiner = []StorageMiner{{Full: 0, Preseal: PresealGenesis}} func (ts *testSuite) testVersion(t *testing.T) { + build.RunningNodeType = build.NodeFull + ctx := context.Background() apis, _ := ts.makeNodes(t, 1, OneMiner) api := apis[0] diff --git a/build/version.go b/build/version.go index adaade907..54a3af007 100644 --- a/build/version.go +++ b/build/version.go @@ -1,6 +1,10 @@ package build -import "fmt" +import ( + "fmt" + + "golang.org/x/xerrors" +) var CurrentCommit string var BuildType int @@ -52,8 +56,37 @@ func (ve Version) EqMajorMinor(v2 Version) bool { return ve&minorMask == v2&minorMask } -// APIVersion is a semver version of the rpc api exposed -var APIVersion Version = newVer(0, 14, 0) +type NodeType int + +const ( + NodeUnknown NodeType = iota + + NodeFull + NodeMiner + NodeWorker +) + +var RunningNodeType NodeType + +func VersionForType(nodeType NodeType) (Version, error) { + switch nodeType { + case NodeFull: + return FullAPIVersion, nil + case NodeMiner: + return MinerAPIVersion, nil + case NodeWorker: + return WorkerAPIVersion, nil + default: + return Version(0), xerrors.Errorf("unknown node type %d", nodeType) + } +} + +// semver versions of the rpc api exposed +var ( + FullAPIVersion = newVer(0, 14, 0) + MinerAPIVersion = newVer(0, 14, 0) + WorkerAPIVersion = newVer(0, 14, 0) +) //nolint:varcheck,deadcode const ( diff --git a/cmd/lotus-seal-worker/main.go b/cmd/lotus-seal-worker/main.go index e6361d3cf..e36514bb8 100644 --- a/cmd/lotus-seal-worker/main.go +++ b/cmd/lotus-seal-worker/main.go @@ -45,6 +45,8 @@ const FlagWorkerRepo = "worker-repo" const FlagWorkerRepoDeprecation = "workerrepo" func main() { + build.RunningNodeType = build.NodeWorker + lotuslog.SetupLogLevels() local := []*cli.Command{ @@ -187,8 +189,8 @@ var runCmd = &cli.Command{ if err != nil { return err } - if v.APIVersion != build.APIVersion { - return xerrors.Errorf("lotus-miner API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion}) + if v.APIVersion != build.MinerAPIVersion { + return xerrors.Errorf("lotus-miner API version doesn't match: expected: %s", api.Version{APIVersion: build.MinerAPIVersion}) } log.Infof("Remote version %s", v) diff --git a/cmd/lotus-seal-worker/rpc.go b/cmd/lotus-seal-worker/rpc.go index 5380fe432..8aa9093c2 100644 --- a/cmd/lotus-seal-worker/rpc.go +++ b/cmd/lotus-seal-worker/rpc.go @@ -21,7 +21,7 @@ type worker struct { } func (w *worker) Version(context.Context) (build.Version, error) { - return build.APIVersion, nil + return build.WorkerAPIVersion, nil } func (w *worker) StorageAddLocal(ctx context.Context, path string) error { diff --git a/cmd/lotus-storage-miner/init.go b/cmd/lotus-storage-miner/init.go index 9fbdcb8d4..ba9460dab 100644 --- a/cmd/lotus-storage-miner/init.go +++ b/cmd/lotus-storage-miner/init.go @@ -179,8 +179,8 @@ var initCmd = &cli.Command{ return err } - if !v.APIVersion.EqMajorMinor(build.APIVersion) { - return xerrors.Errorf("Remote API version didn't match (local %s, remote %s)", build.APIVersion, v.APIVersion) + if !v.APIVersion.EqMajorMinor(build.FullAPIVersion) { + return xerrors.Errorf("Remote API version didn't match (expected %s, remote %s)", build.FullAPIVersion, v.APIVersion) } log.Info("Initializing repo") diff --git a/cmd/lotus-storage-miner/main.go b/cmd/lotus-storage-miner/main.go index cc704f891..cee64f077 100644 --- a/cmd/lotus-storage-miner/main.go +++ b/cmd/lotus-storage-miner/main.go @@ -26,6 +26,8 @@ const FlagMinerRepo = "miner-repo" const FlagMinerRepoDeprecation = "storagerepo" func main() { + build.RunningNodeType = build.NodeMiner + lotuslog.SetupLogLevels() local := []*cli.Command{ diff --git a/cmd/lotus-storage-miner/run.go b/cmd/lotus-storage-miner/run.go index 7c88b74c4..83d78172e 100644 --- a/cmd/lotus-storage-miner/run.go +++ b/cmd/lotus-storage-miner/run.go @@ -77,8 +77,8 @@ var runCmd = &cli.Command{ } } - if v.APIVersion != build.APIVersion { - return xerrors.Errorf("lotus-daemon API version doesn't match: local: %s", api.Version{APIVersion: build.APIVersion}) + if v.APIVersion != build.FullAPIVersion { + return xerrors.Errorf("lotus-daemon API version doesn't match: expected: %s", api.Version{APIVersion: build.FullAPIVersion}) } log.Info("Checking full node sync status") diff --git a/cmd/lotus/main.go b/cmd/lotus/main.go index 1e2c7faec..ee95ad64b 100644 --- a/cmd/lotus/main.go +++ b/cmd/lotus/main.go @@ -16,6 +16,8 @@ import ( var AdvanceBlockCmd *cli.Command func main() { + build.RunningNodeType = build.NodeFull + lotuslog.SetupLogLevels() local := []*cli.Command{ diff --git a/node/impl/common/common.go b/node/impl/common/common.go index 6a69b2a7a..b07c18305 100644 --- a/node/impl/common/common.go +++ b/node/impl/common/common.go @@ -170,9 +170,14 @@ func (a *CommonAPI) ID(context.Context) (peer.ID, error) { } func (a *CommonAPI) Version(context.Context) (api.Version, error) { + v, err := build.VersionForType(build.RunningNodeType) + if err != nil { + return api.Version{}, err + } + return api.Version{ Version: build.UserVersion(), - APIVersion: build.APIVersion, + APIVersion: v, BlockDelay: build.BlockDelaySecs, }, nil From 8a8f0ab3eca65d09d50e0980ac3381572eba60a2 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 8 Sep 2020 13:45:44 -0700 Subject: [PATCH 097/199] pass tipset through upgrade logic --- chain/stmgr/forks.go | 10 +++++----- chain/stmgr/forks_test.go | 2 +- chain/stmgr/stmgr.go | 6 +++--- chain/stmgr/utils.go | 2 +- conformance/driver.go | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/chain/stmgr/forks.go b/chain/stmgr/forks.go index 769cae7c0..addaba90f 100644 --- a/chain/stmgr/forks.go +++ b/chain/stmgr/forks.go @@ -17,14 +17,14 @@ import ( "golang.org/x/xerrors" ) -var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree) error{ +var ForksAtHeight = map[abi.ChainEpoch]func(context.Context, *StateManager, types.StateTree, *types.TipSet) error{ build.UpgradeBreezeHeight: UpgradeFaucetBurnRecovery, } -func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree, height abi.ChainEpoch) (err error) { +func (sm *StateManager) handleStateForks(ctx context.Context, st types.StateTree, height abi.ChainEpoch, ts *types.TipSet) (err error) { f, ok := ForksAtHeight[height] if ok { - err := f(ctx, sm, st) + err := f(ctx, sm, st, ts) if err != nil { return err } @@ -66,7 +66,7 @@ func doTransfer(tree types.StateTree, from, to address.Address, amt abi.TokenAmo return nil } -func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types.StateTree) error { +func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types.StateTree, ts *types.TipSet) error { // Some initial parameters FundsForMiners := types.FromFil(1_000_000) LookbackEpoch := abi.ChainEpoch(32000) @@ -91,7 +91,7 @@ func UpgradeFaucetBurnRecovery(ctx context.Context, sm *StateManager, tree types } // Grab lookback state for account checks - lbts, err := sm.ChainStore().GetTipsetByHeight(ctx, LookbackEpoch, nil, false) + lbts, err := sm.ChainStore().GetTipsetByHeight(ctx, LookbackEpoch, ts, false) if err != nil { return xerrors.Errorf("failed to get tipset at lookback height: %w", err) } diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index 7b7671317..b5fb0c602 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -119,7 +119,7 @@ func TestForkHeightTriggers(t *testing.T) { t.Fatal(err) } - stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, st types.StateTree) error { + stmgr.ForksAtHeight[testForkHeight] = func(ctx context.Context, sm *StateManager, st types.StateTree, ts *types.TipSet) error { cst := cbor.NewCborStore(sm.ChainStore().Blockstore()) act, err := st.GetActor(taddr) diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 5679991ae..929c9daf7 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -147,7 +147,7 @@ func (sm *StateManager) ExecutionTrace(ctx context.Context, ts *types.TipSet) (c type ExecCallback func(cid.Cid, *types.Message, *vm.ApplyRet) error -func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount) (cid.Cid, cid.Cid, error) { +func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEpoch, pstate cid.Cid, bms []store.BlockMessages, epoch abi.ChainEpoch, r vm.Rand, cb ExecCallback, baseFee abi.TokenAmount, ts *types.TipSet) (cid.Cid, cid.Cid, error) { vmopt := &vm.VMOpts{ StateBase: pstate, @@ -201,7 +201,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, parentEpoch abi.ChainEp for i := parentEpoch; i < epoch; i++ { // handle state forks - err = sm.handleStateForks(ctx, vmi.StateTree(), i) + err = sm.handleStateForks(ctx, vmi.StateTree(), i, ts) if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("error handling state forks: %w", err) } @@ -350,7 +350,7 @@ func (sm *StateManager) computeTipSetState(ctx context.Context, ts *types.TipSet baseFee := blks[0].ParentBaseFee - return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee) + return sm.ApplyBlocks(ctx, parentEpoch, pstate, blkmsgs, blks[0].Height, r, cb, baseFee, ts) } func (sm *StateManager) parentState(ts *types.TipSet) cid.Cid { diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index ab7f4f472..b21400da6 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -456,7 +456,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch, for i := ts.Height(); i < height; i++ { // handle state forks - err = sm.handleStateForks(ctx, vmi.StateTree(), i) + err = sm.handleStateForks(ctx, vmi.StateTree(), i, ts) if err != nil { return cid.Undef, nil, xerrors.Errorf("error handling state forks: %w", err) } diff --git a/conformance/driver.go b/conformance/driver.go index b6a61dac0..0cc5844f5 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -102,7 +102,7 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, preroot messages = append(messages, msg) results = append(results, ret) return nil - }, tipset.BaseFee) + }, tipset.BaseFee, nil) if err != nil { return nil, err From 63cdbef2197c8182b0dc1982249e649e13a93c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Tue, 8 Sep 2020 21:50:25 +0100 Subject: [PATCH 098/199] temp fix test-vectors import cycle. --- conformance/chaos/actor.go | 231 +++++++++++++ conformance/chaos/cbor_gen.go | 616 ++++++++++++++++++++++++++++++++++ conformance/chaos/gen/gen.go | 20 ++ conformance/chaos/ids.go | 29 ++ conformance/chaos/state.go | 32 ++ conformance/driver.go | 9 +- conformance/runner_test.go | 8 +- go.mod | 4 +- 8 files changed, 940 insertions(+), 9 deletions(-) create mode 100644 conformance/chaos/actor.go create mode 100644 conformance/chaos/cbor_gen.go create mode 100644 conformance/chaos/gen/gen.go create mode 100644 conformance/chaos/ids.go create mode 100644 conformance/chaos/state.go diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go new file mode 100644 index 000000000..f10c135e0 --- /dev/null +++ b/conformance/chaos/actor.go @@ -0,0 +1,231 @@ +package chaos + +import ( + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/ipfs/go-cid" + "github.com/whyrusleeping/cbor-gen" +) + +//go:generate go run ./gen + +// Actor is a chaos actor. It implements a variety of illegal behaviours that +// trigger violations of VM invariants. These behaviours are not found in +// production code, but are important to test that the VM constraints are +// properly enforced. +// +// The chaos actor is being incubated and its behaviour and ABI be standardised +// shortly. Its CID is ChaosActorCodeCID, and its singleton address is 98 (Address). +// It cannot be instantiated via the init actor, and its constructor panics. +// +// Test vectors relying on the chaos actor being deployed will carry selector +// "chaos_actor:true". +type Actor struct{} + +// CallerValidationBranch is an enum used to select a branch in the +// CallerValidation method. +type CallerValidationBranch int64 + +const ( + CallerValidationBranchNone CallerValidationBranch = iota + CallerValidationBranchTwice + CallerValidationBranchAddrNilSet + CallerValidationBranchTypeNilSet +) + +// MutateStateBranch is an enum used to select the type of state mutation to attempt. +type MutateStateBranch int64 + +const ( + // MutateInTransaction legally mutates state within a transaction. + MutateInTransaction MutateStateBranch = iota + // MutateReadonly ILLEGALLY mutates readonly state. + MutateReadonly + // MutateAfterTransaction ILLEGALLY mutates state after a transaction. + MutateAfterTransaction +) + +const ( + _ = 0 // skip zero iota value; first usage of iota gets 1. + MethodCallerValidation = builtin.MethodConstructor + iota + MethodCreateActor + MethodResolveAddress + // MethodDeleteActor is the identifier for the method that deletes this actor. + MethodDeleteActor + // MethodSend is the identifier for the method that sends a message to another actor. + MethodSend + // MethodMutateState is the identifier for the method that attempts to mutate + // a state value in the actor. + MethodMutateState +) + +// Exports defines the methods this actor exposes publicly. +func (a Actor) Exports() []interface{} { + return []interface{}{ + builtin.MethodConstructor: a.Constructor, + MethodCallerValidation: a.CallerValidation, + MethodCreateActor: a.CreateActor, + MethodResolveAddress: a.ResolveAddress, + MethodDeleteActor: a.DeleteActor, + MethodSend: a.Send, + MethodMutateState: a.MutateState, + } +} + +var _ runtime.Invokee = Actor{} + +// SendArgs are the arguments for the Send method. +type SendArgs struct { + To address.Address + Value abi.TokenAmount + Method abi.MethodNum + Params []byte +} + +// SendReturn is the return values for the Send method. +type SendReturn struct { + Return runtime.CBORBytes + Code exitcode.ExitCode +} + +// Send requests for this actor to send a message to an actor with the +// passed parameters. +func (a Actor) Send(rt runtime.Runtime, args *SendArgs) *SendReturn { + rt.ValidateImmediateCallerAcceptAny() + ret, code := rt.Send( + args.To, + args.Method, + runtime.CBORBytes(args.Params), + args.Value, + ) + var out runtime.CBORBytes + if ret != nil { + if err := ret.Into(&out); err != nil { + rt.Abortf(exitcode.ErrIllegalState, "failed to unmarshal send return: %v", err) + } + } + return &SendReturn{ + Return: out, + Code: code, + } +} + +// Constructor will panic because the Chaos actor is a singleton. +func (a Actor) Constructor(_ runtime.Runtime, _ *adt.EmptyValue) *adt.EmptyValue { + panic("constructor should not be called; the Chaos actor is a singleton actor") +} + +// CallerValidation violates VM call validation constraints. +// +// CallerValidationBranchNone performs no validation. +// CallerValidationBranchTwice validates twice. +// CallerValidationBranchAddrNilSet validates against an empty caller +// address set. +// CallerValidationBranchTypeNilSet validates against an empty caller type set. +func (a Actor) CallerValidation(rt runtime.Runtime, branch *typegen.CborInt) *adt.EmptyValue { + switch CallerValidationBranch(*branch) { + case CallerValidationBranchNone: + case CallerValidationBranchTwice: + rt.ValidateImmediateCallerAcceptAny() + rt.ValidateImmediateCallerAcceptAny() + case CallerValidationBranchAddrNilSet: + rt.ValidateImmediateCallerIs() + case CallerValidationBranchTypeNilSet: + rt.ValidateImmediateCallerType() + default: + panic("invalid branch passed to CallerValidation") + } + + return nil +} + +// CreateActorArgs are the arguments to CreateActor. +type CreateActorArgs struct { + // UndefActorCID instructs us to use cid.Undef; we can't pass cid.Undef + // in ActorCID because it doesn't serialize. + UndefActorCID bool + ActorCID cid.Cid + + // UndefAddress is the same as UndefActorCID but for Address. + UndefAddress bool + Address address.Address +} + +// CreateActor creates an actor with the supplied CID and Address. +func (a Actor) CreateActor(rt runtime.Runtime, args *CreateActorArgs) *adt.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + + var ( + acid = args.ActorCID + addr = args.Address + ) + + if args.UndefActorCID { + acid = cid.Undef + } + if args.UndefAddress { + addr = address.Undef + } + + rt.CreateActor(acid, addr) + return nil +} + +// ResolveAddressResponse holds the response of a call to runtime.ResolveAddress +type ResolveAddressResponse struct { + Address address.Address + Success bool +} + +func (a Actor) ResolveAddress(rt runtime.Runtime, args *address.Address) *ResolveAddressResponse { + rt.ValidateImmediateCallerAcceptAny() + + resolvedAddr, ok := rt.ResolveAddress(*args) + if !ok { + invalidAddr, _ := address.NewIDAddress(0) + resolvedAddr = invalidAddr + } + return &ResolveAddressResponse{resolvedAddr, ok} +} + +// DeleteActor deletes the executing actor from the state tree, transferring any +// balance to beneficiary. +func (a Actor) DeleteActor(rt runtime.Runtime, beneficiary *address.Address) *adt.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + rt.DeleteActor(*beneficiary) + return nil +} + +// MutateStateArgs specify the value to set on the state and the way in which +// it should be attempted to be set. +type MutateStateArgs struct { + Value string + Branch MutateStateBranch +} + +// MutateState attempts to mutate a state value in the actor. +func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *adt.EmptyValue { + rt.ValidateImmediateCallerAcceptAny() + var st State + switch args.Branch { + case MutateInTransaction: + rt.State().Transaction(&st, func() { + st.Value = args.Value + }) + case MutateReadonly: + rt.State().Readonly(&st) + st.Value = args.Value + case MutateAfterTransaction: + rt.State().Transaction(&st, func() { + st.Value = args.Value + "-in" + }) + st.Value = args.Value + default: + panic("unknown mutation type") + } + return nil +} diff --git a/conformance/chaos/cbor_gen.go b/conformance/chaos/cbor_gen.go new file mode 100644 index 000000000..9f01ccce7 --- /dev/null +++ b/conformance/chaos/cbor_gen.go @@ -0,0 +1,616 @@ +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package chaos + +import ( + "fmt" + "io" + + abi "github.com/filecoin-project/go-state-types/abi" + exitcode "github.com/filecoin-project/go-state-types/exitcode" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf + +var lengthBufState = []byte{130} + +func (t *State) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufState); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Value (string) (string) + if len(t.Value) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Value was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.Value))); err != nil { + return err + } + if _, err := io.WriteString(w, string(t.Value)); err != nil { + return err + } + + // t.Unmarshallable ([]*chaos.UnmarshallableCBOR) (slice) + if len(t.Unmarshallable) > cbg.MaxLength { + return xerrors.Errorf("Slice value in field t.Unmarshallable was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajArray, uint64(len(t.Unmarshallable))); err != nil { + return err + } + for _, v := range t.Unmarshallable { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *State) UnmarshalCBOR(r io.Reader) error { + *t = State{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Value (string) (string) + + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + t.Value = string(sval) + } + // t.Unmarshallable ([]*chaos.UnmarshallableCBOR) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.MaxLength { + return fmt.Errorf("t.Unmarshallable: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Unmarshallable = make([]*UnmarshallableCBOR, extra) + } + + for i := 0; i < int(extra); i++ { + + var v UnmarshallableCBOR + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Unmarshallable[i] = &v + } + + return nil +} + +var lengthBufCreateActorArgs = []byte{132} + +func (t *CreateActorArgs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufCreateActorArgs); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.UndefActorCID (bool) (bool) + if err := cbg.WriteBool(w, t.UndefActorCID); err != nil { + return err + } + + // t.ActorCID (cid.Cid) (struct) + + if err := cbg.WriteCidBuf(scratch, w, t.ActorCID); err != nil { + return xerrors.Errorf("failed to write cid field t.ActorCID: %w", err) + } + + // t.UndefAddress (bool) (bool) + if err := cbg.WriteBool(w, t.UndefAddress); err != nil { + return err + } + + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *CreateActorArgs) UnmarshalCBOR(r io.Reader) error { + *t = CreateActorArgs{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.UndefActorCID (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.UndefActorCID = false + case 21: + t.UndefActorCID = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.ActorCID (cid.Cid) (struct) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.ActorCID: %w", err) + } + + t.ActorCID = c + + } + // t.UndefAddress (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.UndefAddress = false + case 21: + t.UndefAddress = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Address (address.Address) (struct) + + { + + if err := t.Address.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Address: %w", err) + } + + } + return nil +} + +var lengthBufResolveAddressResponse = []byte{130} + +func (t *ResolveAddressResponse) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufResolveAddressResponse); err != nil { + return err + } + + // t.Address (address.Address) (struct) + if err := t.Address.MarshalCBOR(w); err != nil { + return err + } + + // t.Success (bool) (bool) + if err := cbg.WriteBool(w, t.Success); err != nil { + return err + } + return nil +} + +func (t *ResolveAddressResponse) UnmarshalCBOR(r io.Reader) error { + *t = ResolveAddressResponse{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Address (address.Address) (struct) + + { + + if err := t.Address.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Address: %w", err) + } + + } + // t.Success (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Success = false + case 21: + t.Success = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + return nil +} + +var lengthBufSendArgs = []byte{132} + +func (t *SendArgs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufSendArgs); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.To (address.Address) (struct) + if err := t.To.MarshalCBOR(w); err != nil { + return err + } + + // t.Value (big.Int) (struct) + if err := t.Value.MarshalCBOR(w); err != nil { + return err + } + + // t.Method (abi.MethodNum) (uint64) + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Method)); err != nil { + return err + } + + // t.Params ([]uint8) (slice) + if len(t.Params) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Params was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.Params))); err != nil { + return err + } + + if _, err := w.Write(t.Params[:]); err != nil { + return err + } + return nil +} + +func (t *SendArgs) UnmarshalCBOR(r io.Reader) error { + *t = SendArgs{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 4 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.To (address.Address) (struct) + + { + + if err := t.To.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.To: %w", err) + } + + } + // t.Value (big.Int) (struct) + + { + + if err := t.Value.UnmarshalCBOR(br); err != nil { + return xerrors.Errorf("unmarshaling t.Value: %w", err) + } + + } + // t.Method (abi.MethodNum) (uint64) + + { + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Method = abi.MethodNum(extra) + + } + // t.Params ([]uint8) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Params: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Params = make([]uint8, extra) + } + + if _, err := io.ReadFull(br, t.Params[:]); err != nil { + return err + } + return nil +} + +var lengthBufSendReturn = []byte{130} + +func (t *SendReturn) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufSendReturn); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Return (runtime.CBORBytes) (slice) + if len(t.Return) > cbg.ByteArrayMaxLen { + return xerrors.Errorf("Byte array in field t.Return was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajByteString, uint64(len(t.Return))); err != nil { + return err + } + + if _, err := w.Write(t.Return[:]); err != nil { + return err + } + + // t.Code (exitcode.ExitCode) (int64) + if t.Code >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Code)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Code-1)); err != nil { + return err + } + } + return nil +} + +func (t *SendReturn) UnmarshalCBOR(r io.Reader) error { + *t = SendReturn{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Return (runtime.CBORBytes) (slice) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + + if extra > cbg.ByteArrayMaxLen { + return fmt.Errorf("t.Return: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Return = make([]uint8, extra) + } + + if _, err := io.ReadFull(br, t.Return[:]); err != nil { + return err + } + // t.Code (exitcode.ExitCode) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Code = exitcode.ExitCode(extraI) + } + return nil +} + +var lengthBufMutateStateArgs = []byte{130} + +func (t *MutateStateArgs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufMutateStateArgs); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Value (string) (string) + if len(t.Value) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Value was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.Value))); err != nil { + return err + } + if _, err := io.WriteString(w, string(t.Value)); err != nil { + return err + } + + // t.Branch (chaos.MutateStateBranch) (int64) + if t.Branch >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Branch)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Branch-1)); err != nil { + return err + } + } + return nil +} + +func (t *MutateStateArgs) UnmarshalCBOR(r io.Reader) error { + *t = MutateStateArgs{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 2 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Value (string) (string) + + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + t.Value = string(sval) + } + // t.Branch (chaos.MutateStateBranch) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Branch = MutateStateBranch(extraI) + } + return nil +} diff --git a/conformance/chaos/gen/gen.go b/conformance/chaos/gen/gen.go new file mode 100644 index 000000000..308fed11e --- /dev/null +++ b/conformance/chaos/gen/gen.go @@ -0,0 +1,20 @@ +package main + +import ( + "github.com/filecoin-project/lotus/conformance/chaos" + + gen "github.com/whyrusleeping/cbor-gen" +) + +func main() { + if err := gen.WriteTupleEncodersToFile("../cbor_gen.go", "chaos", + chaos.State{}, + chaos.CreateActorArgs{}, + chaos.ResolveAddressResponse{}, + chaos.SendArgs{}, + chaos.SendReturn{}, + chaos.MutateStateArgs{}, + ); err != nil { + panic(err) + } +} diff --git a/conformance/chaos/ids.go b/conformance/chaos/ids.go new file mode 100644 index 000000000..6b0ad86a7 --- /dev/null +++ b/conformance/chaos/ids.go @@ -0,0 +1,29 @@ +package chaos + +import ( + "github.com/filecoin-project/go-address" + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" +) + +// ChaosActorCodeCID is the CID by which this kind of actor will be identified. +var ChaosActorCodeCID = func() cid.Cid { + builder := cid.V1Builder{Codec: cid.Raw, MhType: multihash.IDENTITY} + c, err := builder.Sum([]byte("fil/1/chaos")) + if err != nil { + panic(err) + } + return c +}() + +// Address is the singleton address of this actor. Its value is 98 +// (builtin.FirstNonSingletonActorId - 2), as 99 is reserved for the burnt funds +// singleton. +var Address = func() address.Address { + // the address before the burnt funds address (99) + addr, err := address.NewIDAddress(98) + if err != nil { + panic(err) + } + return addr +}() diff --git a/conformance/chaos/state.go b/conformance/chaos/state.go new file mode 100644 index 000000000..4a54ef61c --- /dev/null +++ b/conformance/chaos/state.go @@ -0,0 +1,32 @@ +package chaos + +import ( + "fmt" + "io" +) + +// State is the state for the chaos actor used by some methods to invoke +// behaviours in the vm or runtime. +type State struct { + // Value can be updated by chaos actor methods to test illegal state + // mutations when the state is in readonly mode for example. + Value string + // Unmarshallable is a sentinel value. If the slice contains no values, the + // State struct will encode as CBOR without issue. If the slice is non-nil, + // CBOR encoding will fail. + Unmarshallable []*UnmarshallableCBOR +} + +// UnmarshallableCBOR is a type that cannot be marshalled or unmarshalled to +// CBOR despite implementing the CBORMarshaler and CBORUnmarshaler interface. +type UnmarshallableCBOR struct{} + +// UnmarshalCBOR will fail to unmarshal the value from CBOR. +func (t *UnmarshallableCBOR) UnmarshalCBOR(io.Reader) error { + return fmt.Errorf("failed to unmarshal cbor") +} + +// MarshalCBOR will fail to marshal the value to CBOR. +func (t *UnmarshallableCBOR) MarshalCBOR(io.Writer) error { + return fmt.Errorf("failed to marshal cbor") +} diff --git a/conformance/driver.go b/conformance/driver.go index b6a61dac0..0c9607988 100644 --- a/conformance/driver.go +++ b/conformance/driver.go @@ -9,12 +9,12 @@ import ( "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" + "github.com/filecoin-project/lotus/conformance/chaos" "github.com/filecoin-project/lotus/extern/sector-storage/ffiwrapper" "github.com/filecoin-project/lotus/lib/blockstore" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/test-vectors/chaos" "github.com/filecoin-project/test-vectors/schema" "github.com/filecoin-project/go-address" @@ -96,13 +96,16 @@ func (d *Driver) ExecuteTipset(bs blockstore.Blockstore, ds ds.Batching, preroot var ( messages []*types.Message results []*vm.ApplyRet + + epoch = abi.ChainEpoch(tipset.Epoch) + basefee = abi.NewTokenAmount(tipset.BaseFee.Int64()) ) - postcid, receiptsroot, err := sm.ApplyBlocks(context.Background(), parentEpoch, preroot, blocks, tipset.Epoch, vmRand, func(_ cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { + postcid, receiptsroot, err := sm.ApplyBlocks(context.Background(), parentEpoch, preroot, blocks, epoch, vmRand, func(_ cid.Cid, msg *types.Message, ret *vm.ApplyRet) error { messages = append(messages, msg) results = append(results, ret) return nil - }, tipset.BaseFee) + }, basefee) if err != nil { return nil, err diff --git a/conformance/runner_test.go b/conformance/runner_test.go index 87317fc8d..59d40d052 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -14,6 +14,8 @@ import ( "strings" "testing" + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" @@ -177,7 +179,7 @@ func executeMessageVector(t *testing.T, vector *schema.TestVector) { // Execute the message. var ret *vm.ApplyRet - ret, root, err = driver.ExecuteMessage(bs, root, epoch, msg) + ret, root, err = driver.ExecuteMessage(bs, root, abi.ChainEpoch(epoch), msg) if err != nil { t.Fatalf("fatal failure when executing message: %s", err) } @@ -212,7 +214,7 @@ func executeTipsetVector(t *testing.T, vector *schema.TestVector) { var receiptsIdx int for i, ts := range vector.ApplyTipsets { ts := ts // capture - ret, err := driver.ExecuteTipset(bs, tmpds, root, prevEpoch, &ts) + ret, err := driver.ExecuteTipset(bs, tmpds, root, abi.ChainEpoch(prevEpoch), &ts) if err != nil { t.Fatalf("failed to apply tipset %d message: %s", i, err) } @@ -244,7 +246,7 @@ func executeTipsetVector(t *testing.T, vector *schema.TestVector) { func assertMsgResult(t *testing.T, expected *schema.Receipt, actual *vm.ApplyRet, label string) { t.Helper() - if expected, actual := expected.ExitCode, actual.ExitCode; expected != actual { + if expected, actual := exitcode.ExitCode(expected.ExitCode), actual.ExitCode; expected != actual { t.Errorf("exit code of msg %s did not match; expected: %s, got: %s", label, expected, actual) } if expected, actual := expected.GasUsed, actual.GasUsed; expected != actual { diff --git a/go.mod b/go.mod index 9904e9e5f..c9a593af9 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/filecoin-project/specs-actors v0.9.7 github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 github.com/filecoin-project/statediff v0.0.1 - github.com/filecoin-project/test-vectors v0.0.0-20200907193218-2c0739eccce6 + github.com/filecoin-project/test-vectors/schema v0.0.0-00010101000000-000000000000 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 github.com/google/uuid v1.1.1 @@ -133,5 +133,3 @@ replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 - -replace github.com/filecoin-project/test-vectors => ./extern/test-vectors From 8c0994e290d7b148b0e7444d392b010d6f3b79e5 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 8 Sep 2020 15:47:40 -0700 Subject: [PATCH 099/199] add an auto flag to mpool replace --- cli/mpool.go | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/cli/mpool.go b/cli/mpool.go index 6e335a243..cebbe1a95 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -12,6 +12,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" ) @@ -293,6 +294,10 @@ var mpoolReplaceCmd = &cli.Command{ Name: "gas-limit", Usage: "gas price for new message", }, + &cli.BoolFlag{ + Name: "auto", + Usage: "automatically reprice the specified message", + }, }, ArgsUsage: "[from] [nonce]", Action: func(cctx *cli.Context) error { @@ -342,15 +347,27 @@ var mpoolReplaceCmd = &cli.Command{ msg := found.Message - msg.GasLimit = cctx.Int64("gas-limit") - msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium")) - if err != nil { - return fmt.Errorf("parsing gas-premium: %w", err) - } - // TODO: estimate fee cap here - msg.GasFeeCap, err = types.BigFromString(cctx.String("gas-feecap")) - if err != nil { - return fmt.Errorf("parsing gas-feecap: %w", err) + if cctx.Bool("auto") { + // msg.GasLimit = 0 // TODO: need to fix the way we estimate gas limits to account for the messages already being in the mempool + msg.GasFeeCap = abi.NewTokenAmount(0) + msg.GasPremium = abi.NewTokenAmount(0) + retm, err := api.GasEstimateMessageGas(ctx, &msg, &lapi.MessageSendSpec{}, types.EmptyTSK) + if err != nil { + return fmt.Errorf("failed to estimate gas values: %w", err) + } + msg.GasFeeCap = retm.GasFeeCap + msg.GasPremium = retm.GasPremium + } else { + msg.GasLimit = cctx.Int64("gas-limit") + msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium")) + if err != nil { + return fmt.Errorf("parsing gas-premium: %w", err) + } + // TODO: estimate 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) From 0b09082450b4ad6ff1273b0da60762804cf25ee3 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 9 Sep 2020 12:37:03 +0300 Subject: [PATCH 100/199] adjust optimal selection to always try to fill blocks --- chain/messagepool/selection.go | 71 ++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 454540dbd..a1aa491e9 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -3,6 +3,7 @@ package messagepool import ( "context" "math/big" + "math/rand" "sort" "time" @@ -304,6 +305,69 @@ tailLoop: log.Infow("pack tail chains done", "took", dt) } + // if we have gasLimit to spare, pick some random (non-negative) chains to fill the block + // we pick randomly so that we minimize the probability of duplication among all miners + startRandom := time.Now() + if gasLimit >= minGas { + shuffleChains(chains) + + for _, chain := range chains { + // have we filled the block + if gasLimit < minGas { + break + } + + // has it been merged or invalidated? + if chain.merged || !chain.valid { + continue + } + + // is it negative? + if !allowNegativeChains(curTs.Height()) && chain.gasPerf < 0 { + continue + } + + // compute the dependencies that must be merged and the gas limit including deps + chainGasLimit := chain.gasLimit + depGasLimit := int64(0) + var chainDeps []*msgChain + for curChain := chain.prev; curChain != nil && !curChain.merged; curChain = curChain.prev { + chainDeps = append(chainDeps, curChain) + chainGasLimit += curChain.gasLimit + depGasLimit += curChain.gasLimit + } + + // do the deps fit? if the deps won't fit, invalidate the chain + if depGasLimit > gasLimit { + chain.Invalidate() + continue + } + + // do they fit as is? if it doesn't, trim to make it fit if possible + if chainGasLimit >= gasLimit { + chain.Trim(gasLimit-depGasLimit, mp, baseFee, allowNegativeChains(curTs.Height())) + + if !chain.valid { + continue + } + } + + // include it together with all dependencies + for i := len(chainDeps) - 1; i >= 0; i-- { + curChain := chainDeps[i] + curChain.merged = true + result = append(result, curChain.msgs...) + } + + chain.merged = true + result = append(result, chain.msgs...) + gasLimit -= chainGasLimit + } + } + if dt := time.Since(startRandom); dt > time.Millisecond { + log.Infow("pack random tail chains done", "took", dt) + } + return result, nil } @@ -852,3 +916,10 @@ func (mc *msgChain) BeforeEffective(other *msgChain) bool { (mc.effPerf == other.effPerf && mc.gasPerf > other.gasPerf) || (mc.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0) } + +func shuffleChains(lst []*msgChain) { + for i := range lst { + j := rand.Intn(i + 1) + lst[i], lst[j] = lst[j], lst[i] + } +} From 2aba16e2c9de358bf1aab4113321eeecc8227305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 9 Sep 2020 11:41:02 +0200 Subject: [PATCH 101/199] gas: Fix median calc --- node/impl/full/gas.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 2aa8a39ca..a3496cbd7 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -102,8 +102,8 @@ func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, for _, price := range prices { prev1, prev2 = price.price, prev1 at -= price.limit - if at > 0 { - continue + if at < 0 { + break } } From 194b6eb9d8a33ead19314470429503bda48f49d3 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 9 Sep 2020 12:58:51 +0300 Subject: [PATCH 102/199] fix issue with gasLimit check for trimming (> instead of >=) --- chain/messagepool/selection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index a1aa491e9..b9bbdf304 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -344,7 +344,7 @@ tailLoop: } // do they fit as is? if it doesn't, trim to make it fit if possible - if chainGasLimit >= gasLimit { + if chainGasLimit > gasLimit { chain.Trim(gasLimit-depGasLimit, mp, baseFee, allowNegativeChains(curTs.Height())) if !chain.valid { From f695c0c164313d62bc60f4d7d15f434f63172808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 9 Sep 2020 12:03:02 +0200 Subject: [PATCH 103/199] gas: Add tests to median premium math --- node/impl/full/gas.go | 61 +++++++++++++++++++++----------------- node/impl/full/gas_test.go | 40 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 28 deletions(-) create mode 100644 node/impl/full/gas_test.go diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index a3496cbd7..4f29188c8 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -2,16 +2,15 @@ package full import ( "context" - "math" - "math/rand" - "sort" - "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" + "math" + "math/rand" + "sort" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -50,6 +49,35 @@ func (a *GasAPI) GasEstimateFeeCap(ctx context.Context, msg *types.Message, maxq return out, nil } +type gasMeta struct { + price big.Int + limit int64 +} + +func medianGasPremium(prices []gasMeta, blocks int) abi.TokenAmount { + sort.Slice(prices, func(i, j int) bool { + // sort desc by price + return prices[i].price.GreaterThan(prices[j].price) + }) + + at := build.BlockGasTarget * int64(blocks) / 2 + prev1, prev2 := big.Zero(), big.Zero() + for _, price := range prices { + prev1, prev2 = price.price, prev1 + at -= price.limit + if at < 0 { + break + } + } + + premium := prev1 + if prev2.Sign() != 0 { + premium = big.Div(types.BigAdd(prev1, prev2), types.NewInt(2)) + } + + return premium +} + func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, sender address.Address, gaslimit int64, _ types.TipSetKey) (types.BigInt, error) { @@ -57,11 +85,6 @@ func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, nblocksincl = 1 } - type gasMeta struct { - price big.Int - limit int64 - } - var prices []gasMeta var blocks int @@ -92,25 +115,7 @@ func (a *GasAPI) GasEstimateGasPremium(ctx context.Context, nblocksincl uint64, ts = pts } - sort.Slice(prices, func(i, j int) bool { - // sort desc by price - return prices[i].price.GreaterThan(prices[j].price) - }) - - at := build.BlockGasTarget * int64(blocks) / 2 - prev1, prev2 := big.Zero(), big.Zero() - for _, price := range prices { - prev1, prev2 = price.price, prev1 - at -= price.limit - if at < 0 { - break - } - } - - premium := prev1 - if prev2.Sign() != 0 { - premium = big.Div(types.BigAdd(prev1, prev2), types.NewInt(2)) - } + premium := medianGasPremium(prices, blocks) if types.BigCmp(premium, types.NewInt(MinGasPremium)) < 0 { switch nblocksincl { diff --git a/node/impl/full/gas_test.go b/node/impl/full/gas_test.go new file mode 100644 index 000000000..2452ab807 --- /dev/null +++ b/node/impl/full/gas_test.go @@ -0,0 +1,40 @@ +package full + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/types" +) + +func TestMedian(t *testing.T) { + require.Equal(t, types.NewInt(5), medianGasPremium([]gasMeta{ + {big.NewInt(5), build.BlockGasTarget}, + }, 1)) + + require.Equal(t, types.NewInt(10), medianGasPremium([]gasMeta{ + {big.NewInt(5), build.BlockGasTarget}, + {big.NewInt(10), build.BlockGasTarget}, + }, 1)) + + require.Equal(t, types.NewInt(15), medianGasPremium([]gasMeta{ + {big.NewInt(10), build.BlockGasTarget / 2}, + {big.NewInt(20), build.BlockGasTarget / 2}, + }, 1)) + + require.Equal(t, types.NewInt(25), medianGasPremium([]gasMeta{ + {big.NewInt(10), build.BlockGasTarget / 2}, + {big.NewInt(20), build.BlockGasTarget / 2}, + {big.NewInt(30), build.BlockGasTarget / 2}, + }, 1)) + + require.Equal(t, types.NewInt(15), medianGasPremium([]gasMeta{ + {big.NewInt(10), build.BlockGasTarget / 2}, + {big.NewInt(20), build.BlockGasTarget / 2}, + {big.NewInt(30), build.BlockGasTarget / 2}, + }, 2)) +} From e91ee9f62a43b4942772bb4bb414c31e661e7df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 9 Sep 2020 12:18:02 +0200 Subject: [PATCH 104/199] Fix lint --- node/impl/full/gas.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 4f29188c8..40ab88b6b 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -2,24 +2,25 @@ package full import ( "context" - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/messagepool" - "github.com/filecoin-project/lotus/chain/stmgr" - "github.com/filecoin-project/lotus/chain/store" - "github.com/filecoin-project/lotus/chain/types" "math" "math/rand" "sort" + "go.uber.org/fx" + "golang.org/x/xerrors" + "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/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" - "go.uber.org/fx" - "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/messagepool" + "github.com/filecoin-project/lotus/chain/stmgr" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" ) type GasAPI struct { From 37c0f7549901a5403b619eb7df069005c5bad754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Wed, 9 Sep 2020 13:07:15 +0200 Subject: [PATCH 105/199] Bump version to 0.6.2-rc1 --- build/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/version.go b/build/version.go index adaade907..338be1263 100644 --- a/build/version.go +++ b/build/version.go @@ -25,7 +25,7 @@ func buildType() string { } // BuildVersion is the local build version, set by build system -const BuildVersion = "0.6.1" +const BuildVersion = "0.6.2-rc1" func UserVersion() string { return BuildVersion + buildType() + CurrentCommit From e8d1bab9144aab9e208b15ac84a7c220d9c177bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 9 Sep 2020 13:03:43 +0100 Subject: [PATCH 106/199] make the runner call statediff as a binary. --- .circleci/config.yml | 8 +++ conformance/runner_test.go | 70 +++++++++++++++++-- extern/test-vectors | 2 +- go.mod | 9 ++- go.sum | 138 +++---------------------------------- 5 files changed, 91 insertions(+), 136 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d49d40bf9..bf4149bac 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -231,6 +231,14 @@ jobs: - go/install-gotestsum: gobin: $HOME/.local/bin version: 0.5.2 + - run: + name: install statediff globally + command: | + mkdir -p /tmp/statediff + git clone https://github.com/filecoin-project/statediff.git /tmp/statediff + cd /tmp/statediff + go generate ./... + go install ./cmd/statediff - run: name: go test environment: diff --git a/conformance/runner_test.go b/conformance/runner_test.go index 59d40d052..ca7fdfc63 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -9,6 +9,7 @@ import ( "fmt" "io/ioutil" "os" + "os/exec" "path/filepath" "strconv" "strings" @@ -16,14 +17,17 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" + "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" + "github.com/ipfs/go-ipfs-exchange-offline" + "github.com/ipfs/go-ipld-format" + "github.com/ipfs/go-merkledag" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/lib/blockstore" - "github.com/filecoin-project/statediff" "github.com/filecoin-project/test-vectors/schema" "github.com/fatih/color" @@ -258,6 +262,23 @@ func assertMsgResult(t *testing.T, expected *schema.Receipt, actual *vm.ApplyRet } func dumpThreeWayStateDiff(t *testing.T, vector *schema.TestVector, bs blockstore.Blockstore, actual cid.Cid) { + // check if statediff exists; if not, skip. + if err := exec.Command("statediff", "--help").Run(); err != nil { + t.Log("could not dump 3-way state tree diff upon test failure: statediff command not found") + t.Log("install statediff with:") + t.Log("$ git clone https://github.com/filecoin-project/statediff.git") + t.Log("$ cd statediff") + t.Log("$ go generate ./...") + t.Log("$ go install ./cmd/statediff") + return + } + + tmpCar := writeStateToTempCAR(t, bs, + vector.Pre.StateTree.RootCID, + vector.Post.StateTree.RootCID, + actual, + ) + color.NoColor = false // enable colouring. t.Errorf("wrong post root cid; expected %v, but got %v", vector.Post.StateTree.RootCID, actual) @@ -269,6 +290,8 @@ func dumpThreeWayStateDiff(t *testing.T, vector *schema.TestVector, bs blockstor d1 = color.New(color.FgGreen, color.Bold).Sprint("[Δ1]") d2 = color.New(color.FgGreen, color.Bold).Sprint("[Δ2]") d3 = color.New(color.FgGreen, color.Bold).Sprint("[Δ3]") + + cmd *exec.Cmd ) bold := color.New(color.Bold).SprintfFunc() @@ -277,13 +300,52 @@ func dumpThreeWayStateDiff(t *testing.T, vector *schema.TestVector, bs blockstor t.Log(bold("=== dumping 3-way diffs between %s, %s, %s ===", a, b, c)) t.Log(bold("--- %s left: %s; right: %s ---", d1, a, b)) - t.Log(statediff.Diff(context.Background(), bs, vector.Post.StateTree.RootCID, actual)) + cmd = exec.Command("statediff", tmpCar, vector.Post.StateTree.RootCID.String(), actual.String()) + t.Log(cmd.CombinedOutput()) t.Log(bold("--- %s left: %s; right: %s ---", d2, c, b)) - t.Log(statediff.Diff(context.Background(), bs, vector.Pre.StateTree.RootCID, actual)) + cmd = exec.Command("statediff", tmpCar, vector.Pre.StateTree.RootCID.String(), actual.String()) + t.Log(cmd.CombinedOutput()) t.Log(bold("--- %s left: %s; right: %s ---", d3, c, a)) - t.Log(statediff.Diff(context.Background(), bs, vector.Pre.StateTree.RootCID, vector.Post.StateTree.RootCID)) + cmd = exec.Command("statediff", tmpCar, vector.Pre.StateTree.RootCID.String(), vector.Post.StateTree.RootCID.String()) + t.Log(cmd.CombinedOutput()) +} + +// writeStateToTempCAR writes the provided roots to a temporary CAR that'll be +// cleaned up via t.Cleanup(). It returns the full path of the temp file. +func writeStateToTempCAR(t *testing.T, bs blockstore.Blockstore, roots ...cid.Cid) string { + tmp, err := ioutil.TempFile("", "lotus-tests-*.car") + if err != nil { + t.Fatalf("failed to create temp file to dump CAR for diffing: %s", err) + } + // register a cleanup function to delete the CAR. + t.Cleanup(func() { + _ = os.Remove(tmp.Name()) + }) + + carWalkFn := func(nd format.Node) (out []*format.Link, err error) { + for _, link := range nd.Links() { + if link.Cid.Prefix().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed { + continue + } + out = append(out, link) + } + return out, nil + } + + var ( + offl = offline.Exchange(bs) + blkserv = blockservice.New(bs, offl) + dserv = merkledag.NewDAGService(blkserv) + ) + + err = car.WriteCarWithWalker(context.Background(), dserv, roots, tmp, carWalkFn) + if err != nil { + t.Fatalf("failed to dump CAR for diffing: %s", err) + } + _ = tmp.Close() + return tmp.Name() } func loadCAR(t *testing.T, vectorCAR schema.Base64EncodedBytes) blockstore.Blockstore { diff --git a/extern/test-vectors b/extern/test-vectors index 2c0739ecc..7d3becbeb 160000 --- a/extern/test-vectors +++ b/extern/test-vectors @@ -1 +1 @@ -Subproject commit 2c0739eccce6ea5703dcea2df564efcb6cf79fee +Subproject commit 7d3becbeb5b932baed419c43390595b5e5cece12 diff --git a/go.mod b/go.mod index c9a593af9..bc4067d67 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/BurntSushi/toml v0.3.1 github.com/GeertJohan/go.rice v1.0.0 github.com/Gurpartap/async v0.0.0-20180927173644-4f7f499dd9ee + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/coreos/go-systemd/v22 v22.0.0 @@ -39,10 +40,10 @@ require ( github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b github.com/filecoin-project/specs-actors v0.9.7 github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 - github.com/filecoin-project/statediff v0.0.1 - github.com/filecoin-project/test-vectors/schema v0.0.0-00010101000000-000000000000 + github.com/filecoin-project/test-vectors/schema v0.0.1 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 github.com/go-kit/kit v0.10.0 + github.com/go-ole/go-ole v1.2.4 // indirect github.com/google/uuid v1.1.1 github.com/gorilla/mux v1.7.4 github.com/gorilla/websocket v1.4.2 @@ -118,6 +119,7 @@ require ( github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 go.opencensus.io v0.22.4 + go.uber.org/dig v1.10.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/multierr v1.5.0 go.uber.org/zap v1.15.0 @@ -126,6 +128,7 @@ require ( golang.org/x/time v0.0.0-20191024005414-555d28b269f0 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 gotest.tools v2.2.0+incompatible + launchpad.net/gocheck v0.0.0-20140225173054-000000000087 // indirect ) replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v1.18.0 @@ -133,3 +136,5 @@ replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 + +replace github.com/filecoin-project/test-vectors => ./extern/test-vectors diff --git a/go.sum b/go.sum index d163f4db8..0fa13fe70 100644 --- a/go.sum +++ b/go.sum @@ -8,20 +8,14 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= contrib.go.opencensus.io/exporter/jaeger v0.1.0 h1:WNc9HbA38xEQmsI40Tjd/MNU/g8byN2Of7lwIjv0Jdc= contrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA= contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg= @@ -35,8 +29,6 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -160,7 +152,6 @@ github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= -github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -168,8 +159,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f h1:BOaYiTvg8p9vBUXpklC22XSK/mifLF7lG9jtmYYi3Tc= github.com/davidlazar/go-crypto v0.0.0-20190912175916-7055855a373f/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e h1:lj77EKYUpYXTd8CD/+QMIf8b6OIOTsfEBSXiAzuEHTU= github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e/go.mod h1:3ZQK6DMPSz/QZ73jlWxBtUhNA8xZx7LzUFSq/OfP8vk= github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= @@ -221,56 +210,34 @@ 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/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= -github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef h1:MtQRSnJLsQOOlmsd/Ua5KWXimpxcaa715h6FUh/eJPY= -github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef/go.mod h1:SMj5VK1pYgqC8FXVEtOBRTc+9AIrYu+C+K3tAXi2Rk8= -github.com/filecoin-project/chain-validation v0.0.6-0.20200907020853-f4e4e7417fea/go.mod h1:pKcH/ShsOvCpO2qnsGFzEJ0NMJdBenPRk4Uu/xpIEkY= -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.3 h1:eVfbdjEbpbzIrbiSa+PiGUY+oDK9HnUn+M1R/ggoHf8= github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= -github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= -github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= -github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 h1:K6t4Hrs+rwUxBz2xg88Bdqeh4k5/rycQFdPseZhRyfE= -github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161/go.mod h1:vgmwKBkx+ca5OIeEvstiQgzAZnb7R6QaqE1oEDSqa6g= -github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= -github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.3/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= -github.com/filecoin-project/go-bitfield v0.1.2/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-bitfield v0.2.0 h1:gCtLcjskIPtdg4NfN7gQZSQF9yrBQ7mkT0qCJxzGI2Q= github.com/filecoin-project/go-bitfield v0.2.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:av5fw6wmm58FYMgJeoB/lK9XXrgdugYiTqkdxjTy9k8= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= -github.com/filecoin-project/go-data-transfer v0.6.1/go.mod h1:uRYBRKVBVM12CSusBtVrzDHkVw/3DKZpkxKJVP1Ydas= github.com/filecoin-project/go-data-transfer v0.6.3 h1:7TLwm8nuodHYD/uiwJjKc/PGRR+LwqM8jmlZqgWuUfY= github.com/filecoin-project/go-data-transfer v0.6.3/go.mod h1:PmBKVXkhh67/tnEdJXQwDHl5mT+7Tbcwe1NPninqhnM= -github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= -github.com/filecoin-project/go-fil-markets v0.5.6-0.20200814234959-80b1788108ac/go.mod h1:umicPCaN99ysHTiYOmwhuLxTFbOwcsI+mdw/t96vvM4= -github.com/filecoin-project/go-fil-markets v0.5.10-0.20200907054005-9945d0d2141a/go.mod h1:w0wCAf/fT7UfvJAZEMjjCQfsbwvrdjU4sN4QFLWsPrk= github.com/filecoin-project/go-fil-markets v0.6.0 h1:gfxMweUHo4u+2BZh2Q7/7+cV0/ttikuJfhkkxLRsE2Q= github.com/filecoin-project/go-fil-markets v0.6.0/go.mod h1:LhSFYLkjaoe0vFRKABGYyw1Jz+9jCpF1sPA7yOftLTw= -github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200817153016-2ea5cbaf5ec0/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= github.com/filecoin-project/go-multistore v0.0.3/go.mod h1:kaNqCC4IhU4B1uyr7YWFHd23TL4KM32aChS0jNkyUvQ= -github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6/go.mod h1:0HgYnrkeSU4lu1p+LEOeDpFsNBssa0OGGriWdA4hvaE= github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 h1:+/4aUeUoKr6AKfPE3mBhXA5spIV6UcKdTYDPNU2Tdmg= github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak= -github.com/filecoin-project/go-paramfetch v0.0.1/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= -github.com/filecoin-project/go-paramfetch v0.0.2-0.20200218225740-47c639bab663/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 h1:A256QonvzRaknIIAuWhe/M2dpV2otzs3NBhi5TWa/UA= github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261/go.mod h1:fZzmf4tftbwf9S37XRifoJlz7nCjRdIrMGLR07dKLCc= github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df h1:m2esXSuGBkuXlRyCsl1a/7/FkFam63o1OzIgzaHtOfI= github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= -github.com/filecoin-project/go-statemachine v0.0.0-20200226041606-2074af6d51d9/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= @@ -278,31 +245,13 @@ github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIi github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= -github.com/filecoin-project/lotus v0.4.3-0.20200820203717-d1718369a182/go.mod h1:biFZPQ/YyQGfkHUmHMiaNf2hnD6zm1+OAXPQYQ61Zkg= -github.com/filecoin-project/lotus v0.5.11-0.20200907070510-420a8706da6d/go.mod h1:SVrkI6GQzqSeSuaZ6KsHih4Dh800q9HSFQCtBnyMYBI= -github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= -github.com/filecoin-project/sector-storage v0.0.0-20200730050024-3ee28c3b6d9a/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= -github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0/go.mod h1:oOawOl9Yk+qeytLzzIryjI8iRbqo+qzS6EEeElP4PWA= -github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= -github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= -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.8.2/go.mod h1:Q3ACV5kBLvqPaYbthc/J1lGMJ5OwogmD9pzdtPRMdCw= -github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU= -github.com/filecoin-project/specs-actors v0.9.2/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA= -github.com/filecoin-project/specs-actors v0.9.3/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA= github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4= -github.com/filecoin-project/specs-actors v0.9.6 h1:U3PU4jrHcmXxfEP0CC1fGETx4RrXlm5RYJeuT5eWjhI= -github.com/filecoin-project/specs-actors v0.9.6/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= github.com/filecoin-project/specs-actors v0.9.7 h1:7PAZ8kdqwBdmgf/23FCkQZLCXcVu02XJrkpkhBikiA8= github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= -github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= -github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= -github.com/filecoin-project/statediff v0.0.1 h1:lym6d5wNnzr+5Uc/6RRWx1hgwb+tCKn2mFIK0Eb1Q18= -github.com/filecoin-project/statediff v0.0.1/go.mod h1:qNWauolLFEzOiA4LNWermBRVNbaZHfPcPevumZeh+hE= -github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f/go.mod h1:1CGbd11KkHuyWPT+xwwCol1zl/jnlpiKD2L4fzKxaiI= +github.com/filecoin-project/test-vectors/schema v0.0.1 h1:5fNF76nl4qolEvcIsjc0kUADlTMVHO73tW4kXXPnsus= +github.com/filecoin-project/test-vectors/schema v0.0.1/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= @@ -321,7 +270,6 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclK github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= @@ -365,7 +313,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -373,7 +320,6 @@ github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -401,9 +347,7 @@ github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8v github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= @@ -422,7 +366,6 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -495,7 +438,6 @@ github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3 github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= -github.com/ipfs/go-bitswap v0.2.8/go.mod h1:2Yjog0GMdH8+AsxkE0DI9D2mANaUTxbVVav0pPoZoug= github.com/ipfs/go-bitswap v0.2.20 h1:Zfi5jDUoqxDThORUznqdeL77DdGniAzlccNJ4vr+Itc= github.com/ipfs/go-bitswap v0.2.20/go.mod h1:C7TwBgHnu89Q8sHsTJP7IhUqF9XYLe71P4tT5adgmYo= github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= @@ -550,15 +492,11 @@ github.com/ipfs/go-ds-measure v0.1.0 h1:vE4TyY4aeLeVgnnPBC5QzKIjKrqzha0NCujTfgvV github.com/ipfs/go-ds-measure v0.1.0/go.mod h1:1nDiFrhLlwArTME1Ees2XaBOl49OoCgd2A3f8EchMSY= github.com/ipfs/go-filestore v1.0.0 h1:QR7ekKH+q2AGiWDc7W2Q0qHuYSRZGUJqUn0GsegEPb0= github.com/ipfs/go-filestore v1.0.0/go.mod h1:/XOCuNtIe2f1YPbiXdYvD0BKLA0JR1MgPiFOdcuu9SM= -github.com/ipfs/go-fs-lock v0.0.1/go.mod h1:DNBekbboPKcxs1aukPSaOtFA3QfSdi5C855v0i9XJ8Y= github.com/ipfs/go-fs-lock v0.0.6 h1:sn3TWwNVQqSeNjlWy6zQ1uUGAZrV3hPOyEA6y1/N2a0= github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28L7zESmM= github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= -github.com/ipfs/go-graphsync v0.1.1/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= github.com/ipfs/go-graphsync v0.1.2 h1:25Ll9kIXCE+DY0dicvfS3KMw+U5sd01b/FJbA7KAbhg= github.com/ipfs/go-graphsync v0.1.2/go.mod h1:sLXVXm1OxtE2XYPw62MuXCdAuNwkAdsbnfrmos5odbA= -github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= -github.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg= github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk= github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= @@ -590,7 +528,6 @@ github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAz github.com/ipfs/go-ipfs-files v0.0.2/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= github.com/ipfs/go-ipfs-files v0.0.4/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= -github.com/ipfs/go-ipfs-files v0.0.7/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= github.com/ipfs/go-ipfs-files v0.0.8 h1:8o0oFJkJ8UkO/ABl8T6ac6tKF3+NIpj67aAB6ZpusRg= github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= github.com/ipfs/go-ipfs-flags v0.0.1/go.mod h1:RnXBb9WV53GSfTrSDVK61NLTFKvWc60n+K9EgCDh+rA= @@ -779,7 +716,6 @@ github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qD github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El8cTaefiM= github.com/libp2p/go-libp2p v0.9.2/go.mod h1:cunHNLDVus66Ct9iXXcjKRLdmHdFdHVe1TAnbubJQqQ= github.com/libp2p/go-libp2p v0.10.0/go.mod h1:yBJNpb+mGJdgrwbKAKrhPU0u3ogyNFTfjJ6bdM+Q/G8= -github.com/libp2p/go-libp2p v0.10.3/go.mod h1:0ER6iPSaPeQjryNgOnm9bLNpMJCYmuw54xJXsVR17eE= github.com/libp2p/go-libp2p v0.11.0 h1:jb5mqdqYEBAybTEhD8io43Cz5LzVKuWxOK7znSN69jE= github.com/libp2p/go-libp2p v0.11.0/go.mod h1:3/ogJDXsbbepEfqtZKBR/DedzxJXCeK17t2Z9RE9bEE= github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4= @@ -907,13 +843,10 @@ github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1 github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= -github.com/libp2p/go-libp2p-pubsub v0.3.5-0.20200820194335-bfc96c2cd081/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200901174250-06a12f17b7de/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb h1:0jm9ZSDkteX9XRjZqZwG5X0wuR+e0zAJ6ZEnqo2vcb0= github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= -github.com/libp2p/go-libp2p-quic-transport v0.7.1/go.mod h1:TD31to4E5exogR/GWHClXCfkktigjAl5rXSt7HoxNvY= github.com/libp2p/go-libp2p-quic-transport v0.8.0 h1:mHA94K2+TD0e9XtjWx/P5jGGZn0GdQ4OFYwNllagv4E= github.com/libp2p/go-libp2p-quic-transport v0.8.0/go.mod h1:F2FG/6Bzz0U6essUVxDzE0s9CrY4XGLbl7QEmDNvU7A= github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= @@ -1048,7 +981,6 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= github.com/lucas-clemente/quic-go v0.16.0/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= -github.com/lucas-clemente/quic-go v0.17.3/go.mod h1:I0+fcNTdb9eS1ZcjQZbDVPGchJ86chcIxPALn9lEJqE= github.com/lucas-clemente/quic-go v0.18.0 h1:JhQDdqxdwdmGdKsKgXi1+coHRoGhvU6z0rNzOJqZ/4o= github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg= github.com/lufia/iostat v1.1.0/go.mod h1:rEPNA0xXgjHQjuI5Cy05sLlS2oRcSlWHRLrvh/AQ+Pg= @@ -1073,10 +1005,8 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -1095,7 +1025,6 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= @@ -1378,9 +1307,8 @@ github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3 github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1431,13 +1359,11 @@ github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba/go.mod h1:CH github.com/whyrusleeping/cbor-gen v0.0.0-20191212224538-d370462a7e8a/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= github.com/whyrusleeping/cbor-gen v0.0.0-20191216205031-b047b6acb3c0/go.mod h1:xdlJQaiqipF0HW+Mzpg7XRM3fWbGvfgFlcppuvlkIvY= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= -github.com/whyrusleeping/cbor-gen v0.0.0-20200206220010-03c9665e2a66/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= -github.com/whyrusleeping/cbor-gen v0.0.0-20200723185710-6a3894a6352b/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20200814224545-656e08ce49ee h1:U7zWWvvAjT76EiuWPSOiZlQDnaQYPxPoxugTtTAcJK0= @@ -1464,12 +1390,7 @@ github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d/go.mod h1:g7c github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= github.com/whyrusleeping/yamux v1.1.5/go.mod h1:E8LnQQ8HKx5KD29HZFUwM1PxCOdPRzGwur1mcYhXcD8= -github.com/willscott/go-cmp v0.5.2-0.20200812183318-8affb9542345 h1:IJVAwIctqDFOrO0C2qzksXmANviyHJzrklU27e1ltzE= -github.com/willscott/go-cmp v0.5.2-0.20200812183318-8affb9542345/go.mod h1:D7hA8H5pyQx7Y5Em7IWx1R4vNJzfon3gpG9nxjkITjQ= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829 h1:wb7xrDzfkLgPHsSEBm+VSx6aDdi64VtV0xvP0E6j8bk= github.com/xlab/c-for-go v0.0.0-20200718154222-87b0065af829/go.mod h1:h/1PEBwj7Ym/8kOuMWvO2ujZ6Lt+TMbySEXNhjjR87I= @@ -1479,7 +1400,6 @@ github.com/xorcare/golden v0.6.0/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/ github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 h1:oWgZJmC1DorFZDpfMfWg7xk29yEOZiXmo/wZl+utTI8= github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542/go.mod h1:7T39/ZMvaSEZlBPoYfVFmsBLmUl3uz9IuzWj/U6FtvQ= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= @@ -1510,7 +1430,6 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY= go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/fx v1.9.0 h1:7OAz8ucp35AU8eydejpYG7QrbE8rLKzGhHbZlJi5LYY= @@ -1530,8 +1449,6 @@ go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -go4.org v0.0.0-20190218023631-ce4c26f7be8e/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -go4.org v0.0.0-20190313082347-94abd6928b1d/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= @@ -1556,15 +1473,11 @@ golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200427165652-729f1e841bcc/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1575,10 +1488,8 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd h1:zkO/Lhoka23X63N9OSzpSeROEUQ5ODw47tM3YWjygbs= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1590,15 +1501,13 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -1636,11 +1545,8 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200519113804-d87ec0cfa476/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -1698,13 +1604,11 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190902133755-9109b7679e13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1714,20 +1618,14 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200427175716-29b57079015a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y= @@ -1771,22 +1669,14 @@ golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200108195415-316d2f248479/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200318150045-ba25ddc85566/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200711155855-7342f9734a7d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3 h1:r3P/5xOq/dK1991B65Oy6E1fRF/2d/fSYZJ/fXGVfJc= golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1807,11 +1697,8 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0 h1:0q95w+VuFtv4PAx4PZVQdBMmYbaCHbnfKaEiDIcVyag= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.25.0 h1:LodzhlzZEUfhXzNUMIfVlf9Gr6Ua5MMtoFWh7+f47qA= -google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1837,12 +1724,7 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 h1:i+Aiej6cta/Frzp13/swvwz5O00kYcSe0A/C5Wd7zX8= @@ -1863,7 +1745,6 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200617041141-9a465503579e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -1915,9 +1796,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= From 2a3743ff840aeecbb98f542b486a1b0fbaeaab1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 9 Sep 2020 14:08:54 +0100 Subject: [PATCH 107/199] invoke the statediff command properly. --- conformance/runner_test.go | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/conformance/runner_test.go b/conformance/runner_test.go index ca7fdfc63..a57458dcb 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -194,8 +194,10 @@ func executeMessageVector(t *testing.T, vector *schema.TestVector) { // Once all messages are applied, assert that the final state root matches // the expected postcondition root. - if root != vector.Post.StateTree.RootCID { + if expected, actual := vector.Post.StateTree.RootCID, root; expected != actual { + t.Logf("actual state root CID doesn't match expected one; expected: %s, actual: %s", expected, actual) dumpThreeWayStateDiff(t, vector, bs, root) + t.FailNow() } } @@ -239,8 +241,10 @@ func executeTipsetVector(t *testing.T, vector *schema.TestVector) { // Once all messages are applied, assert that the final state root matches // the expected postcondition root. - if root != vector.Post.StateTree.RootCID { + if expected, actual := vector.Post.StateTree.RootCID, root; expected != actual { + t.Logf("actual state root CID doesn't match expected one; expected: %s, actual: %s", expected, actual) dumpThreeWayStateDiff(t, vector, bs, root) + t.FailNow() } } @@ -290,26 +294,30 @@ func dumpThreeWayStateDiff(t *testing.T, vector *schema.TestVector, bs blockstor d1 = color.New(color.FgGreen, color.Bold).Sprint("[Δ1]") d2 = color.New(color.FgGreen, color.Bold).Sprint("[Δ2]") d3 = color.New(color.FgGreen, color.Bold).Sprint("[Δ3]") - - cmd *exec.Cmd ) + printDiff := func(left, right cid.Cid) { + cmd := exec.Command("statediff", "car", "--file", tmpCar, left.String(), right.String()) + b, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("statediff failed: %s", err) + } + t.Log(string(b)) + } + bold := color.New(color.Bold).SprintfFunc() // run state diffs. t.Log(bold("=== dumping 3-way diffs between %s, %s, %s ===", a, b, c)) t.Log(bold("--- %s left: %s; right: %s ---", d1, a, b)) - cmd = exec.Command("statediff", tmpCar, vector.Post.StateTree.RootCID.String(), actual.String()) - t.Log(cmd.CombinedOutput()) + printDiff(vector.Post.StateTree.RootCID, actual) t.Log(bold("--- %s left: %s; right: %s ---", d2, c, b)) - cmd = exec.Command("statediff", tmpCar, vector.Pre.StateTree.RootCID.String(), actual.String()) - t.Log(cmd.CombinedOutput()) + printDiff(vector.Pre.StateTree.RootCID, actual) t.Log(bold("--- %s left: %s; right: %s ---", d3, c, a)) - cmd = exec.Command("statediff", tmpCar, vector.Pre.StateTree.RootCID.String(), vector.Post.StateTree.RootCID.String()) - t.Log(cmd.CombinedOutput()) + printDiff(vector.Pre.StateTree.RootCID, vector.Post.StateTree.RootCID) } // writeStateToTempCAR writes the provided roots to a temporary CAR that'll be From b3dedfedc05a3b1b2ffeb072c288dbc79f4ff8c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 9 Sep 2020 14:20:11 +0100 Subject: [PATCH 108/199] ci: remove unnecessary go get. --- .circleci/config.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index bf4149bac..b7e72bf4a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -225,9 +225,6 @@ jobs: cd extern/test-vectors git fetch git checkout origin/<< parameters.vectors-branch >> - - run: - name: go get vectors branch - command: go get github.com/filecoin-project/test-vectors@<< parameters.vectors-branch >> - go/install-gotestsum: gobin: $HOME/.local/bin version: 0.5.2 From 6d2b4ab775455ffa67e5012eb58d49b45d6054ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 9 Sep 2020 14:28:56 +0100 Subject: [PATCH 109/199] fix lint. --- conformance/chaos/actor.go | 3 ++- conformance/runner_test.go | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index f10c135e0..ed7a230c7 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -8,7 +8,8 @@ import ( "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" - "github.com/whyrusleeping/cbor-gen" + + typegen "github.com/whyrusleeping/cbor-gen" ) //go:generate go run ./gen diff --git a/conformance/runner_test.go b/conformance/runner_test.go index a57458dcb..cc7ef6b3d 100644 --- a/conformance/runner_test.go +++ b/conformance/runner_test.go @@ -20,8 +20,8 @@ import ( "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" - "github.com/ipfs/go-ipfs-exchange-offline" - "github.com/ipfs/go-ipld-format" + offline "github.com/ipfs/go-ipfs-exchange-offline" + format "github.com/ipfs/go-ipld-format" "github.com/ipfs/go-merkledag" "github.com/filecoin-project/lotus/chain/types" From ef2303bc5d0bf7309aadf561af91bf8c36bdec47 Mon Sep 17 00:00:00 2001 From: Dirk McCormick Date: Wed, 9 Sep 2020 15:37:34 +0200 Subject: [PATCH 110/199] docs: add docs on how to use paych status --- documentation/en/payment-channels.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/documentation/en/payment-channels.md b/documentation/en/payment-channels.md index 7179da916..afddcdc40 100644 --- a/documentation/en/payment-channels.md +++ b/documentation/en/payment-channels.md @@ -84,3 +84,28 @@ Once the settlement period is over, either the client or provider can call colle ```sh $ lotus paych collect ``` + +Check the status of a channel that is still being created using `lotus paych status-by-from-to`. + +```sh +$ lotus paych status-by-from-to +Creating channel + From: t3sb6xzvs6rhlziatagevxpp3dwapdolurtkpn4kyh3kgoo4tn5o7lutjqlsnvpceztlhxu3lzzfe34rvpsjgq + To: t1zip4sblhyrn4oxygzsm6nafbsynp2avmk3xafea + Pending Amt: 10000 + Wait Sentinel: bafy2bzacedk2jidsyxcynusted35t5ipkhu2kpiodtwyjr3pimrhke6f5pqbm +``` + +Check the status of a channel that has been created using `lotus paych status`. + +```sh +$ lotus paych status +Channel exists + Channel: t2nydpzhmeqkmid5smtqnowlr2mr5az6rexpmyv6i + From: t3sb6xzvs6rhlziatagevxpp3dwapdolurtkpn4kyh3kgoo4tn5o7lutjqlsnvpceztlhxu3lzzfe34rvpsjgq + To: t1zip4sblhyrn4oxygzsm6nafbsynp2avmk3xafea + Confirmed Amt: 10000 + Pending Amt: 6000 + Queued Amt: 3000 + Voucher Redeemed Amt: 2000 +``` From 333c7ce1c9ba29ec12e15aa6d457401c9bc1eb3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Wed, 9 Sep 2020 14:39:53 +0100 Subject: [PATCH 111/199] initial CODEOWNERS. --- .github/CODEOWNERS | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..3cba4641b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,15 @@ +## filecoin-project/lotus CODEOWNERS +## Refer to https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners. +## +## These users or groups will be automatically assigned as reviewers every time +## a PR is submitted that modifies code in the specified locations. +## +## The Lotus repo configuration requires that at least ONE codeowner approves +## the PR before merging. + +### Global owners. +* @magik6k @whyrusleeping + +### Conformance testing. +conformance/ @raulk +extern/test-vectors @raulk From fe7c152c9723ef2818adfc99fe9612340718aa43 Mon Sep 17 00:00:00 2001 From: Mosh <1306020+mishmosh@users.noreply.github.com> Date: Wed, 9 Sep 2020 12:24:33 -0400 Subject: [PATCH 112/199] typo fix in error message --- markets/storageadapter/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 5251b1cd3..4f7361d00 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -161,7 +161,7 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor pubmsg, err := c.cs.GetMessage(*deal.PublishMessage) if err != nil { - return 0, xerrors.Errorf("getting deal pubsish message: %w", err) + return 0, xerrors.Errorf("getting deal publish message: %w", err) } mi, err := stmgr.StateMinerInfo(ctx, c.sm, c.cs.GetHeaviestTipSet(), deal.Proposal.Provider) From e9b85f5acb834272ca223c3d93306f9ed83b88b7 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 9 Sep 2020 10:23:41 -0700 Subject: [PATCH 113/199] ensure replaced message can properly RBF --- chain/messagepool/messagepool.go | 10 +++++++--- cli/mpool.go | 6 +++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 09b888101..64add44d7 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -11,6 +11,7 @@ import ( "sync" "time" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" @@ -154,6 +155,11 @@ func newMsgSet(nonce uint64) *msgSet { } } +func ComputeMinRBF(curPrem abi.TokenAmount) abi.TokenAmount { + minPrice := types.BigAdd(curPrem, types.BigDiv(types.BigMul(curPrem, rbfNumBig), rbfDenomBig)) + return types.BigAdd(minPrice, types.NewInt(1)) +} + func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (bool, error) { nextNonce := ms.nextNonce nonceGap := false @@ -181,9 +187,7 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (boo if m.Cid() != exms.Cid() { // check if RBF passes - minPrice := exms.Message.GasPremium - minPrice = types.BigAdd(minPrice, types.BigDiv(types.BigMul(minPrice, rbfNumBig), rbfDenomBig)) - minPrice = types.BigAdd(minPrice, types.NewInt(1)) + minPrice := ComputeMinRBF(exms.Message.GasPremium) if types.BigCmp(m.Message.GasPremium, minPrice) >= 0 { log.Infow("add with RBF", "oldpremium", exms.Message.GasPremium, "newpremium", m.Message.GasPremium, "addr", m.Message.From, "nonce", m.Message.Nonce) diff --git a/cli/mpool.go b/cli/mpool.go index cebbe1a95..6561e2cbc 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -11,8 +11,10 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/types" ) @@ -356,7 +358,9 @@ var mpoolReplaceCmd = &cli.Command{ return fmt.Errorf("failed to estimate gas values: %w", err) } msg.GasFeeCap = retm.GasFeeCap - msg.GasPremium = retm.GasPremium + + minRBF := messagepool.ComputeMinRBF(msg.GasPremium) + msg.GasPremium = big.Max(retm.GasPremium, minRBF) } else { msg.GasLimit = cctx.Int64("gas-limit") msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium")) From 97cbfa11b75673c11b53f02c985a5ca5ed01e332 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 9 Sep 2020 20:45:24 +0300 Subject: [PATCH 114/199] fix nasty bug in optimal selection the sort has to account for negative gasPerf and be stable; go figure. --- chain/messagepool/selection.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index b9bbdf304..8bb32eb1d 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -199,9 +199,11 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64 gasLimit -= chainGasLimit // resort to account for already merged chains and effective performance adjustments - sort.Slice(chains[i+1:], func(i, j int) bool { + // the sort *must* be stable or we end up getting negative gasPerfs pushed up. + sort.SliceStable(chains[i+1:], func(i, j int) bool { return chains[i].BeforeEffective(chains[j]) }) + continue } @@ -912,7 +914,9 @@ func (mc *msgChain) SetNullEffectivePerf() { func (mc *msgChain) BeforeEffective(other *msgChain) bool { // move merged chains to the front so we can discard them earlier - return (mc.merged && !other.merged) || mc.effPerf > other.effPerf || + return (mc.merged && !other.merged) || + (mc.gasPerf >= 0 && other.gasPerf < 0) || + mc.effPerf > other.effPerf || (mc.effPerf == other.effPerf && mc.gasPerf > other.gasPerf) || (mc.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0) } From cf515bc5ca224701f4e535f507d9560aa8373797 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 9 Sep 2020 20:46:26 +0300 Subject: [PATCH 115/199] add selection test with real world messages dumped from a live node mpool --- chain/messagepool/messagepool_test.go | 8 ++ chain/messagepool/selection_test.go | 179 ++++++++++++++++++++++++ chain/messagepool/test-messages.json.gz | Bin 0 -> 206325 bytes 3 files changed, 187 insertions(+) create mode 100644 chain/messagepool/test-messages.json.gz diff --git a/chain/messagepool/messagepool_test.go b/chain/messagepool/messagepool_test.go index 25a30ff66..a4aa059ca 100644 --- a/chain/messagepool/messagepool_test.go +++ b/chain/messagepool/messagepool_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/lotus/chain/messagepool/gasguess" "github.com/filecoin-project/lotus/chain/types" @@ -56,6 +57,13 @@ func (tma *testMpoolAPI) nextBlock() *types.BlockHeader { return newBlk } +func (tma *testMpoolAPI) nextBlockWithHeight(height uint64) *types.BlockHeader { + newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1) + newBlk.Height = abi.ChainEpoch(height) + tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk)) + return newBlk +} + func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) { t.Helper() if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil { diff --git a/chain/messagepool/selection_test.go b/chain/messagepool/selection_test.go index 489a41eab..5e372fc85 100644 --- a/chain/messagepool/selection_test.go +++ b/chain/messagepool/selection_test.go @@ -1,11 +1,16 @@ package messagepool import ( + "compress/gzip" "context" + "encoding/json" "fmt" + "io" "math" "math/big" "math/rand" + "os" + "sort" "testing" "github.com/filecoin-project/go-address" @@ -1281,3 +1286,177 @@ func TestGasReward(t *testing.T) { }) } } + +func TestRealWorldSelection(t *testing.T) { + // load test-messages.json.gz and rewrite the messages so that + // 1) we map each real actor to a test actor so that we can sign the messages + // 2) adjust the nonces so that they start from 0 + file, err := os.Open("test-messages.json.gz") + if err != nil { + t.Fatal(err) + } + + gzr, err := gzip.NewReader(file) + if err != nil { + t.Fatal(err) + } + + dec := json.NewDecoder(gzr) + + var msgs []*types.SignedMessage + baseNonces := make(map[address.Address]uint64) + +readLoop: + for { + m := new(types.SignedMessage) + err := dec.Decode(m) + switch err { + case nil: + msgs = append(msgs, m) + nonce, ok := baseNonces[m.Message.From] + if !ok || m.Message.Nonce < nonce { + baseNonces[m.Message.From] = m.Message.Nonce + } + + case io.EOF: + break readLoop + + default: + t.Fatal(err) + } + } + + actorMap := make(map[address.Address]address.Address) + actorWallets := make(map[address.Address]*wallet.Wallet) + + for _, m := range msgs { + baseNonce := baseNonces[m.Message.From] + + localActor, ok := actorMap[m.Message.From] + if !ok { + w, err := wallet.NewWallet(wallet.NewMemKeyStore()) + if err != nil { + t.Fatal(err) + } + + a, err := w.GenerateKey(crypto.SigTypeSecp256k1) + if err != nil { + t.Fatal(err) + } + + actorMap[m.Message.From] = a + actorWallets[a] = w + localActor = a + } + + w, ok := actorWallets[localActor] + if !ok { + t.Fatalf("failed to lookup wallet for actor %s", localActor) + } + + m.Message.From = localActor + m.Message.Nonce -= baseNonce + + sig, err := w.Sign(context.TODO(), localActor, m.Message.Cid().Bytes()) + if err != nil { + t.Fatal(err) + } + + m.Signature = *sig + } + + mp, tma := makeTestMpool() + + block := tma.nextBlockWithHeight(build.UpgradeBreezeHeight + 10) + ts := mock.TipSet(block) + tma.applyBlock(t, block) + + for _, a := range actorMap { + tma.setBalance(a, 1000000) + } + + tma.baseFee = types.NewInt(800_000_000) + + sort.Slice(msgs, func(i, j int) bool { + return msgs[i].Message.Nonce < msgs[j].Message.Nonce + }) + + // add the messages + for _, m := range msgs { + mustAdd(t, mp, m) + } + + // do message selection and check block packing + minGasLimit := int64(0.9 * float64(build.BlockGasLimit)) + + // greedy first + selected, err := mp.SelectMessages(ts, 1.0) + if err != nil { + t.Fatal(err) + } + + gasLimit := int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=1.0; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // high quality ticket + selected, err = mp.SelectMessages(ts, .8) + if err != nil { + t.Fatal(err) + } + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.8; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // mid quality ticket + selected, err = mp.SelectMessages(ts, .4) + if err != nil { + t.Fatal(err) + } + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.4; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // low quality ticket + selected, err = mp.SelectMessages(ts, .1) + if err != nil { + t.Fatal(err) + } + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.1; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // very low quality ticket + selected, err = mp.SelectMessages(ts, .01) + if err != nil { + t.Fatal(err) + } + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.01; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + +} diff --git a/chain/messagepool/test-messages.json.gz b/chain/messagepool/test-messages.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..09481e1f88c651faa3a5609470cacf05d2b25699 GIT binary patch literal 206325 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

(fvO%4+CPM2ZqzCiZE^e!0a`E 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

F?s(-!Y5t=_HIg0g=IR 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 Date: Wed, 9 Sep 2020 11:23:48 -0700 Subject: [PATCH 116/199] add basic command for printing gas performance of messages in the mempool --- cli/mpool.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/cli/mpool.go b/cli/mpool.go index 6561e2cbc..add3af7bd 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -29,6 +29,7 @@ var mpoolCmd = &cli.Command{ mpoolReplaceCmd, mpoolFindCmd, mpoolConfig, + mpoolGasPerfCmd, }, } @@ -516,3 +517,65 @@ var mpoolConfig = &cli.Command{ return nil }, } + +var mpoolGasPerfCmd = &cli.Command{ + Name: "gas-perf", + Usage: "Check gas performance of messages in mempool", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "all", + Usage: "print gas performance for all mempool messages (default only prints for local)", + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + msgs, err := api.MpoolPending(ctx, types.EmptyTSK) + if err != nil { + return err + } + + var filter map[address.Address]struct{} + if !cctx.Bool("all") { + filter = map[address.Address]struct{}{} + + addrss, err := api.WalletList(ctx) + if err != nil { + return xerrors.Errorf("getting local addresses: %w", err) + } + + for _, a := range addrss { + filter[a] = struct{}{} + } + + var filtered []*types.SignedMessage + for _, msg := range msgs { + if _, has := filter[msg.Message.From]; !has { + continue + } + filtered = append(filtered, msg) + } + msgs = filtered + } + + ts, err := api.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("failed to get chain head: %w", err) + } + + baseFee := ts.Blocks()[0].ParentBaseFee + for _, m := range msgs { + feeCapSlack := types.BigSub(m.Message.GasFeeCap, baseFee) + + fmt.Printf("%s\t%d\t%s\n", m.Message.From, m.Message.Nonce, feeCapSlack) + } + + return nil + }, +} From 35aa78dad98488008c3f0bbc36f90a0de32dece1 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 01:14:01 -0400 Subject: [PATCH 117/199] Allow marking a certain tipset as checkpointed --- api/api_full.go | 3 ++ api/apistruct/struct.go | 5 +++ chain/checkpoint.go | 81 +++++++++++++++++++++++++++++++++++++++++ chain/sync.go | 44 ++++++++++++++++++++-- node/impl/full/sync.go | 5 +++ node/modules/chain.go | 4 +- 6 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 chain/checkpoint.go diff --git a/api/api_full.go b/api/api_full.go index 9d1d7ab63..7a477a874 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -157,6 +157,9 @@ type FullNode interface { // yet synced block headers. SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHeader, error) + // SyncCheckpoint marks a blocks as checkpointed, meaning that it won't ever fork away from it. + SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error + // SyncMarkBad marks a blocks as bad, meaning that it won't ever by synced. // Use with extreme caution. SyncMarkBad(ctx context.Context, bcid cid.Cid) error diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 3cf9a0add..bfd99ab0f 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -105,6 +105,7 @@ type FullNodeStruct struct { SyncState func(context.Context) (*api.SyncState, error) `perm:"read"` SyncSubmitBlock func(ctx context.Context, blk *types.BlockMsg) error `perm:"write"` SyncIncomingBlocks func(ctx context.Context) (<-chan *types.BlockHeader, error) `perm:"read"` + SyncCheckpoint func(ctx context.Context, key types.TipSetKey) error `perm:"admin"` SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"` SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"` @@ -704,6 +705,10 @@ func (c *FullNodeStruct) SyncIncomingBlocks(ctx context.Context) (<-chan *types. return c.Internal.SyncIncomingBlocks(ctx) } +func (c *FullNodeStruct) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error { + return c.Internal.SyncCheckpoint(ctx, tsk) +} + func (c *FullNodeStruct) SyncMarkBad(ctx context.Context, bcid cid.Cid) error { return c.Internal.SyncMarkBad(ctx, bcid) } diff --git a/chain/checkpoint.go b/chain/checkpoint.go new file mode 100644 index 000000000..8f99d73e4 --- /dev/null +++ b/chain/checkpoint.go @@ -0,0 +1,81 @@ +package chain + +import ( + "encoding/json" + + "github.com/filecoin-project/lotus/chain/types" + + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/ipfs/go-datastore" + "golang.org/x/xerrors" +) + +var CheckpointKey = datastore.NewKey("/chain/checks") + +func loadCheckpoint(ds dtypes.MetadataDS) (types.TipSetKey, error) { + haveChks, err := ds.Has(CheckpointKey) + if err != nil { + return types.EmptyTSK, err + } + + if !haveChks { + return types.EmptyTSK, nil + } + + tskBytes, err := ds.Get(CheckpointKey) + if err != nil { + return types.EmptyTSK, err + } + + var tsk types.TipSetKey + err = json.Unmarshal(tskBytes, &tsk) + if err != nil { + return types.EmptyTSK, err + } + + return tsk, err +} + +func (syncer *Syncer) SetCheckpoint(tsk types.TipSetKey) error { + if tsk == types.EmptyTSK { + return xerrors.Errorf("called with empty tsk") + } + + syncer.checkptLk.Lock() + defer syncer.checkptLk.Unlock() + + ts, err := syncer.ChainStore().LoadTipSet(tsk) + if err != nil { + return xerrors.Errorf("cannot find tipset: %w", err) + } + + hts := syncer.ChainStore().GetHeaviestTipSet() + anc, err := syncer.ChainStore().IsAncestorOf(ts, hts) + if err != nil { + return xerrors.Errorf("cannot determine whether checkpoint tipset is in main-chain: %w", err) + } + + if !hts.Equals(ts) && !anc { + return xerrors.Errorf("cannot mark tipset as checkpoint, since it isn't in the main-chain: %w", err) + } + + tskBytes, err := json.Marshal(tsk) + if err != nil { + return err + } + + err = syncer.ds.Put(CheckpointKey, tskBytes) + if err != nil { + return err + } + + syncer.checkpt = tsk + + return nil +} + +func (syncer *Syncer) GetCheckpoint() types.TipSetKey { + syncer.checkptLk.Lock() + defer syncer.checkptLk.Unlock() + return syncer.checkpt +} diff --git a/chain/sync.go b/chain/sync.go index d2cf08b92..47c8c55c9 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -9,8 +9,11 @@ import ( "sort" "strconv" "strings" + "sync" "time" + "github.com/filecoin-project/lotus/node/modules/dtypes" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/Gurpartap/async" @@ -129,10 +132,16 @@ type Syncer struct { windowSize int tickerCtxCancel context.CancelFunc + + checkptLk sync.Mutex + + checkpt types.TipSetKey + + ds dtypes.MetadataDS } // NewSyncer creates a new Syncer object. -func NewSyncer(sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) { +func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) { gen, err := sm.ChainStore().GetGenesis() if err != nil { return nil, xerrors.Errorf("getting genesis block: %w", err) @@ -143,7 +152,14 @@ func NewSyncer(sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr return nil, err } + cp, err := loadCheckpoint(ds) + if err != nil { + return nil, xerrors.Errorf("error loading mpool config: %w", err) + } + s := &Syncer{ + ds: ds, + checkpt: cp, beacon: beacon, bad: NewBadBlockCache(), Genesis: gent, @@ -1361,7 +1377,7 @@ loop: log.Warnf("(fork detected) synced header chain (%s - %d) does not link to our best block (%s - %d)", incoming.Cids(), incoming.Height(), known.Cids(), known.Height()) fork, err := syncer.syncFork(ctx, base, known) if err != nil { - if xerrors.Is(err, ErrForkTooLong) { + if xerrors.Is(err, ErrForkTooLong) || xerrors.Is(err, ErrForkCheckpoint) { // TODO: we're marking this block bad in the same way that we mark invalid blocks bad. Maybe distinguish? log.Warn("adding forked chain to our bad tipset cache") for _, b := range incoming.Blocks() { @@ -1377,14 +1393,17 @@ loop: } var ErrForkTooLong = fmt.Errorf("fork longer than threshold") +var ErrForkCheckpoint = fmt.Errorf("fork would require us to diverge from checkpointed block") // syncFork tries to obtain the chain fragment that links a fork into a common // ancestor in our view of the chain. // -// If the fork is too long (build.ForkLengthThreshold), we add the entire subchain to the -// denylist. Else, we find the common ancestor, and add the missing chain +// If the fork is too long (build.ForkLengthThreshold), or would cause us to diverge from the checkpoint (ErrForkCheckpoint), +// we add the entire subchain to the denylist. Else, we find the common ancestor, and add the missing chain // fragment until the fork point to the returned []TipSet. func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, known *types.TipSet) ([]*types.TipSet, error) { + // TODO: Does this mean we always ask for ForkLengthThreshold blocks from the network, even if we just need, like, 2? + // Would it not be better to ask in smaller chunks, given that an ~ForkLengthThreshold is very rare? tips, err := syncer.Exchange.GetBlocks(ctx, incoming.Parents(), int(build.ForkLengthThreshold)) if err != nil { return nil, err @@ -1404,6 +1423,22 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know } if nts.Equals(tips[cur]) { + // We've identified the ancestor + // Still need to make sure this wouldn't cause us to fork away from the checkpointed tipset + + chkpt := syncer.GetCheckpoint() + + if chkpt != types.EmptyTSK { + chkTs, err := syncer.ChainStore().LoadTipSet(chkpt) + if err != nil { + return nil, xerrors.Errorf("failed to retrieve checkpoint tipset: %w", err) + } + + if chkTs.Height() > nts.Height() { + return nil, ErrForkCheckpoint + } + } + return tips[:cur+1], nil } @@ -1416,6 +1451,7 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know } } } + return nil, ErrForkTooLong } diff --git a/node/impl/full/sync.go b/node/impl/full/sync.go index 9066df56f..9fe73220e 100644 --- a/node/impl/full/sync.go +++ b/node/impl/full/sync.go @@ -97,6 +97,11 @@ func (a *SyncAPI) SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHe return a.Syncer.IncomingBlocks(ctx) } +func (a *SyncAPI) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error { + log.Warnf("Marking tipset %s as bad", tsk) + return a.Syncer.SetCheckpoint(tsk) +} + func (a *SyncAPI) SyncMarkBad(ctx context.Context, bcid cid.Cid) error { log.Warnf("Marking block %s as bad", bcid) a.Syncer.MarkBad(bcid) diff --git a/node/modules/chain.go b/node/modules/chain.go index 1f398d0d8..cc86156b6 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -163,8 +163,8 @@ func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, return netName, err } -func NewSyncer(lc fx.Lifecycle, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { - syncer, err := chain.NewSyncer(sm, exchange, h.ConnManager(), h.ID(), beacon, verifier) +func NewSyncer(lc fx.Lifecycle, ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { + syncer, err := chain.NewSyncer(ds, sm, exchange, h.ConnManager(), h.ID(), beacon, verifier) if err != nil { return nil, err } From 5e3c178b9ef2b0ec38d6f9ed3c84af0a678ec605 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 03:12:04 -0400 Subject: [PATCH 118/199] Add a sync test for checkpointed tipsets --- chain/sync_test.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/chain/sync_test.go b/chain/sync_test.go index f91929a02..92873118a 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -333,6 +333,36 @@ func (tu *syncTestUtil) compareSourceState(with int) { } } +func (tu *syncTestUtil) assertBad(node int, ts *types.TipSet) { + for _, blk := range ts.Cids() { + rsn, err := tu.nds[node].SyncCheckBad(context.TODO(), blk) + require.NoError(tu.t, err) + require.True(tu.t, len(rsn) != 0) + } +} + +func (tu *syncTestUtil) getHead(node int) *types.TipSet { + ts, err := tu.nds[node].ChainHead(context.TODO()) + require.NoError(tu.t, err) + return ts +} + +func (tu *syncTestUtil) checkpointTs(node int, tsk types.TipSetKey) { + require.NoError(tu.t, tu.nds[node].SyncCheckpoint(context.TODO(), tsk)) +} + +func (tu *syncTestUtil) waitUntilNodeHasTs(node int, tsk types.TipSetKey) { + for { + _, err := tu.nds[node].ChainGetTipSet(context.TODO(), tsk) + if err != nil { + break + } + } + + // Time to allow for syncing and validation + time.Sleep(2 * time.Second) +} + func (tu *syncTestUtil) waitUntilSync(from, to int) { target, err := tu.nds[from].ChainHead(tu.ctx) if err != nil { @@ -678,3 +708,45 @@ func TestSyncInputs(t *testing.T) { t.Fatal("should error on block with nil election proof") } } + +func TestSyncCheckpoint(t *testing.T) { + H := 10 + tu := prepSyncTest(t, H) + + p1 := tu.addClientNode() + p2 := tu.addClientNode() + + fmt.Println("GENESIS: ", tu.g.Genesis().Cid()) + tu.loadChainToNode(p1) + tu.loadChainToNode(p2) + + base := tu.g.CurTipset + fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height()) + + // The two nodes fork at this point into 'a' and 'b' + a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil) + a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil) + a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil) + + tu.waitUntilSyncTarget(p1, a.TipSet()) + tu.checkpointTs(p1, a.TipSet().Key()) + + require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) + // chain B will now be heaviest + b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + + fmt.Println("A: ", a.Cids(), a.TipSet().Height()) + fmt.Println("B: ", b.Cids(), b.TipSet().Height()) + + // Now for the fun part!! p1 should mark p2's head as BAD. + + require.NoError(t, tu.mn.LinkAll()) + tu.connect(p1, p2) + tu.waitUntilNodeHasTs(p1, b.TipSet().Key()) + p1Head := tu.getHead(p1) + require.Equal(tu.t, p1Head, a.TipSet()) + tu.assertBad(p1, b.TipSet()) +} From 7d2118cd97d561a429441d5d6586c05c6e7a2b8c Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 03:12:18 -0400 Subject: [PATCH 119/199] Fix a typo that's totally related to this PR --- documentation/en/architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/en/architecture.md b/documentation/en/architecture.md index 619e04f05..ca4789fa0 100644 --- a/documentation/en/architecture.md +++ b/documentation/en/architecture.md @@ -259,7 +259,7 @@ When we launch a Lotus node with the command `./lotus daemon` (see [here](https://github.com/filecoin-project/lotus/blob/master/cmd/lotus/daemon.go) for more), the node is created through [dependency injection](https://godoc.org/go.uber.org/fx). This relies on reflection, which makes some of the references hard to follow. -The node sets up all of the subsystems it needs to run, such as the repository, the network connections, thechain sync +The node sets up all of the subsystems it needs to run, such as the repository, the network connections, the chain sync service, etc. This setup is orchestrated through calls to the `node.Override` function. The structure of each call indicates the type of component it will set up From 5c852e26c2846c5bc67fc9d532b13f831ac1774f Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 03:24:09 -0400 Subject: [PATCH 120/199] Add a SyncUnmarkBad API --- api/api_full.go | 3 +++ api/apistruct/struct.go | 5 +++++ chain/badtscache.go | 4 ++++ chain/sync.go | 5 +++++ node/impl/full/sync.go | 6 ++++++ 5 files changed, 23 insertions(+) diff --git a/api/api_full.go b/api/api_full.go index 7a477a874..034e8f996 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -164,6 +164,9 @@ type FullNode interface { // Use with extreme caution. SyncMarkBad(ctx context.Context, bcid cid.Cid) error + // SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again. + SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error + // SyncCheckBad checks if a block was marked as bad, and if it was, returns // the reason. SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index bfd99ab0f..6361e60b3 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -107,6 +107,7 @@ type FullNodeStruct struct { SyncIncomingBlocks func(ctx context.Context) (<-chan *types.BlockHeader, error) `perm:"read"` SyncCheckpoint func(ctx context.Context, key types.TipSetKey) error `perm:"admin"` SyncMarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"` + SyncUnmarkBad func(ctx context.Context, bcid cid.Cid) error `perm:"admin"` SyncCheckBad func(ctx context.Context, bcid cid.Cid) (string, error) `perm:"read"` MpoolGetConfig func(context.Context) (*types.MpoolConfig, error) `perm:"read"` @@ -713,6 +714,10 @@ func (c *FullNodeStruct) SyncMarkBad(ctx context.Context, bcid cid.Cid) error { return c.Internal.SyncMarkBad(ctx, bcid) } +func (c *FullNodeStruct) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error { + return c.Internal.SyncUnmarkBad(ctx, bcid) +} + func (c *FullNodeStruct) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) { return c.Internal.SyncCheckBad(ctx, bcid) } diff --git a/chain/badtscache.go b/chain/badtscache.go index 103237307..3c5bf05ef 100644 --- a/chain/badtscache.go +++ b/chain/badtscache.go @@ -56,6 +56,10 @@ func (bts *BadBlockCache) Add(c cid.Cid, bbr BadBlockReason) { bts.badBlocks.Add(c, bbr) } +func (bts *BadBlockCache) Remove(c cid.Cid) { + bts.badBlocks.Remove(c) +} + func (bts *BadBlockCache) Has(c cid.Cid) (BadBlockReason, bool) { rval, ok := bts.badBlocks.Get(c) if !ok { diff --git a/chain/sync.go b/chain/sync.go index 47c8c55c9..ccc97e12f 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -1680,6 +1680,11 @@ func (syncer *Syncer) MarkBad(blk cid.Cid) { syncer.bad.Add(blk, NewBadBlockReason([]cid.Cid{blk}, "manually marked bad")) } +// UnmarkBad manually adds a block to the "bad blocks" cache. +func (syncer *Syncer) UnmarkBad(blk cid.Cid) { + syncer.bad.Remove(blk) +} + func (syncer *Syncer) CheckBadBlockCache(blk cid.Cid) (string, bool) { bbr, ok := syncer.bad.Has(blk) return bbr.String(), ok diff --git a/node/impl/full/sync.go b/node/impl/full/sync.go index 9fe73220e..7f7fd48be 100644 --- a/node/impl/full/sync.go +++ b/node/impl/full/sync.go @@ -108,6 +108,12 @@ func (a *SyncAPI) SyncMarkBad(ctx context.Context, bcid cid.Cid) error { return nil } +func (a *SyncAPI) SyncUnmarkBad(ctx context.Context, bcid cid.Cid) error { + log.Warnf("Unmarking block %s as bad", bcid) + a.Syncer.UnmarkBad(bcid) + return nil +} + func (a *SyncAPI) SyncCheckBad(ctx context.Context, bcid cid.Cid) (string, error) { reason, ok := a.Syncer.CheckBadBlockCache(bcid) if !ok { From 93a0052219465b812e01bfde6393a53c47661d5a Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 03:25:19 -0400 Subject: [PATCH 121/199] Add a SyncUnmarkBad CLI --- cli/sync.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/cli/sync.go b/cli/sync.go index a92cd9437..d92d6d7c6 100644 --- a/cli/sync.go +++ b/cli/sync.go @@ -20,6 +20,7 @@ var syncCmd = &cli.Command{ syncStatusCmd, syncWaitCmd, syncMarkBadCmd, + syncUnmarkBadCmd, syncCheckBadCmd, }, } @@ -117,6 +118,31 @@ var syncMarkBadCmd = &cli.Command{ }, } +var syncUnmarkBadCmd = &cli.Command{ + Name: "unmark-bad", + Usage: "Unmark the given block as bad, makes it possible to sync to a chain containing it", + ArgsUsage: "[blockCid]", + Action: func(cctx *cli.Context) error { + napi, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + if !cctx.Args().Present() { + return fmt.Errorf("must specify block cid to unmark") + } + + bcid, err := cid.Decode(cctx.Args().First()) + if err != nil { + return fmt.Errorf("failed to decode input as a cid: %s", err) + } + + return napi.SyncUnmarkBad(ctx, bcid) + }, +} + var syncCheckBadCmd = &cli.Command{ Name: "check-bad", Usage: "check if the given block was marked bad, and for what reason", From 22fdb9594dc404f03f69563ca448364f3f5d7e47 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 03:42:03 -0400 Subject: [PATCH 122/199] Add CLI to checkpoint tipsets --- cli/chain.go | 19 ------------------- cli/sync.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ cli/util.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 cli/util.go diff --git a/cli/chain.go b/cli/chain.go index d00247364..ce1660641 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -337,25 +337,6 @@ var chainSetHeadCmd = &cli.Command{ }, } -func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.TipSet, error) { - var headers []*types.BlockHeader - for _, c := range vals { - blkc, err := cid.Decode(c) - if err != nil { - return nil, err - } - - bh, err := api.ChainGetBlock(ctx, blkc) - if err != nil { - return nil, err - } - - headers = append(headers, bh) - } - - return types.NewTipSet(headers) -} - var chainListCmd = &cli.Command{ Name: "list", Usage: "View a segment of the chain", diff --git a/cli/sync.go b/cli/sync.go index d92d6d7c6..bff34960e 100644 --- a/cli/sync.go +++ b/cli/sync.go @@ -5,6 +5,8 @@ import ( "fmt" "time" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/go-state-types/abi" cid "github.com/ipfs/go-cid" "github.com/urfave/cli/v2" @@ -22,6 +24,7 @@ var syncCmd = &cli.Command{ syncMarkBadCmd, syncUnmarkBadCmd, syncCheckBadCmd, + syncCheckpointCmd, }, } @@ -179,6 +182,48 @@ var syncCheckBadCmd = &cli.Command{ }, } +var syncCheckpointCmd = &cli.Command{ + Name: "checkpoint", + Usage: "mark a certain tipset as checkpointed; the node will never fork away from this tipset", + ArgsUsage: "[tipsetKey]", + Flags: []cli.Flag{ + &cli.Uint64Flag{ + Name: "epoch", + Usage: "checkpoint the tipset at the given epoch", + }, + }, + Action: func(cctx *cli.Context) error { + napi, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + ctx := ReqContext(cctx) + + var ts *types.TipSet + + if cctx.IsSet("epoch") { + ts, err = napi.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(cctx.Uint64("epoch")), types.EmptyTSK) + } + if ts == nil { + ts, err = parseTipSet(ctx, napi, cctx.Args().Slice()) + } + if err != nil { + return err + } + + if ts == nil { + return fmt.Errorf("must pass cids for tipset to set as head, or specify epoch flag") + } + + if err := napi.SyncCheckpoint(ctx, ts.Key()); err != nil { + return err + } + + return nil + }, +} + func SyncWait(ctx context.Context, napi api.FullNode) error { for { state, err := napi.SyncState(ctx) diff --git a/cli/util.go b/cli/util.go new file mode 100644 index 000000000..4371f8bbc --- /dev/null +++ b/cli/util.go @@ -0,0 +1,28 @@ +package cli + +import ( + "context" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" +) + +func parseTipSet(ctx context.Context, api api.FullNode, vals []string) (*types.TipSet, error) { + var headers []*types.BlockHeader + for _, c := range vals { + blkc, err := cid.Decode(c) + if err != nil { + return nil, err + } + + bh, err := api.ChainGetBlock(ctx, blkc) + if err != nil { + return nil, err + } + + headers = append(headers, bh) + } + + return types.NewTipSet(headers) +} From 3337b9a98f8ade41310dbfbc1c5c607eb0baa242 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 03:45:47 -0400 Subject: [PATCH 123/199] Update docs --- documentation/en/api-methods.md | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index 64f0d272a..10b870e14 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -156,10 +156,12 @@ * [StateWaitMsg](#StateWaitMsg) * [Sync](#Sync) * [SyncCheckBad](#SyncCheckBad) + * [SyncCheckpoint](#SyncCheckpoint) * [SyncIncomingBlocks](#SyncIncomingBlocks) * [SyncMarkBad](#SyncMarkBad) * [SyncState](#SyncState) * [SyncSubmitBlock](#SyncSubmitBlock) + * [SyncUnmarkBad](#SyncUnmarkBad) * [Wallet](#Wallet) * [WalletBalance](#WalletBalance) * [WalletDefaultAddress](#WalletDefaultAddress) @@ -3995,6 +3997,28 @@ Inputs: Response: `"string value"` +### SyncCheckpoint +SyncCheckpoint marks a blocks as checkpointed, meaning that it won't ever fork away from it. + + +Perms: admin + +Inputs: +```json +[ + [ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + }, + { + "/": "bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve" + } + ] +] +``` + +Response: `{}` + ### SyncIncomingBlocks SyncIncomingBlocks returns a channel streaming incoming, potentially not yet synced block headers. @@ -4130,6 +4154,23 @@ Inputs: Response: `{}` +### SyncUnmarkBad +SyncUnmarkBad unmarks a blocks as bad, making it possible to be validated and synced again. + + +Perms: admin + +Inputs: +```json +[ + { + "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" + } +] +``` + +Response: `{}` + ## Wallet From f0554676dd7f6cb9becb3d4d138aa4270796cfa3 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 14:33:00 -0400 Subject: [PATCH 124/199] Explicitly check tipsetkeys when considering checkpoint --- chain/sync.go | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/chain/sync.go b/chain/sync.go index ccc97e12f..d64e68055 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -1402,6 +1402,12 @@ var ErrForkCheckpoint = fmt.Errorf("fork would require us to diverge from checkp // we add the entire subchain to the denylist. Else, we find the common ancestor, and add the missing chain // fragment until the fork point to the returned []TipSet. func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, known *types.TipSet) ([]*types.TipSet, error) { + + chkpt := syncer.GetCheckpoint() + if known.Key() == chkpt { + return nil, ErrForkCheckpoint + } + // TODO: Does this mean we always ask for ForkLengthThreshold blocks from the network, even if we just need, like, 2? // Would it not be better to ask in smaller chunks, given that an ~ForkLengthThreshold is very rare? tips, err := syncer.Exchange.GetBlocks(ctx, incoming.Parents(), int(build.ForkLengthThreshold)) @@ -1423,28 +1429,17 @@ func (syncer *Syncer) syncFork(ctx context.Context, incoming *types.TipSet, know } if nts.Equals(tips[cur]) { - // We've identified the ancestor - // Still need to make sure this wouldn't cause us to fork away from the checkpointed tipset - - chkpt := syncer.GetCheckpoint() - - if chkpt != types.EmptyTSK { - chkTs, err := syncer.ChainStore().LoadTipSet(chkpt) - if err != nil { - return nil, xerrors.Errorf("failed to retrieve checkpoint tipset: %w", err) - } - - if chkTs.Height() > nts.Height() { - return nil, ErrForkCheckpoint - } - } - return tips[:cur+1], nil } if nts.Height() < tips[cur].Height() { cur++ } else { + // We will be forking away from nts, check that it isn't checkpointed + if nts.Key() == chkpt { + return nil, ErrForkCheckpoint + } + nts, err = syncer.store.LoadTipSet(nts.Parents()) if err != nil { return nil, xerrors.Errorf("loading next local tipset: %w", err) From afa913f2ed8fd75a546112c32afa3f081b1f7a9c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 9 Sep 2020 11:34:55 -0700 Subject: [PATCH 125/199] Remove hard-coded late-fee in window PoSt This is no longer necessary, and doesn't really serve any purpose. --- storage/wdpost_run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 51d71e331..090648dbb 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -490,7 +490,7 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi From: s.worker, Method: builtin.MethodsMiner.SubmitWindowedPoSt, Params: enc, - Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late + Value: types.NewInt(0), } spec := &api.MessageSendSpec{MaxFee: abi.TokenAmount(s.feeCfg.MaxWindowPoStGasFee)} s.setSender(ctx, msg, spec) From f7d3d371f7eb7de5b8700fdb288f0fb733e6d634 Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 9 Sep 2020 22:11:51 +0300 Subject: [PATCH 126/199] print reward and actual gas performancec --- cli/mpool.go | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/cli/mpool.go b/cli/mpool.go index add3af7bd..6ae94356a 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -3,6 +3,7 @@ package cli import ( "encoding/json" "fmt" + stdbig "math/big" "sort" "strconv" @@ -14,6 +15,7 @@ import ( "github.com/filecoin-project/go-state-types/big" lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/types" ) @@ -570,10 +572,31 @@ var mpoolGasPerfCmd = &cli.Command{ } baseFee := ts.Blocks()[0].ParentBaseFee - for _, m := range msgs { - feeCapSlack := types.BigSub(m.Message.GasFeeCap, baseFee) - fmt.Printf("%s\t%d\t%s\n", m.Message.From, m.Message.Nonce, feeCapSlack) + bigBlockGasLimit := big.NewInt(build.BlockGasLimit) + + getGasReward := func(msg *types.SignedMessage) big.Int { + maxPremium := types.BigSub(msg.Message.GasFeeCap, baseFee) + if types.BigCmp(maxPremium, msg.Message.GasPremium) < 0 { + maxPremium = msg.Message.GasPremium + } + return types.BigMul(maxPremium, types.NewInt(uint64(msg.Message.GasLimit))) + } + + getGasPerf := func(gasReward big.Int, gasLimit int64) float64 { + // gasPerf = gasReward * build.BlockGasLimit / gasLimit + a := new(stdbig.Rat).SetInt(new(stdbig.Int).Mul(gasReward.Int, bigBlockGasLimit.Int)) + b := stdbig.NewRat(1, gasLimit) + c := new(stdbig.Rat).Mul(a, b) + r, _ := c.Float64() + return r + } + + for _, m := range msgs { + gasReward := getGasReward(m) + gasPerf := getGasPerf(gasReward, m.Message.GasLimit) + + fmt.Printf("%s\t%d\t%s\t%f\n", m.Message.From, m.Message.Nonce, gasReward, gasPerf) } return nil From 2d7a924275e396e7ed7187a98fcba4f0a6e698fb Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 9 Sep 2020 21:32:03 +0200 Subject: [PATCH 127/199] Add Kubuxu to CODEOWNERS 3 pairs of eyes are better than two and getting directly notified on PR is what I want (but GH notifications have no repo+PR filter). --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3cba4641b..49e461d00 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,7 +8,7 @@ ## the PR before merging. ### Global owners. -* @magik6k @whyrusleeping +* @magik6k @whyrusleeping @Kubuxu ### Conformance testing. conformance/ @raulk From d369f542c5d881879e37e968493b3fba7ac3d9fb Mon Sep 17 00:00:00 2001 From: vyzo Date: Wed, 9 Sep 2020 23:17:09 +0300 Subject: [PATCH 128/199] warn when optimal selection fails to pack a block and we fall back to random selection --- chain/messagepool/selection.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/chain/messagepool/selection.go b/chain/messagepool/selection.go index 8bb32eb1d..2ddbed0ad 100644 --- a/chain/messagepool/selection.go +++ b/chain/messagepool/selection.go @@ -309,8 +309,10 @@ tailLoop: // if we have gasLimit to spare, pick some random (non-negative) chains to fill the block // we pick randomly so that we minimize the probability of duplication among all miners - startRandom := time.Now() if gasLimit >= minGas { + randomCount := 0 + + startRandom := time.Now() shuffleChains(chains) for _, chain := range chains { @@ -359,15 +361,23 @@ tailLoop: curChain := chainDeps[i] curChain.merged = true result = append(result, curChain.msgs...) + randomCount += len(curChain.msgs) } chain.merged = true result = append(result, chain.msgs...) + randomCount += len(chain.msgs) gasLimit -= chainGasLimit } - } - if dt := time.Since(startRandom); dt > time.Millisecond { - log.Infow("pack random tail chains done", "took", dt) + + if dt := time.Since(startRandom); dt > time.Millisecond { + log.Infow("pack random tail chains done", "took", dt) + } + + if randomCount > 0 { + log.Warnf("optimal selection failed to pack a block; picked %d messages with random selection", + randomCount) + } } return result, nil From 1d4b5c201e65c97282f94c5dc64bd8d6d8c24f64 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 15:54:21 -0400 Subject: [PATCH 129/199] Lotus version 0.6.2 --- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++++++ build/version.go | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15bfe8334..a3d85ab6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,44 @@ # Lotus changelog +# 0.6.2 / 2020-09-09 + +This release introduces some critical fixes to message selection and gas estimation logic. It also adds the ability for nodes to mark a certain tipset as checkpointed, as well as various minor improvements and bugfixes. + +## Changes + +#### Messagepool + +- Warn when optimal selection fails to pack a block and we fall back to random selection (https://github.com/filecoin-project/lotus/pull/3708) +- Add basic command for printing gas performance of messages in the mpool (https://github.com/filecoin-project/lotus/pull/3701) +- Adjust optimal selection to always try to fill blocks (https://github.com/filecoin-project/lotus/pull/3685) +- Fix very minor bug in repub baseFeeLowerBound (https://github.com/filecoin-project/lotus/pull/3663) +- Add an auto flag to mpool replace (https://github.com/filecoin-project/lotus/pull/3676) +- Fix mpool optimal selection packing failure (https://github.com/filecoin-project/lotus/pull/3698) + +#### Core Lotus + +- Don't use latency as initital estimate for blocksync (https://github.com/filecoin-project/lotus/pull/3648) +- Add niceSleep 1 second when drand errors (https://github.com/filecoin-project/lotus/pull/3664) +- Fix isChainNearSync check in block validator (https://github.com/filecoin-project/lotus/pull/3650) +- Add peer to peer manager before fetching the tipset (https://github.com/filecoin-project/lotus/pull/3667) +- Add StageFetchingMessages to sync status (https://github.com/filecoin-project/lotus/pull/3668) +- Pass tipset through upgrade logic (https://github.com/filecoin-project/lotus/pull/3673) +- Allow nodes to mark tipsets as checkpointed (https://github.com/filecoin-project/lotus/pull/3680) +- Remove hard-coded late-fee in window PoSt (https://github.com/filecoin-project/lotus/pull/3702) +- Gas: Fix median calc (https://github.com/filecoin-project/lotus/pull/3686) + +#### Storage + +- Storage manager: bail out with an error if unsealed cid is undefined (https://github.com/filecoin-project/lotus/pull/3655) +- Storage: return true from Sealer.ReadPiece() on success (https://github.com/filecoin-project/lotus/pull/3657) + +#### Maintenance + +- Resolve lotus, test-vectors, statediff dependency cycle (https://github.com/filecoin-project/lotus/pull/3688) +- Paych: add docs on how to use paych status (https://github.com/filecoin-project/lotus/pull/3690) +- Initial CODEOWNERS (https://github.com/filecoin-project/lotus/pull/3691) + + # 0.6.1 / 2020-09-08 This optional release introduces a minor improvement to the sync process, ensuring nodes don't fall behind and then resync. diff --git a/build/version.go b/build/version.go index 338be1263..21d3942c2 100644 --- a/build/version.go +++ b/build/version.go @@ -25,7 +25,7 @@ func buildType() string { } // BuildVersion is the local build version, set by build system -const BuildVersion = "0.6.2-rc1" +const BuildVersion = "0.6.2" func UserVersion() string { return BuildVersion + buildType() + CurrentCommit From 7a6ceebb34a95508acdef964519c75929d37cfc4 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 9 Sep 2020 14:00:15 -0700 Subject: [PATCH 130/199] windowed post generation now returns faulty sectors --- extern/filecoin-ffi | 2 +- .../sector-storage/ffiwrapper/verifier_cgo.go | 17 +++++++++++++---- go.mod | 8 ++++++-- storage/wdpost_run.go | 4 +++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 405691046..79b324966 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 40569104603407c999d6c9e4c3f1228cbd4d0e5c +Subproject commit 79b3249666a809871fad12fbf50f68e22218b01c diff --git a/extern/sector-storage/ffiwrapper/verifier_cgo.go b/extern/sector-storage/ffiwrapper/verifier_cgo.go index 0af12da0b..59d0856d1 100644 --- a/extern/sector-storage/ffiwrapper/verifier_cgo.go +++ b/extern/sector-storage/ffiwrapper/verifier_cgo.go @@ -32,16 +32,25 @@ func (sb *Sealer) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, return ffi.GenerateWinningPoSt(minerID, privsectors, randomness) } -func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) { +func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, []abi.SectorID, error) { randomness[31] &= 0x3f privsectors, skipped, done, err := sb.pubSectorToPriv(ctx, minerID, sectorInfo, nil, abi.RegisteredSealProof.RegisteredWindowPoStProof) if err != nil { - return nil, nil, xerrors.Errorf("gathering sector info: %w", err) + return nil, nil, nil, xerrors.Errorf("gathering sector info: %w", err) } defer done() - proof, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness) - return proof, skipped, err + proof, faulty, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness) + + var faultyIDs []abi.SectorID + for _, f := range faulty { + faultyIDs = append(faultyIDs, abi.SectorID{ + Miner: minerID, + Number: f, + }) + } + + return proof, skipped, faultyIDs, err } func (sb *Sealer) pubSectorToPriv(ctx context.Context, mid abi.ActorID, sectorInfo []proof.SectorInfo, faults []abi.SectorNumber, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error)) (ffi.SortedPrivateSectorInfo, []abi.SectorID, func(), error) { diff --git a/go.mod b/go.mod index bc4067d67..56c1420d0 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/filecoin-project/lotus go 1.14 -replace github.com/supranational/blst => github.com/supranational/blst v0.1.2-alpha.1 - require ( contrib.go.opencensus.io/exporter/jaeger v0.1.0 contrib.go.opencensus.io/exporter/prometheus v0.1.0 @@ -138,3 +136,9 @@ replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 replace github.com/filecoin-project/test-vectors => ./extern/test-vectors + +replace github.com/supranational/blst => ./extern/fil-blst/blst + +replace github.com/filecoin-project/fil-blst => ./extern/fil-blst + +replace github.com/filecoin-project/specs-storage => ../specs-storage diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 090648dbb..d3e91e450 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -406,11 +406,13 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo return nil, err } - postOut, postSkipped, err := s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) + postOut, postSkipped, faulty, err := s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) if err != nil { return nil, xerrors.Errorf("running post failed: %w", err) } + _ = faulty // TODO(magik) + if len(postOut) == 0 { return nil, xerrors.Errorf("received proofs back from generate window post") } From a7a43a1124073f4c39e805a418170854200b9269 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 17:10:35 -0400 Subject: [PATCH 131/199] Fix devnets --- build/params_2k.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/params_2k.go b/build/params_2k.go index a24e4421c..4bc7c2ecc 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -10,7 +10,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" ) -const UpgradeBreezeHeight = 0 +const UpgradeBreezeHeight = -1 const BreezeGasTampingDuration = 0 func init() { From 8807c75c5165504d1cbff4f7f27eeb8c9bf64b39 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 18:17:05 -0400 Subject: [PATCH 132/199] Fix warn message --- node/impl/full/sync.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/impl/full/sync.go b/node/impl/full/sync.go index 7f7fd48be..31a707b90 100644 --- a/node/impl/full/sync.go +++ b/node/impl/full/sync.go @@ -98,7 +98,7 @@ func (a *SyncAPI) SyncIncomingBlocks(ctx context.Context) (<-chan *types.BlockHe } func (a *SyncAPI) SyncCheckpoint(ctx context.Context, tsk types.TipSetKey) error { - log.Warnf("Marking tipset %s as bad", tsk) + log.Warnf("Marking tipset %s as checkpoint", tsk) return a.Syncer.SetCheckpoint(tsk) } From 679c4183e7e3865e1fe12da345bc67ab1865fff7 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Mon, 31 Aug 2020 16:37:18 -0700 Subject: [PATCH 133/199] add a simple command to watch messages sitting in the mempool --- cmd/lotus-shed/main.go | 1 + cmd/lotus-shed/mempool-stats.go | 79 +++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 cmd/lotus-shed/mempool-stats.go diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 2d0d7c3a0..4944b67aa 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -33,6 +33,7 @@ func main() { mpoolCmd, genesisVerifyCmd, mathCmd, + mpoolStatsCmd, } app := &cli.App{ diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go new file mode 100644 index 000000000..d2651a826 --- /dev/null +++ b/cmd/lotus-shed/mempool-stats.go @@ -0,0 +1,79 @@ +package main + +import ( + "fmt" + "time" + + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log" + "github.com/urfave/cli/v2" + + lapi "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" +) + +type msgInfo struct { + msg *types.SignedMessage + seen time.Time +} + +var mpoolStatsCmd = &cli.Command{ + Name: "mpool-stats", + Action: func(cctx *cli.Context) error { + logging.SetLogLevel("rpc", "ERROR") + + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + updates, err := api.MpoolSub(ctx) + if err != nil { + return err + } + + tracker := make(map[cid.Cid]*msgInfo) + tick := time.Tick(time.Second) + for { + select { + case u := <-updates: + switch u.Type { + case lapi.MpoolAdd: + tracker[u.Message.Cid()] = &msgInfo{ + msg: u.Message, + seen: time.Now(), + } + case lapi.MpoolRemove: + mi, ok := tracker[u.Message.Cid()] + if !ok { + continue + } + fmt.Printf("%s was in the mempool for %s (feecap=%s, prem=%s)\n", u.Message.Cid(), time.Since(mi.seen), u.Message.Message.GasFeeCap, u.Message.Message.GasPremium) + delete(tracker, u.Message.Cid()) + default: + return fmt.Errorf("unrecognized mpool update state: %d", u.Type) + } + case <-tick: + if len(tracker) == 0 { + continue + } + var avg time.Duration + var oldest time.Duration + for _, v := range tracker { + age := time.Since(v.seen) + if age > oldest { + oldest = age + } + + avg += age + } + fmt.Printf("%d messages in mempool for average of %s, max=%s\n", len(tracker), avg/time.Duration(len(tracker)), oldest) + } + } + return nil + }, +} From 47ad7ccb5f7546367c86fd7cbe862c878b3f1288 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 1 Sep 2020 12:40:42 -0700 Subject: [PATCH 134/199] some more stats --- cmd/lotus-shed/mempool-stats.go | 63 ++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index d2651a826..320ba31a5 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "sort" "time" "github.com/ipfs/go-cid" @@ -58,22 +59,68 @@ var mpoolStatsCmd = &cli.Command{ return fmt.Errorf("unrecognized mpool update state: %d", u.Type) } case <-tick: + var ages []time.Duration if len(tracker) == 0 { continue } - var avg time.Duration - var oldest time.Duration for _, v := range tracker { age := time.Since(v.seen) - if age > oldest { - oldest = age - } - - avg += age + ages = append(ages, age) } - fmt.Printf("%d messages in mempool for average of %s, max=%s\n", len(tracker), avg/time.Duration(len(tracker)), oldest) + + st := ageStats(ages) + fmt.Printf("%d messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95) } } return nil }, } + +type ageStat struct { + Average time.Duration + Max time.Duration + Perc40 time.Duration + Perc50 time.Duration + Perc60 time.Duration + Perc70 time.Duration + Perc80 time.Duration + Perc90 time.Duration + Perc95 time.Duration + Count int +} + +func ageStats(ages []time.Duration) *ageStat { + sort.Slice(ages, func(i, j int) bool { + return ages[i] < ages[j] + }) + + st := ageStat{ + Count: len(ages), + } + var sum time.Duration + for _, a := range ages { + sum += a + if a > st.Max { + st.Max = a + } + } + st.Average = sum / time.Duration(len(ages)) + + p40 := (4 * len(ages)) / 10 + p50 := len(ages) / 2 + p60 := (6 * len(ages)) / 10 + p70 := (7 * len(ages)) / 10 + p80 := (4 * len(ages)) / 5 + p90 := (9 * len(ages)) / 10 + p95 := (19 * len(ages)) / 20 + + st.Perc40 = ages[p40] + st.Perc50 = ages[p50] + st.Perc60 = ages[p60] + st.Perc70 = ages[p70] + st.Perc80 = ages[p80] + st.Perc90 = ages[p90] + st.Perc95 = ages[p95] + + return &st +} From 7d1d690eb720626c5b202cc7c6185705a8185e11 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 1 Sep 2020 14:09:14 -0700 Subject: [PATCH 135/199] lets get some metrics --- cmd/lotus-shed/mempool-stats.go | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index 320ba31a5..d7408b9cb 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -2,18 +2,52 @@ package main import ( "fmt" + "net/http" "sort" "time" + "contrib.go.opencensus.io/exporter/prometheus" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log" "github.com/urfave/cli/v2" + "go.opencensus.io/stats" + "go.opencensus.io/stats/view" + "go.opencensus.io/tag" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" ) +var ( + MpoolAge = stats.Float64("mpoolage", "Age of messages in the mempool", stats.UnitSeconds) + MpoolSize = stats.Int64("mpoolsize", "Number of messages in mempool", stats.UnitDimensionless) + MpoolInboundRate = stats.Int64("inbound", "Counter for inbound messages", stats.UnitDimensionless) +) + +var ( + LeTag, _ = tag.NewKey("le") +) + +var ( + AgeView = &view.View{ + Name: "mpool-age", + Measure: MpoolAge, + TagKeys: []tag.Key{LeTag}, + Aggregation: view.LastValue(), + } + SizeView = &view.View{ + Name: "mpool-size", + Measure: MpoolSize, + Aggregation: view.LastValue(), + } + InboundRate = &view.View{ + Name: "msg-inbound", + Measure: MpoolInboundRate, + Aggregation: view.Count(), + } +) + type msgInfo struct { msg *types.SignedMessage seen time.Time @@ -24,6 +58,25 @@ var mpoolStatsCmd = &cli.Command{ Action: func(cctx *cli.Context) error { logging.SetLogLevel("rpc", "ERROR") + if err := view.Register(AgeView); err != nil { + return err + } + + expo, err := prometheus.NewExporter(prometheus.Options{ + Namespace: "lotusmpool", + }) + if err != nil { + return err + } + + http.Handle("/debug/metrics", expo) + + go func() { + if err := http.ListenAndServe(":10555", nil); err != nil { + panic(err) + } + }() + api, closer, err := lcli.GetFullNodeAPI(cctx) if err != nil { return err @@ -48,6 +101,7 @@ var mpoolStatsCmd = &cli.Command{ msg: u.Message, seen: time.Now(), } + stats.Record(ctx, MpoolInboundRate.M(1)) case lapi.MpoolRemove: mi, ok := tracker[u.Message.Cid()] if !ok { @@ -69,6 +123,15 @@ var mpoolStatsCmd = &cli.Command{ } st := ageStats(ages) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40")}, MpoolAge.M(st.Perc40.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50")}, MpoolAge.M(st.Perc50.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60")}, MpoolAge.M(st.Perc60.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70")}, MpoolAge.M(st.Perc70.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80")}, MpoolAge.M(st.Perc80.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90")}, MpoolAge.M(st.Perc90.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95")}, MpoolAge.M(st.Perc95.Seconds())) + + stats.Record(ctx, MpoolSize.M(int64(len(tracker)))) fmt.Printf("%d messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95) } } From 8414aa6e4b053d21f32e8028a1dbb3fcb940103a Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 1 Sep 2020 15:11:02 -0700 Subject: [PATCH 136/199] more metrics! --- cmd/lotus-shed/mempool-stats.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index d7408b9cb..fc7159d2a 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -20,9 +20,11 @@ import ( ) var ( - MpoolAge = stats.Float64("mpoolage", "Age of messages in the mempool", stats.UnitSeconds) - MpoolSize = stats.Int64("mpoolsize", "Number of messages in mempool", stats.UnitDimensionless) - MpoolInboundRate = stats.Int64("inbound", "Counter for inbound messages", stats.UnitDimensionless) + MpoolAge = stats.Float64("mpoolage", "Age of messages in the mempool", stats.UnitSeconds) + MpoolSize = stats.Int64("mpoolsize", "Number of messages in mempool", stats.UnitDimensionless) + MpoolInboundRate = stats.Int64("inbound", "Counter for inbound messages", stats.UnitDimensionless) + BlockInclusionRate = stats.Int64("inclusion", "Counter for message included in blocks", stats.UnitDimensionless) + MsgWaitTime = stats.Float64("msg-wait-time", "Wait time of messages to make it into a block", stats.UnitSeconds) ) var ( @@ -46,6 +48,16 @@ var ( Measure: MpoolInboundRate, Aggregation: view.Count(), } + InclusionRate = &view.View{ + Name: "msg-inclusion", + Measure: BlockInclusionRate, + Aggregation: view.Count(), + } + MsgWait = &view.View{ + Name: "msg-wait", + Measure: MsgWaitTime, + Aggregation: view.Distribution(10, 30, 60, 120, 240, 600, 1800, 3600), + } ) type msgInfo struct { @@ -58,7 +70,7 @@ var mpoolStatsCmd = &cli.Command{ Action: func(cctx *cli.Context) error { logging.SetLogLevel("rpc", "ERROR") - if err := view.Register(AgeView); err != nil { + if err := view.Register(AgeView, SizeView, InboundRate, InclusionRate, MsgWait); err != nil { return err } @@ -108,6 +120,8 @@ var mpoolStatsCmd = &cli.Command{ continue } fmt.Printf("%s was in the mempool for %s (feecap=%s, prem=%s)\n", u.Message.Cid(), time.Since(mi.seen), u.Message.Message.GasFeeCap, u.Message.Message.GasPremium) + stats.Record(ctx, BlockInclusionRate.M(1)) + stats.Record(ctx, MsgWaitTime.M(time.Since(mi.seen).Seconds())) delete(tracker, u.Message.Cid()) default: return fmt.Errorf("unrecognized mpool update state: %d", u.Type) From e58327d4ed6ec61743522ba2fd12769af9fe55c1 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Tue, 1 Sep 2020 15:46:55 -0700 Subject: [PATCH 137/199] rename LE tag to quantile --- cmd/lotus-shed/mempool-stats.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index fc7159d2a..b21948065 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -28,7 +28,7 @@ var ( ) var ( - LeTag, _ = tag.NewKey("le") + LeTag, _ = tag.NewKey("quantile") ) var ( From 09194aa6133c4a7344dad81d343b9c15c4d30238 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 2 Sep 2020 15:57:42 -0700 Subject: [PATCH 138/199] print better error when losing connection --- cmd/lotus-shed/mempool-stats.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index b21948065..4c87b5b5a 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -106,7 +106,10 @@ var mpoolStatsCmd = &cli.Command{ tick := time.Tick(time.Second) for { select { - case u := <-updates: + case u, ok := <-updates: + if !ok { + return fmt.Errorf("connection with lotus node broke") + } switch u.Type { case lapi.MpoolAdd: tracker[u.Message.Cid()] = &msgInfo{ From f2b238f50ab3e5ff320ec13b576594caab8809fa Mon Sep 17 00:00:00 2001 From: frrist Date: Wed, 9 Sep 2020 15:30:30 -0700 Subject: [PATCH 139/199] fix(chainwatch): compare prev miner with cur miner - bug was comparing cur miner with cur miner --- cmd/lotus-chainwatch/processor/miner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/lotus-chainwatch/processor/miner.go b/cmd/lotus-chainwatch/processor/miner.go index 1442a84bc..e063db19f 100644 --- a/cmd/lotus-chainwatch/processor/miner.go +++ b/cmd/lotus-chainwatch/processor/miner.go @@ -694,7 +694,7 @@ func (p *Processor) getMinerSectorChanges(ctx context.Context, m minerActorInfo) } func (p *Processor) diffMinerPartitions(ctx context.Context, m minerActorInfo, events chan<- *MinerSectorsEvent) error { - prevMiner, err := p.getMinerStateAt(ctx, m.common.addr, m.common.tsKey) + prevMiner, err := p.getMinerStateAt(ctx, m.common.addr, m.common.parentTsKey) if err != nil { return err } From 183df4c1357ed3221ebb592b6f6af3d966a0875a Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 19:09:55 -0400 Subject: [PATCH 140/199] Fix IsAncestorOf --- chain/store/store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/store/store.go b/chain/store/store.go index e0a997686..c85f547a1 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -471,7 +471,7 @@ func (cs *ChainStore) IsAncestorOf(a, b *types.TipSet) (bool, error) { cur := b for !a.Equals(cur) && cur.Height() > a.Height() { - next, err := cs.LoadTipSet(b.Parents()) + next, err := cs.LoadTipSet(cur.Parents()) if err != nil { return false, err } From e1a0cf6ca56de88672e206a177201588e67af970 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Wed, 9 Sep 2020 19:21:48 -0400 Subject: [PATCH 141/199] Add a checkpoint test --- chain/sync_test.go | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/chain/sync_test.go b/chain/sync_test.go index 92873118a..0b0d1ed00 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -709,7 +709,7 @@ func TestSyncInputs(t *testing.T) { } } -func TestSyncCheckpoint(t *testing.T) { +func TestSyncCheckpointHead(t *testing.T) { H := 10 tu := prepSyncTest(t, H) @@ -750,3 +750,45 @@ func TestSyncCheckpoint(t *testing.T) { require.Equal(tu.t, p1Head, a.TipSet()) tu.assertBad(p1, b.TipSet()) } + +func TestSyncCheckpointEarlierThanHead(t *testing.T) { + H := 10 + tu := prepSyncTest(t, H) + + p1 := tu.addClientNode() + p2 := tu.addClientNode() + + fmt.Println("GENESIS: ", tu.g.Genesis().Cid()) + tu.loadChainToNode(p1) + tu.loadChainToNode(p2) + + base := tu.g.CurTipset + fmt.Println("Mining base: ", base.TipSet().Cids(), base.TipSet().Height()) + + // The two nodes fork at this point into 'a' and 'b' + a1 := tu.mineOnBlock(base, p1, []int{0}, true, false, nil) + a := tu.mineOnBlock(a1, p1, []int{0}, true, false, nil) + a = tu.mineOnBlock(a, p1, []int{0}, true, false, nil) + + tu.waitUntilSyncTarget(p1, a.TipSet()) + tu.checkpointTs(p1, a1.TipSet().Key()) + + require.NoError(t, tu.g.ResyncBankerNonce(a1.TipSet())) + // chain B will now be heaviest + b := tu.mineOnBlock(base, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + b = tu.mineOnBlock(b, p2, []int{1}, true, false, nil) + + fmt.Println("A: ", a.Cids(), a.TipSet().Height()) + fmt.Println("B: ", b.Cids(), b.TipSet().Height()) + + // Now for the fun part!! p1 should mark p2's head as BAD. + + require.NoError(t, tu.mn.LinkAll()) + tu.connect(p1, p2) + tu.waitUntilNodeHasTs(p1, b.TipSet().Key()) + p1Head := tu.getHead(p1) + require.Equal(tu.t, p1Head, a.TipSet()) + tu.assertBad(p1, b.TipSet()) +} From 0361ca1c396d756a044dcdbf56534e5bebbcd054 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 9 Sep 2020 17:18:55 -0700 Subject: [PATCH 142/199] add some bits about windowed post --- cmd/lotus-shed/mempool-stats.go | 116 +++++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 24 deletions(-) diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index 4c87b5b5a..f38dc6a38 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -14,9 +14,11 @@ import ( "go.opencensus.io/stats/view" "go.opencensus.io/tag" + "github.com/filecoin-project/go-address" lapi "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/specs-actors/actors/builtin" ) var ( @@ -29,33 +31,38 @@ var ( var ( LeTag, _ = tag.NewKey("quantile") + MTTag, _ = tag.NewKey("msg_type") ) var ( AgeView = &view.View{ Name: "mpool-age", Measure: MpoolAge, - TagKeys: []tag.Key{LeTag}, + TagKeys: []tag.Key{LeTag, MTTag}, Aggregation: view.LastValue(), } SizeView = &view.View{ Name: "mpool-size", Measure: MpoolSize, + TagKeys: []tag.Key{MTTag}, Aggregation: view.LastValue(), } InboundRate = &view.View{ Name: "msg-inbound", Measure: MpoolInboundRate, + TagKeys: []tag.Key{MTTag}, Aggregation: view.Count(), } InclusionRate = &view.View{ Name: "msg-inclusion", Measure: BlockInclusionRate, + TagKeys: []tag.Key{MTTag}, Aggregation: view.Count(), } MsgWait = &view.View{ Name: "msg-wait", Measure: MsgWaitTime, + TagKeys: []tag.Key{MTTag}, Aggregation: view.Distribution(10, 30, 60, 120, 240, 600, 1800, 3600), } ) @@ -102,6 +109,24 @@ var mpoolStatsCmd = &cli.Command{ return err } + mcache := make(map[address.Address]bool) + isMiner := func(addr address.Address) (bool, error) { + cache, ok := mcache[addr] + if ok { + return cache, nil + } + + act, err := api.StateGetActor(ctx, addr, types.EmptyTSK) + if err != nil { + return false, err + } + + ism := act.Code == builtin.StorageMinerActorCodeID + mcache[addr] = ism + return ism, nil + } + + wpostTracker := make(map[cid.Cid]*msgInfo) tracker := make(map[cid.Cid]*msgInfo) tick := time.Tick(time.Second) for { @@ -112,44 +137,87 @@ var mpoolStatsCmd = &cli.Command{ } switch u.Type { case lapi.MpoolAdd: + stats.Record(ctx, MpoolInboundRate.M(1)) tracker[u.Message.Cid()] = &msgInfo{ msg: u.Message, seen: time.Now(), } - stats.Record(ctx, MpoolInboundRate.M(1)) + + if u.Message.Message.Method == builtin.MethodsMiner.SubmitWindowedPoSt { + + miner, err := isMiner(u.Message.Message.To) + if err != nil { + log.Warnf("failed to determine if message target was to a miner: %s", err) + continue + } + + if miner { + wpostTracker[u.Message.Cid()] = &msgInfo{ + msg: u.Message, + seen: time.Now(), + } + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolInboundRate.M(1)) + } + } + case lapi.MpoolRemove: mi, ok := tracker[u.Message.Cid()] - if !ok { - continue + if ok { + fmt.Printf("%s was in the mempool for %s (feecap=%s, prem=%s)\n", u.Message.Cid(), time.Since(mi.seen), u.Message.Message.GasFeeCap, u.Message.Message.GasPremium) + stats.Record(ctx, BlockInclusionRate.M(1)) + stats.Record(ctx, MsgWaitTime.M(time.Since(mi.seen).Seconds())) + delete(tracker, u.Message.Cid()) + } + + wm, ok := wpostTracker[u.Message.Cid()] + if ok { + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, BlockInclusionRate.M(1)) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MsgWaitTime.M(time.Since(wm.seen).Seconds())) + delete(wpostTracker, u.Message.Cid()) } - fmt.Printf("%s was in the mempool for %s (feecap=%s, prem=%s)\n", u.Message.Cid(), time.Since(mi.seen), u.Message.Message.GasFeeCap, u.Message.Message.GasPremium) - stats.Record(ctx, BlockInclusionRate.M(1)) - stats.Record(ctx, MsgWaitTime.M(time.Since(mi.seen).Seconds())) - delete(tracker, u.Message.Cid()) default: return fmt.Errorf("unrecognized mpool update state: %d", u.Type) } case <-tick: var ages []time.Duration - if len(tracker) == 0 { - continue - } - for _, v := range tracker { - age := time.Since(v.seen) - ages = append(ages, age) + if len(tracker) > 0 { + for _, v := range tracker { + age := time.Since(v.seen) + ages = append(ages, age) + } + + st := ageStats(ages) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40")}, MpoolAge.M(st.Perc40.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50")}, MpoolAge.M(st.Perc50.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60")}, MpoolAge.M(st.Perc60.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70")}, MpoolAge.M(st.Perc70.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80")}, MpoolAge.M(st.Perc80.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90")}, MpoolAge.M(st.Perc90.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95")}, MpoolAge.M(st.Perc95.Seconds())) + + stats.Record(ctx, MpoolSize.M(int64(len(tracker)))) + fmt.Printf("%d messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95) } - st := ageStats(ages) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40")}, MpoolAge.M(st.Perc40.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50")}, MpoolAge.M(st.Perc50.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60")}, MpoolAge.M(st.Perc60.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70")}, MpoolAge.M(st.Perc70.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80")}, MpoolAge.M(st.Perc80.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90")}, MpoolAge.M(st.Perc90.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95")}, MpoolAge.M(st.Perc95.Seconds())) + var wpages []time.Duration + if len(wpostTracker) > 0 { + for _, v := range wpostTracker { + age := time.Since(v.seen) + wpages = append(wpages, age) + } - stats.Record(ctx, MpoolSize.M(int64(len(tracker)))) - fmt.Printf("%d messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95) + st := ageStats(wpages) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc40.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc50.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc60.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc70.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc80.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc90.Seconds())) + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc95.Seconds())) + + stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolSize.M(int64(len(wpostTracker)))) + fmt.Printf("%d wpost messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95) + } } } return nil From c73916b4e7e49d2aa6d112beaeeffb1a61c13a20 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 9 Sep 2020 17:37:49 -0700 Subject: [PATCH 143/199] fix the linter --- cmd/lotus-shed/mempool-stats.go | 37 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/cmd/lotus-shed/mempool-stats.go b/cmd/lotus-shed/mempool-stats.go index f38dc6a38..b81cf2704 100644 --- a/cmd/lotus-shed/mempool-stats.go +++ b/cmd/lotus-shed/mempool-stats.go @@ -156,7 +156,7 @@ var mpoolStatsCmd = &cli.Command{ msg: u.Message, seen: time.Now(), } - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolInboundRate.M(1)) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolInboundRate.M(1)) } } @@ -171,8 +171,8 @@ var mpoolStatsCmd = &cli.Command{ wm, ok := wpostTracker[u.Message.Cid()] if ok { - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, BlockInclusionRate.M(1)) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MsgWaitTime.M(time.Since(wm.seen).Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, BlockInclusionRate.M(1)) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MsgWaitTime.M(time.Since(wm.seen).Seconds())) delete(wpostTracker, u.Message.Cid()) } default: @@ -187,13 +187,13 @@ var mpoolStatsCmd = &cli.Command{ } st := ageStats(ages) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40")}, MpoolAge.M(st.Perc40.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50")}, MpoolAge.M(st.Perc50.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60")}, MpoolAge.M(st.Perc60.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70")}, MpoolAge.M(st.Perc70.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80")}, MpoolAge.M(st.Perc80.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90")}, MpoolAge.M(st.Perc90.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95")}, MpoolAge.M(st.Perc95.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40")}, MpoolAge.M(st.Perc40.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50")}, MpoolAge.M(st.Perc50.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60")}, MpoolAge.M(st.Perc60.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70")}, MpoolAge.M(st.Perc70.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80")}, MpoolAge.M(st.Perc80.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90")}, MpoolAge.M(st.Perc90.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95")}, MpoolAge.M(st.Perc95.Seconds())) stats.Record(ctx, MpoolSize.M(int64(len(tracker)))) fmt.Printf("%d messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95) @@ -207,20 +207,19 @@ var mpoolStatsCmd = &cli.Command{ } st := ageStats(wpages) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc40.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc50.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc60.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc70.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc80.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc90.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc95.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "40"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc40.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "50"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc50.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "60"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc60.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "70"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc70.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "80"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc80.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "90"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc90.Seconds())) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(LeTag, "95"), tag.Upsert(MTTag, "wpost")}, MpoolAge.M(st.Perc95.Seconds())) - stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolSize.M(int64(len(wpostTracker)))) + _ = stats.RecordWithTags(ctx, []tag.Mutator{tag.Upsert(MTTag, "wpost")}, MpoolSize.M(int64(len(wpostTracker)))) fmt.Printf("%d wpost messages in mempool for average of %s, (%s / %s / %s)\n", st.Count, st.Average, st.Perc50, st.Perc80, st.Perc95) } } } - return nil }, } From 5e7737f55d5f7b7b0b658d45c481e5e2fb536041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 10 Sep 2020 02:59:37 +0200 Subject: [PATCH 144/199] wdpost: Handle skipped sectors correctly --- api/test/window_post.go | 2 +- .../sector-storage/ffiwrapper/verifier_cgo.go | 10 +- extern/sector-storage/mock/mock.go | 22 ++- go.mod | 2 - go.sum | 2 + storage/wdpost_run.go | 166 ++++++++++-------- 6 files changed, 123 insertions(+), 81 deletions(-) diff --git a/api/test/window_post.go b/api/test/window_post.go index 59d7ac1d6..3f15c754b 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -192,7 +192,7 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector // Drop the partition err = parts[0].Sectors.ForEach(func(sid uint64) error { - return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkFailed(abi.SectorID{ + return miner.StorageMiner.(*impl.StorageMinerAPI).IStorageMgr.(*mock.SectorMgr).MarkCorrupted(abi.SectorID{ Miner: abi.ActorID(mid), Number: abi.SectorNumber(sid), }, true) diff --git a/extern/sector-storage/ffiwrapper/verifier_cgo.go b/extern/sector-storage/ffiwrapper/verifier_cgo.go index 59d0856d1..d6c0ae35f 100644 --- a/extern/sector-storage/ffiwrapper/verifier_cgo.go +++ b/extern/sector-storage/ffiwrapper/verifier_cgo.go @@ -32,14 +32,18 @@ func (sb *Sealer) GenerateWinningPoSt(ctx context.Context, minerID abi.ActorID, return ffi.GenerateWinningPoSt(minerID, privsectors, randomness) } -func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, []abi.SectorID, error) { +func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, sectorInfo []proof.SectorInfo, randomness abi.PoStRandomness) ([]proof.PoStProof, []abi.SectorID, error) { randomness[31] &= 0x3f privsectors, skipped, done, err := sb.pubSectorToPriv(ctx, minerID, sectorInfo, nil, abi.RegisteredSealProof.RegisteredWindowPoStProof) if err != nil { - return nil, nil, nil, xerrors.Errorf("gathering sector info: %w", err) + return nil, nil, xerrors.Errorf("gathering sector info: %w", err) } defer done() + if len(skipped) > 0 { + return nil, skipped, xerrors.Errorf("pubSectorToPriv skipped some sectors") + } + proof, faulty, err := ffi.GenerateWindowPoSt(minerID, privsectors, randomness) var faultyIDs []abi.SectorID @@ -50,7 +54,7 @@ func (sb *Sealer) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorID, s }) } - return proof, skipped, faultyIDs, err + return proof, faultyIDs, err } func (sb *Sealer) pubSectorToPriv(ctx context.Context, mid abi.ActorID, sectorInfo []proof.SectorInfo, faults []abi.SectorNumber, rpt func(abi.RegisteredSealProof) (abi.RegisteredPoStProof, error)) (ffi.SortedPrivateSectorInfo, []abi.SectorID, func(), error) { diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index b70350ef8..7609f43b0 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -68,6 +68,7 @@ const ( type sectorState struct { pieces []cid.Cid failed bool + corrupted bool state int @@ -251,6 +252,18 @@ func (mgr *SectorMgr) MarkFailed(sid abi.SectorID, failed bool) error { return nil } +func (mgr *SectorMgr) MarkCorrupted(sid abi.SectorID, corrupted bool) error { + mgr.lk.Lock() + defer mgr.lk.Unlock() + ss, ok := mgr.sectors[sid] + if !ok { + return fmt.Errorf("no such sector in storage") + } + + ss.corrupted = corrupted + return nil +} + func opFinishWait(ctx context.Context) { val, ok := ctx.Value("opfinish").(chan struct{}) if !ok { @@ -275,6 +288,8 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI si := make([]proof.SectorInfo, 0, len(sectorInfo)) var skipped []abi.SectorID + var err error + for _, info := range sectorInfo { sid := abi.SectorID{ Miner: minerID, @@ -283,13 +298,18 @@ func (mgr *SectorMgr) GenerateWindowPoSt(ctx context.Context, minerID abi.ActorI _, found := mgr.sectors[sid] - if found && !mgr.sectors[sid].failed { + if found && !mgr.sectors[sid].failed && !mgr.sectors[sid].corrupted { si = append(si, info) } else { skipped = append(skipped, sid) + err = xerrors.Errorf("skipped some sectors") } } + if err != nil { + return nil, skipped, err + } + return generateFakePoSt(si, abi.RegisteredSealProof.RegisteredWindowPoStProof, randomness), skipped, nil } diff --git a/go.mod b/go.mod index 56c1420d0..4011577df 100644 --- a/go.mod +++ b/go.mod @@ -140,5 +140,3 @@ replace github.com/filecoin-project/test-vectors => ./extern/test-vectors replace github.com/supranational/blst => ./extern/fil-blst/blst replace github.com/filecoin-project/fil-blst => ./extern/fil-blst - -replace github.com/filecoin-project/specs-storage => ../specs-storage diff --git a/go.sum b/go.sum index 0fa13fe70..3f37bff04 100644 --- a/go.sum +++ b/go.sum @@ -250,6 +250,8 @@ github.com/filecoin-project/specs-actors v0.9.7 h1:7PAZ8kdqwBdmgf/23FCkQZLCXcVu0 github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= +github.com/filecoin-project/specs-storage v0.1.1-0.20200909213410-c066548422be h1:UX457RrC0LwL7Bb5kd0WFyzJBxbHOCSw/64oYqeT+Zc= +github.com/filecoin-project/specs-storage v0.1.1-0.20200909213410-c066548422be/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.1 h1:5fNF76nl4qolEvcIsjc0kUADlTMVHO73tW4kXXPnsus= github.com/filecoin-project/test-vectors/schema v0.0.1/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index d3e91e450..4fd4d51e6 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -335,96 +335,114 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo Proofs: nil, } - var sinfos []proof.SectorInfo - sidToPart := map[abi.SectorNumber]uint64{} skipCount := uint64(0) + postSkipped := bitfield.New() + var postOut []proof.PoStProof - for partIdx, partition := range partitions { - // TODO: Can do this in parallel - toProve, err := partition.ActiveSectors() + for retries := 0; retries < 5; retries++ { + var sinfos []proof.SectorInfo + sidToPart := map[abi.SectorNumber]int{} + + for partIdx, partition := range partitions { + // TODO: Can do this in parallel + toProve, err := partition.ActiveSectors() + if err != nil { + return nil, xerrors.Errorf("getting active sectors: %w", err) + } + + toProve, err = bitfield.MergeBitFields(toProve, partition.Recoveries) + if err != nil { + return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err) + } + + toProve, err = bitfield.SubtractBitField(toProve, postSkipped) + if err != nil { + return nil, xerrors.Errorf("toProve - postSkipped: %w", err) + } + + good, err := s.checkSectors(ctx, toProve) + if err != nil { + return nil, xerrors.Errorf("checking sectors to skip: %w", err) + } + + skipped, err := bitfield.SubtractBitField(toProve, good) + if err != nil { + return nil, xerrors.Errorf("toProve - good: %w", err) + } + + sc, err := skipped.Count() + if err != nil { + return nil, xerrors.Errorf("getting skipped sector count: %w", err) + } + + skipCount += sc + + ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts) + if err != nil { + return nil, xerrors.Errorf("getting sorted sector info: %w", err) + } + + if len(ssi) == 0 { + continue + } + + sinfos = append(sinfos, ssi...) + for _, si := range ssi { + sidToPart[si.SectorNumber] = partIdx + } + + params.Partitions = append(params.Partitions, miner.PoStPartition{ + Index: uint64(partIdx), + Skipped: skipped, + }) + } + + if len(sinfos) == 0 { + // nothing to prove.. + return nil, errNoPartitions + } + + log.Infow("running windowPost", + "chain-random", rand, + "deadline", di, + "height", ts.Height(), + "skipped", skipCount) + + tsStart := build.Clock.Now() + + mid, err := address.IDFromAddress(s.actor) if err != nil { - return nil, xerrors.Errorf("getting active sectors: %w", err) + return nil, err } - toProve, err = bitfield.MergeBitFields(toProve, partition.Recoveries) - if err != nil { - return nil, xerrors.Errorf("adding recoveries to set of sectors to prove: %w", err) + var ps []abi.SectorID + postOut, ps, err = s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) + elapsed := time.Since(tsStart) + + log.Infow("computing window PoSt", "elapsed", elapsed) + + if err == nil { + break } - good, err := s.checkSectors(ctx, toProve) - if err != nil { - return nil, xerrors.Errorf("checking sectors to skip: %w", err) + if len(ps) == 0 { + return nil, xerrors.Errorf("running post failed: %w", err) } - skipped, err := bitfield.SubtractBitField(toProve, good) - if err != nil { - return nil, xerrors.Errorf("toProve - good: %w", err) + log.Warnw("generate window PoSt skipped sectors", "sectors", ps, "error", err, "try", retries) + + skipCount += uint64(len(ps)) + for _, sector := range ps { + postSkipped.Set(uint64(sector.Number)) } - - sc, err := skipped.Count() - if err != nil { - return nil, xerrors.Errorf("getting skipped sector count: %w", err) - } - - skipCount += sc - - ssi, err := s.sectorsForProof(ctx, good, partition.Sectors, ts) - if err != nil { - return nil, xerrors.Errorf("getting sorted sector info: %w", err) - } - - if len(ssi) == 0 { - continue - } - - sinfos = append(sinfos, ssi...) - for _, si := range ssi { - sidToPart[si.SectorNumber] = uint64(partIdx) - } - - params.Partitions = append(params.Partitions, miner.PoStPartition{ - Index: uint64(partIdx), - Skipped: skipped, - }) } - if len(sinfos) == 0 { - // nothing to prove.. - return nil, errNoPartitions - } - - log.Infow("running windowPost", - "chain-random", rand, - "deadline", di, - "height", ts.Height(), - "skipped", skipCount) - - tsStart := build.Clock.Now() - - mid, err := address.IDFromAddress(s.actor) - if err != nil { - return nil, err - } - - postOut, postSkipped, faulty, err := s.prover.GenerateWindowPoSt(ctx, abi.ActorID(mid), sinfos, abi.PoStRandomness(rand)) - if err != nil { - return nil, xerrors.Errorf("running post failed: %w", err) - } - - _ = faulty // TODO(magik) - if len(postOut) == 0 { - return nil, xerrors.Errorf("received proofs back from generate window post") + return nil, xerrors.Errorf("received no proofs back from generate window post") } params.Proofs = postOut - for _, sector := range postSkipped { - params.Partitions[sidToPart[sector.Number]].Skipped.Set(uint64(sector.Number)) - } - - elapsed := time.Since(tsStart) - commEpoch := di.Open commRand, err := s.api.ChainGetRandomnessFromTickets(ctx, ts.Key(), crypto.DomainSeparationTag_PoStChainCommit, commEpoch, nil) if err != nil { @@ -433,7 +451,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo params.ChainCommitEpoch = commEpoch params.ChainCommitRand = commRand - log.Infow("submitting window PoSt", "elapsed", elapsed) + log.Infow("submitting window PoSt") return params, nil } From 558b637b07ab42cc39b01ec36fa76f0130d24e74 Mon Sep 17 00:00:00 2001 From: lanzafame Date: Thu, 10 Sep 2020 13:52:21 +1000 Subject: [PATCH 145/199] Increase the number of times precommit2 is attempted before moving back to precommit1 --- extern/storage-sealing/states_failed.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/storage-sealing/states_failed.go b/extern/storage-sealing/states_failed.go index 57a93a773..4dd945a81 100644 --- a/extern/storage-sealing/states_failed.go +++ b/extern/storage-sealing/states_failed.go @@ -62,7 +62,7 @@ func (m *Sealing) handleSealPrecommit2Failed(ctx statemachine.Context, sector Se return err } - if sector.PreCommit2Fails > 1 { + if sector.PreCommit2Fails > 3 { return ctx.Send(SectorRetrySealPreCommit1{}) } From 72c7d4c886dd3bdf4afd753ee17469d8ba3fffb2 Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 10 Sep 2020 09:55:50 +0300 Subject: [PATCH 146/199] relax mpool add strictness checks for local pushes So that a node can have more than 1k pending messages for its own local addresses. --- chain/messagepool/messagepool.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 64add44d7..06cbe65e7 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -590,7 +590,7 @@ func (mp *MessagePool) addTs(m *types.SignedMessage, curTs *types.TipSet, local return false, err } - return publish, mp.addLocked(m, true) + return publish, mp.addLocked(m, !local) } func (mp *MessagePool) addLoaded(m *types.SignedMessage) error { @@ -812,7 +812,7 @@ func (mp *MessagePool) PushWithNonce(ctx context.Context, addr address.Address, return nil, err } - if err := mp.addLocked(msg, true); err != nil { + if err := mp.addLocked(msg, false); err != nil { return nil, xerrors.Errorf("add locked failed: %w", err) } if err := mp.addLocal(msg, msgb); err != nil { From 9e5bce90f410a8626f2127f7cc9c19b441475a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Kripalani?= Date: Thu, 10 Sep 2020 10:41:18 +0100 Subject: [PATCH 147/199] ci: fix statediff build; make optional. --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b7e72bf4a..d8c7abf16 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -231,11 +231,11 @@ jobs: - run: name: install statediff globally command: | + ## statediff is optional; we succeed even if compilation fails. mkdir -p /tmp/statediff git clone https://github.com/filecoin-project/statediff.git /tmp/statediff cd /tmp/statediff - go generate ./... - go install ./cmd/statediff + go install ./cmd/statediff || exit 0 - run: name: go test environment: From f3cae55bd44e069e1cab7ad9c5770cbf8b47b8aa Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Wed, 9 Sep 2020 11:40:30 +0100 Subject: [PATCH 148/199] feat: chaos abort --- conformance/chaos/actor.go | 22 +++++++ conformance/chaos/cbor_gen.go | 116 ++++++++++++++++++++++++++++++++++ conformance/chaos/gen/gen.go | 1 + 3 files changed, 139 insertions(+) diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index ed7a230c7..f162b2c8f 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -62,6 +62,9 @@ const ( // MethodMutateState is the identifier for the method that attempts to mutate // a state value in the actor. MethodMutateState + // MethodAbort is the identifier for the method that panics optionally with + // a passed exit code. + MethodAbort ) // Exports defines the methods this actor exposes publicly. @@ -74,6 +77,7 @@ func (a Actor) Exports() []interface{} { MethodDeleteActor: a.DeleteActor, MethodSend: a.Send, MethodMutateState: a.MutateState, + MethodAbort: a.Abort, } } @@ -230,3 +234,21 @@ func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *adt.Empty } return nil } + +// AbortArgs are the arguments to the abort method, specifying the exit code to +// (optionally) abort with and the message. +type AbortArgs struct { + Code exitcode.ExitCode + NoCode bool + Message string +} + +// Abort simply causes a panic or abort with the passed exit code. +func (a Actor) Abort(rt runtime.Runtime, args *AbortArgs) *adt.EmptyValue { + if args.NoCode { // no code, just plain old panic + panic(args.Message) + } else { + rt.Abortf(args.Code, args.Message) + } + return nil +} diff --git a/conformance/chaos/cbor_gen.go b/conformance/chaos/cbor_gen.go index 9f01ccce7..00825c8f3 100644 --- a/conformance/chaos/cbor_gen.go +++ b/conformance/chaos/cbor_gen.go @@ -614,3 +614,119 @@ func (t *MutateStateArgs) UnmarshalCBOR(r io.Reader) error { } return nil } + +var lengthBufAbortArgs = []byte{131} + +func (t *AbortArgs) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write(lengthBufAbortArgs); err != nil { + return err + } + + scratch := make([]byte, 9) + + // t.Code (exitcode.ExitCode) (int64) + if t.Code >= 0 { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajUnsignedInt, uint64(t.Code)); err != nil { + return err + } + } else { + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajNegativeInt, uint64(-t.Code-1)); err != nil { + return err + } + } + + // t.NoCode (bool) (bool) + if err := cbg.WriteBool(w, t.NoCode); err != nil { + return err + } + + // t.Message (string) (string) + if len(t.Message) > cbg.MaxLength { + return xerrors.Errorf("Value in field t.Message was too long") + } + + if err := cbg.WriteMajorTypeHeaderBuf(scratch, w, cbg.MajTextString, uint64(len(t.Message))); err != nil { + return err + } + if _, err := io.WriteString(w, string(t.Message)); err != nil { + return err + } + return nil +} + +func (t *AbortArgs) UnmarshalCBOR(r io.Reader) error { + *t = AbortArgs{} + + br := cbg.GetPeeker(r) + scratch := make([]byte, 8) + + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 3 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.Code (exitcode.ExitCode) (int64) + { + maj, extra, err := cbg.CborReadHeaderBuf(br, scratch) + var extraI int64 + if err != nil { + return err + } + switch maj { + case cbg.MajUnsignedInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 positive overflow") + } + case cbg.MajNegativeInt: + extraI = int64(extra) + if extraI < 0 { + return fmt.Errorf("int64 negative oveflow") + } + extraI = -1 - extraI + default: + return fmt.Errorf("wrong type for int64 field: %d", maj) + } + + t.Code = exitcode.ExitCode(extraI) + } + // t.NoCode (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.NoCode = false + case 21: + t.NoCode = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } + // t.Message (string) (string) + + { + sval, err := cbg.ReadStringBuf(br, scratch) + if err != nil { + return err + } + + t.Message = string(sval) + } + return nil +} diff --git a/conformance/chaos/gen/gen.go b/conformance/chaos/gen/gen.go index 308fed11e..dbf8463d4 100644 --- a/conformance/chaos/gen/gen.go +++ b/conformance/chaos/gen/gen.go @@ -14,6 +14,7 @@ func main() { chaos.SendArgs{}, chaos.SendReturn{}, chaos.MutateStateArgs{}, + chaos.AbortArgs{}, ); err != nil { panic(err) } From b755ce9528e4060d400e61648fb26f5049197dcd Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 10 Sep 2020 12:03:13 +0100 Subject: [PATCH 149/199] refactor: renames --- conformance/chaos/actor.go | 20 ++++++------- conformance/chaos/cbor_gen.go | 54 +++++++++++++++++------------------ conformance/chaos/gen/gen.go | 2 +- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index f162b2c8f..3792a4bfe 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -77,7 +77,7 @@ func (a Actor) Exports() []interface{} { MethodDeleteActor: a.DeleteActor, MethodSend: a.Send, MethodMutateState: a.MutateState, - MethodAbort: a.Abort, + MethodAbort: a.AbortWith, } } @@ -235,17 +235,17 @@ func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *adt.Empty return nil } -// AbortArgs are the arguments to the abort method, specifying the exit code to -// (optionally) abort with and the message. -type AbortArgs struct { - Code exitcode.ExitCode - NoCode bool - Message string +// AbortWithArgs are the arguments to the Actor.AbortWith method, specifying the +// exit code to (optionally) abort with and the message. +type AbortWithArgs struct { + Code exitcode.ExitCode + Message string + Uncontrolled bool } -// Abort simply causes a panic or abort with the passed exit code. -func (a Actor) Abort(rt runtime.Runtime, args *AbortArgs) *adt.EmptyValue { - if args.NoCode { // no code, just plain old panic +// AbortWith simply causes a panic with the passed exit code. +func (a Actor) AbortWith(rt runtime.Runtime, args *AbortWithArgs) *adt.EmptyValue { + if args.Uncontrolled { // uncontrolled abort: directly panic panic(args.Message) } else { rt.Abortf(args.Code, args.Message) diff --git a/conformance/chaos/cbor_gen.go b/conformance/chaos/cbor_gen.go index 00825c8f3..710b84b93 100644 --- a/conformance/chaos/cbor_gen.go +++ b/conformance/chaos/cbor_gen.go @@ -615,14 +615,14 @@ func (t *MutateStateArgs) UnmarshalCBOR(r io.Reader) error { return nil } -var lengthBufAbortArgs = []byte{131} +var lengthBufAbortWithArgs = []byte{131} -func (t *AbortArgs) MarshalCBOR(w io.Writer) error { +func (t *AbortWithArgs) MarshalCBOR(w io.Writer) error { if t == nil { _, err := w.Write(cbg.CborNull) return err } - if _, err := w.Write(lengthBufAbortArgs); err != nil { + if _, err := w.Write(lengthBufAbortWithArgs); err != nil { return err } @@ -639,11 +639,6 @@ func (t *AbortArgs) MarshalCBOR(w io.Writer) error { } } - // t.NoCode (bool) (bool) - if err := cbg.WriteBool(w, t.NoCode); err != nil { - return err - } - // t.Message (string) (string) if len(t.Message) > cbg.MaxLength { return xerrors.Errorf("Value in field t.Message was too long") @@ -655,11 +650,16 @@ func (t *AbortArgs) MarshalCBOR(w io.Writer) error { if _, err := io.WriteString(w, string(t.Message)); err != nil { return err } + + // t.Uncontrolled (bool) (bool) + if err := cbg.WriteBool(w, t.Uncontrolled); err != nil { + return err + } return nil } -func (t *AbortArgs) UnmarshalCBOR(r io.Reader) error { - *t = AbortArgs{} +func (t *AbortWithArgs) UnmarshalCBOR(r io.Reader) error { + *t = AbortWithArgs{} br := cbg.GetPeeker(r) scratch := make([]byte, 8) @@ -701,23 +701,6 @@ func (t *AbortArgs) UnmarshalCBOR(r io.Reader) error { t.Code = exitcode.ExitCode(extraI) } - // t.NoCode (bool) (bool) - - maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) - if err != nil { - return err - } - if maj != cbg.MajOther { - return fmt.Errorf("booleans must be major type 7") - } - switch extra { - case 20: - t.NoCode = false - case 21: - t.NoCode = true - default: - return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) - } // t.Message (string) (string) { @@ -728,5 +711,22 @@ func (t *AbortArgs) UnmarshalCBOR(r io.Reader) error { t.Message = string(sval) } + // t.Uncontrolled (bool) (bool) + + maj, extra, err = cbg.CborReadHeaderBuf(br, scratch) + if err != nil { + return err + } + if maj != cbg.MajOther { + return fmt.Errorf("booleans must be major type 7") + } + switch extra { + case 20: + t.Uncontrolled = false + case 21: + t.Uncontrolled = true + default: + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) + } return nil } diff --git a/conformance/chaos/gen/gen.go b/conformance/chaos/gen/gen.go index dbf8463d4..97ea98dc8 100644 --- a/conformance/chaos/gen/gen.go +++ b/conformance/chaos/gen/gen.go @@ -14,7 +14,7 @@ func main() { chaos.SendArgs{}, chaos.SendReturn{}, chaos.MutateStateArgs{}, - chaos.AbortArgs{}, + chaos.AbortWithArgs{}, ); err != nil { panic(err) } From 0e7f14159ae04b9a1a6892297613b5c514a6b191 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 10 Sep 2020 12:06:00 +0100 Subject: [PATCH 150/199] refactor: another rename --- conformance/chaos/actor.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index 3792a4bfe..f3da42bb6 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -62,9 +62,9 @@ const ( // MethodMutateState is the identifier for the method that attempts to mutate // a state value in the actor. MethodMutateState - // MethodAbort is the identifier for the method that panics optionally with + // MethodAbortWith is the identifier for the method that panics optionally with // a passed exit code. - MethodAbort + MethodAbortWith ) // Exports defines the methods this actor exposes publicly. @@ -77,7 +77,7 @@ func (a Actor) Exports() []interface{} { MethodDeleteActor: a.DeleteActor, MethodSend: a.Send, MethodMutateState: a.MutateState, - MethodAbort: a.AbortWith, + MethodAbortWith: a.AbortWith, } } From bfa47b36633985fb0174e21bbaf99305e34436fb Mon Sep 17 00:00:00 2001 From: vyzo Date: Thu, 10 Sep 2020 16:11:23 +0300 Subject: [PATCH 151/199] update go-libp2p-pubsub@master --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index bc4067d67..903cfaae4 100644 --- a/go.mod +++ b/go.mod @@ -92,7 +92,7 @@ require ( github.com/libp2p/go-libp2p-mplex v0.2.4 github.com/libp2p/go-libp2p-noise v0.1.1 github.com/libp2p/go-libp2p-peerstore v0.2.6 - github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb + github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18 github.com/libp2p/go-libp2p-quic-transport v0.8.0 github.com/libp2p/go-libp2p-record v0.1.3 github.com/libp2p/go-libp2p-routing-helpers v0.2.3 diff --git a/go.sum b/go.sum index 0fa13fe70..39970d325 100644 --- a/go.sum +++ b/go.sum @@ -843,8 +843,8 @@ github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1 github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= github.com/libp2p/go-libp2p-pubsub v0.1.1/go.mod h1:ZwlKzRSe1eGvSIdU5bD7+8RZN/Uzw0t1Bp9R1znpR/Q= github.com/libp2p/go-libp2p-pubsub v0.3.2-0.20200527132641-c0712c6e92cf/go.mod h1:TxPOBuo1FPdsTjFnv+FGZbNbWYsp74Culx+4ViQpato= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb h1:0jm9ZSDkteX9XRjZqZwG5X0wuR+e0zAJ6ZEnqo2vcb0= -github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200907103802-a3445b756fdb/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18 h1:+ae7vHSv/PJ4xGXwLV6LKGj32zjyB8ttJHtyV4TXal0= +github.com/libp2p/go-libp2p-pubsub v0.3.6-0.20200910093904-f7f33e10cc18/go.mod h1:DTMSVmZZfXodB/pvdTGrY2eHPZ9W2ev7hzTH83OKHrI= github.com/libp2p/go-libp2p-quic-transport v0.1.1/go.mod h1:wqG/jzhF3Pu2NrhJEvE+IE0NTHNXslOPn9JQzyCAxzU= github.com/libp2p/go-libp2p-quic-transport v0.5.0/go.mod h1:IEcuC5MLxvZ5KuHKjRu+dr3LjCT1Be3rcD/4d8JrX8M= github.com/libp2p/go-libp2p-quic-transport v0.8.0 h1:mHA94K2+TD0e9XtjWx/P5jGGZn0GdQ4OFYwNllagv4E= From d4b185be5ebda7e48dd2cd18c8bae5480c9027c4 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 10 Sep 2020 14:22:25 +0100 Subject: [PATCH 152/199] test: add chaos actor tests --- conformance/chaos/actor_test.go | 152 ++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 conformance/chaos/actor_test.go diff --git a/conformance/chaos/actor_test.go b/conformance/chaos/actor_test.go new file mode 100644 index 000000000..3503bf0b8 --- /dev/null +++ b/conformance/chaos/actor_test.go @@ -0,0 +1,152 @@ +package chaos + +import ( + "context" + "github.com/filecoin-project/go-state-types/exitcode" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/specs-actors/support/mock" + atesting "github.com/filecoin-project/specs-actors/support/testing" + "testing" +) + +func TestSingleton(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + a := Actor{} + + msg := "constructor should not be called; the Chaos actor is a singleton actor" + rt.ExpectAssertionFailure(msg, func() { + rt.Call(a.Constructor, adt.Empty) + }) + rt.Verify() +} + +func TestDeleteActor(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + beneficiary := atesting.NewIDAddr(t, 101) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + a := Actor{} + + rt.ExpectValidateCallerAny() + rt.ExpectDeleteActor(beneficiary) + rt.Call(a.DeleteActor, &beneficiary) + rt.Verify() +} + +func TestMutateStateInTransaction(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + a := Actor{} + + rt.ExpectValidateCallerAny() + rt.Create(&State{}) + + val := "__mutstat test" + rt.Call(a.MutateState, &MutateStateArgs{ + Value: val, + Branch: MutateInTransaction, + }) + + var st State + rt.GetState(&st) + + if st.Value != val { + t.Fatal("state was not updated") + } + + rt.Verify() +} + +func TestMutateStateAfterTransaction(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + a := Actor{} + + rt.ExpectValidateCallerAny() + rt.Create(&State{}) + + val := "__mutstat test" + rt.Call(a.MutateState, &MutateStateArgs{ + Value: val, + Branch: MutateAfterTransaction, + }) + + var st State + rt.GetState(&st) + + // state should be updated successfully _in_ the transaction but not outside + if st.Value != val+"-in" { + t.Fatal("state was not updated") + } + + rt.Verify() +} + +func TestMutateStateReadonly(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + a := Actor{} + + rt.ExpectValidateCallerAny() + rt.Create(&State{}) + + val := "__mutstat test" + rt.Call(a.MutateState, &MutateStateArgs{ + Value: val, + Branch: MutateReadonly, + }) + + var st State + rt.GetState(&st) + + if st.Value != "" { + t.Fatal("state was not expected to be updated") + } + + rt.Verify() +} + +func TestAbortWith(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + a := Actor{} + + msg := "__test forbidden" + rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, msg, func() { + rt.Call(a.AbortWith, &AbortWithArgs{ + Code: exitcode.ErrForbidden, + Message: msg, + Uncontrolled: false, + }) + }) + rt.Verify() +} + +func TestAbortWithUncontrolled(t *testing.T) { + receiver := atesting.NewIDAddr(t, 100) + builder := mock.NewBuilder(context.Background(), receiver) + + rt := builder.Build(t) + a := Actor{} + + msg := "__test uncontrolled panic" + rt.ExpectAssertionFailure(msg, func() { + rt.Call(a.AbortWith, &AbortWithArgs{ + Message: msg, + Uncontrolled: true, + }) + }) + rt.Verify() +} From a214069586f38d4b7c217df9bbd42079180a515e Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 10 Sep 2020 14:30:52 +0100 Subject: [PATCH 153/199] chore: appease linter --- conformance/chaos/actor_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conformance/chaos/actor_test.go b/conformance/chaos/actor_test.go index 3503bf0b8..ac49b8670 100644 --- a/conformance/chaos/actor_test.go +++ b/conformance/chaos/actor_test.go @@ -2,11 +2,12 @@ package chaos import ( "context" + "testing" + "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/support/mock" atesting "github.com/filecoin-project/specs-actors/support/testing" - "testing" ) func TestSingleton(t *testing.T) { From c94ff3430ca4d2ba84ed635b07183a4c23e338a0 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 10 Sep 2020 14:51:30 +0100 Subject: [PATCH 154/199] refactor: use nil value --- conformance/chaos/actor_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/conformance/chaos/actor_test.go b/conformance/chaos/actor_test.go index ac49b8670..97c3b85cf 100644 --- a/conformance/chaos/actor_test.go +++ b/conformance/chaos/actor_test.go @@ -15,7 +15,7 @@ func TestSingleton(t *testing.T) { builder := mock.NewBuilder(context.Background(), receiver) rt := builder.Build(t) - a := Actor{} + var a Actor msg := "constructor should not be called; the Chaos actor is a singleton actor" rt.ExpectAssertionFailure(msg, func() { @@ -30,7 +30,7 @@ func TestDeleteActor(t *testing.T) { builder := mock.NewBuilder(context.Background(), receiver) rt := builder.Build(t) - a := Actor{} + var a Actor rt.ExpectValidateCallerAny() rt.ExpectDeleteActor(beneficiary) @@ -43,7 +43,7 @@ func TestMutateStateInTransaction(t *testing.T) { builder := mock.NewBuilder(context.Background(), receiver) rt := builder.Build(t) - a := Actor{} + var a Actor rt.ExpectValidateCallerAny() rt.Create(&State{}) @@ -69,7 +69,7 @@ func TestMutateStateAfterTransaction(t *testing.T) { builder := mock.NewBuilder(context.Background(), receiver) rt := builder.Build(t) - a := Actor{} + var a Actor rt.ExpectValidateCallerAny() rt.Create(&State{}) @@ -96,7 +96,7 @@ func TestMutateStateReadonly(t *testing.T) { builder := mock.NewBuilder(context.Background(), receiver) rt := builder.Build(t) - a := Actor{} + var a Actor rt.ExpectValidateCallerAny() rt.Create(&State{}) @@ -122,7 +122,7 @@ func TestAbortWith(t *testing.T) { builder := mock.NewBuilder(context.Background(), receiver) rt := builder.Build(t) - a := Actor{} + var a Actor msg := "__test forbidden" rt.ExpectAbortContainsMessage(exitcode.ErrForbidden, msg, func() { @@ -140,7 +140,7 @@ func TestAbortWithUncontrolled(t *testing.T) { builder := mock.NewBuilder(context.Background(), receiver) rt := builder.Build(t) - a := Actor{} + var a Actor msg := "__test uncontrolled panic" rt.ExpectAssertionFailure(msg, func() { From dc85a276cdca4064b1e4187e8e49095b63d814b4 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 10 Sep 2020 19:17:48 +0200 Subject: [PATCH 155/199] Upgrade badger Signed-off-by: Jakub Sztandera --- go.mod | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 903cfaae4..ac5106e1a 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129 github.com/coreos/go-systemd/v22 v22.0.0 github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e - github.com/dgraph-io/badger/v2 v2.0.3 + github.com/dgraph-io/badger/v2 v2.2007.2 github.com/docker/go-units v0.4.0 github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4 github.com/drand/kyber v1.1.1 @@ -135,6 +135,4 @@ replace github.com/golangci/golangci-lint => github.com/golangci/golangci-lint v replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi -replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 - replace github.com/filecoin-project/test-vectors => ./extern/test-vectors From c7b0241a48b5f503cfc7a32e3ce2602e412a0fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 10 Sep 2020 21:19:26 +0200 Subject: [PATCH 156/199] ffiwrapper: Test skipping corrupted sectors in PoSt --- .../sector-storage/ffiwrapper/sealer_test.go | 87 ++++++++++--------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/extern/sector-storage/ffiwrapper/sealer_test.go b/extern/sector-storage/ffiwrapper/sealer_test.go index ae1ede7eb..acbd9ca21 100644 --- a/extern/sector-storage/ffiwrapper/sealer_test.go +++ b/extern/sector-storage/ffiwrapper/sealer_test.go @@ -168,50 +168,34 @@ func (s *seal) unseal(t *testing.T, sb *Sealer, sp *basicfs.Provider, si abi.Sec } } -func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time { - /*randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7} +func post(t *testing.T, sealer *Sealer, skipped []abi.SectorID, seals ...seal) { + randomness := abi.PoStRandomness{0, 9, 2, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 45, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 7} - sis := make([]abi.SectorInfo, len(seals)) + sis := make([]saproof.SectorInfo, len(seals)) for i, s := range seals { - sis[i] = abi.SectorInfo{ - RegisteredProof: sealProofType, + sis[i] = saproof.SectorInfo{ + SealProof: sealProofType, SectorNumber: s.id.Number, SealedCID: s.cids.Sealed, } } - candidates, err := sealer.GenerateEPostCandidates(context.TODO(), seals[0].id.Miner, sis, randomness, []abi.SectorNumber{}) - if err != nil { - t.Fatalf("%+v", err) - }*/ - - fmt.Println("skipping post") - - genCandidates := time.Now() - - /*if len(candidates) != 1 { - t.Fatal("expected 1 candidate") + proofs, skp, err := sealer.GenerateWindowPoSt(context.TODO(), seals[0].id.Miner, sis, randomness) + if len(skipped) > 0 { + require.Error(t, err) + require.EqualValues(t, skipped, skp) + return } - candidatesPrime := make([]abi.PoStCandidate, len(candidates)) - for idx := range candidatesPrime { - candidatesPrime[idx] = candidates[idx].Candidate - } - - proofs, err := sealer.ComputeElectionPoSt(context.TODO(), seals[0].id.Miner, sis, randomness, candidatesPrime) if err != nil { t.Fatalf("%+v", err) } - ePoStChallengeCount := ElectionPostChallengeCount(uint64(len(sis)), 0) - - ok, err := ProofVerifier.VerifyElectionPost(context.TODO(), abi.PoStVerifyInfo{ + ok, err := ProofVerifier.VerifyWindowPoSt(context.TODO(), saproof.WindowPoStVerifyInfo{ Randomness: randomness, - Candidates: candidatesPrime, Proofs: proofs, - EligibleSectors: sis, + ChallengedSectors: sis, Prover: seals[0].id.Miner, - ChallengeCount: ePoStChallengeCount, }) if err != nil { t.Fatalf("%+v", err) @@ -219,8 +203,21 @@ func post(t *testing.T, sealer *Sealer, seals ...seal) time.Time { if !ok { t.Fatal("bad post") } - */ - return genCandidates +} + +func corrupt(t *testing.T, sealer *Sealer, id abi.SectorID) { + paths, done, err := sealer.sectors.AcquireSector(context.Background(), id, stores.FTSealed, 0, stores.PathStorage) + require.NoError(t, err) + defer done() + + log.Infof("corrupt %s", paths.Sealed) + f, err := os.OpenFile(paths.Sealed, os.O_RDWR, 0664) + require.NoError(t, err) + + _, err = f.WriteAt(bytes.Repeat([]byte{'d'}, 2048), 0) + require.NoError(t, err) + + require.NoError(t, f.Close()) } func getGrothParamFileAndVerifyingKeys(s abi.SectorSize) { @@ -299,11 +296,11 @@ func TestSealAndVerify(t *testing.T) { commit := time.Now() - genCandidiates := post(t, sb, s) + post(t, sb, nil, s) epost := time.Now() - post(t, sb, s) + post(t, sb, nil, s) if err := sb.FinalizeSector(context.TODO(), si, nil); err != nil { t.Fatalf("%+v", err) @@ -313,8 +310,7 @@ func TestSealAndVerify(t *testing.T) { fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String()) fmt.Printf("Commit: %s\n", commit.Sub(precommit).String()) - fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(commit).String()) - fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String()) + fmt.Printf("EPoSt: %s\n", epost.Sub(commit).String()) } func TestSealPoStNoCommit(t *testing.T) { @@ -370,16 +366,15 @@ func TestSealPoStNoCommit(t *testing.T) { t.Fatal(err) } - genCandidiates := post(t, sb, s) + post(t, sb, nil, s) epost := time.Now() fmt.Printf("PreCommit: %s\n", precommit.Sub(start).String()) - fmt.Printf("GenCandidates: %s\n", genCandidiates.Sub(precommit).String()) - fmt.Printf("EPoSt: %s\n", epost.Sub(genCandidiates).String()) + fmt.Printf("EPoSt: %s\n", epost.Sub(precommit).String()) } -func TestSealAndVerify2(t *testing.T) { +func TestSealAndVerify3(t *testing.T) { defer requireFDsClosed(t, openFDs(t)) if runtime.NumCPU() < 10 && os.Getenv("CI") == "" { // don't bother on slow hardware @@ -419,22 +414,32 @@ func TestSealAndVerify2(t *testing.T) { si1 := abi.SectorID{Miner: miner, Number: 1} si2 := abi.SectorID{Miner: miner, Number: 2} + si3 := abi.SectorID{Miner: miner, Number: 3} s1 := seal{id: si1} s2 := seal{id: si2} + s3 := seal{id: si3} - wg.Add(2) + wg.Add(3) go s1.precommit(t, sb, si1, wg.Done) //nolint: staticcheck time.Sleep(100 * time.Millisecond) go s2.precommit(t, sb, si2, wg.Done) //nolint: staticcheck + time.Sleep(100 * time.Millisecond) + go s3.precommit(t, sb, si3, wg.Done) //nolint: staticcheck wg.Wait() - wg.Add(2) + wg.Add(3) go s1.commit(t, sb, wg.Done) //nolint: staticcheck go s2.commit(t, sb, wg.Done) //nolint: staticcheck + go s3.commit(t, sb, wg.Done) //nolint: staticcheck wg.Wait() - post(t, sb, s1, s2) + post(t, sb, nil, s1, s2, s3) + + corrupt(t, sb, si1) + corrupt(t, sb, si2) + + post(t, sb, []abi.SectorID{si1, si2}, s1, s2, s3) } func BenchmarkWriteWithAlignment(b *testing.B) { From 2374cb1bc599cfab8c0a62707fc4b6ec15f4568c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 10 Sep 2020 21:44:01 +0200 Subject: [PATCH 157/199] Update ffi --- extern/filecoin-ffi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/filecoin-ffi b/extern/filecoin-ffi index 79b324966..f640612a1 160000 --- a/extern/filecoin-ffi +++ b/extern/filecoin-ffi @@ -1 +1 @@ -Subproject commit 79b3249666a809871fad12fbf50f68e22218b01c +Subproject commit f640612a1a1f7a2dd8b3a49e1531db0aa0f63447 From 22556fb24c99c44390c914597e75d18357758647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 10 Sep 2020 22:04:08 +0200 Subject: [PATCH 158/199] Add fil-blst submodule --- .gitmodules | 3 +++ extern/fil-blst | 1 + 2 files changed, 4 insertions(+) create mode 160000 extern/fil-blst diff --git a/.gitmodules b/.gitmodules index ad09aba35..4b450aaf3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,3 +8,6 @@ [submodule "extern/test-vectors"] path = extern/test-vectors url = https://github.com/filecoin-project/test-vectors.git +[submodule "extern/fil-blst"] + path = extern/fil-blst + url = https://github.com/filecoin-project/fil-blst.git diff --git a/extern/fil-blst b/extern/fil-blst new file mode 160000 index 000000000..5f93488fc --- /dev/null +++ b/extern/fil-blst @@ -0,0 +1 @@ +Subproject commit 5f93488fc0dbfb450f2355269f18fc67010d59bb From bbac86f7454222adb1b4a89880b7625270ca4eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Thu, 10 Sep 2020 22:07:20 +0200 Subject: [PATCH 159/199] gofmt, mod tidy --- extern/sector-storage/ffiwrapper/sealer_test.go | 12 ++++++------ extern/sector-storage/mock/mock.go | 4 ++-- go.sum | 4 ---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/extern/sector-storage/ffiwrapper/sealer_test.go b/extern/sector-storage/ffiwrapper/sealer_test.go index acbd9ca21..d59de2cab 100644 --- a/extern/sector-storage/ffiwrapper/sealer_test.go +++ b/extern/sector-storage/ffiwrapper/sealer_test.go @@ -174,9 +174,9 @@ func post(t *testing.T, sealer *Sealer, skipped []abi.SectorID, seals ...seal) { sis := make([]saproof.SectorInfo, len(seals)) for i, s := range seals { sis[i] = saproof.SectorInfo{ - SealProof: sealProofType, - SectorNumber: s.id.Number, - SealedCID: s.cids.Sealed, + SealProof: sealProofType, + SectorNumber: s.id.Number, + SealedCID: s.cids.Sealed, } } @@ -192,10 +192,10 @@ func post(t *testing.T, sealer *Sealer, skipped []abi.SectorID, seals ...seal) { } ok, err := ProofVerifier.VerifyWindowPoSt(context.TODO(), saproof.WindowPoStVerifyInfo{ - Randomness: randomness, - Proofs: proofs, + Randomness: randomness, + Proofs: proofs, ChallengedSectors: sis, - Prover: seals[0].id.Miner, + Prover: seals[0].id.Miner, }) if err != nil { t.Fatalf("%+v", err) diff --git a/extern/sector-storage/mock/mock.go b/extern/sector-storage/mock/mock.go index 7609f43b0..64207e66d 100644 --- a/extern/sector-storage/mock/mock.go +++ b/extern/sector-storage/mock/mock.go @@ -66,8 +66,8 @@ const ( ) type sectorState struct { - pieces []cid.Cid - failed bool + pieces []cid.Cid + failed bool corrupted bool state int diff --git a/go.sum b/go.sum index 3f37bff04..953e3bba6 100644 --- a/go.sum +++ b/go.sum @@ -250,8 +250,6 @@ github.com/filecoin-project/specs-actors v0.9.7 h1:7PAZ8kdqwBdmgf/23FCkQZLCXcVu0 github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= -github.com/filecoin-project/specs-storage v0.1.1-0.20200909213410-c066548422be h1:UX457RrC0LwL7Bb5kd0WFyzJBxbHOCSw/64oYqeT+Zc= -github.com/filecoin-project/specs-storage v0.1.1-0.20200909213410-c066548422be/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.1 h1:5fNF76nl4qolEvcIsjc0kUADlTMVHO73tW4kXXPnsus= github.com/filecoin-project/test-vectors/schema v0.0.1/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= @@ -1318,8 +1316,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/supranational/blst v0.1.2-alpha.1 h1:v0UqVlvbRNZIaSeMPr+T01kvTUq1h0EZuZ6gnDR1Mlg= -github.com/supranational/blst v0.1.2-alpha.1/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= From df5750a21c8f9487abe3284274a7fb040d2cdd9a Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 10 Sep 2020 23:15:56 +0200 Subject: [PATCH 160/199] go mod tidy Signed-off-by: Jakub Sztandera --- go.sum | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/go.sum b/go.sum index 39970d325..1c9723ba1 100644 --- a/go.sum +++ b/go.sum @@ -166,8 +166,10 @@ github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhY github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.1 h1:w9pSFNSdq/JPM1N12Fz/F/bzo993Is1W+Q7HjPzi7yg= github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= -github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 h1:PIPH4SLjYXMMlX/cQqV7nIRatv7556yqUfWY+KBjrtQ= -github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM= +github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k= +github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= +github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= From 2d3f92aeed04790fab02b5d9180614fe714b1756 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Tue, 8 Sep 2020 22:28:06 +0200 Subject: [PATCH 161/199] Introduce beacon Schedule Signed-off-by: Jakub Sztandera --- chain/beacon/beacon.go | 32 ++++++++++++++++++++++++++++---- chain/gen/gen.go | 8 ++++---- chain/stmgr/utils.go | 4 ++-- chain/sync.go | 6 +++--- node/impl/full/state.go | 2 +- node/modules/chain.go | 2 +- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/chain/beacon/beacon.go b/chain/beacon/beacon.go index 5f8a18951..0932c0c2a 100644 --- a/chain/beacon/beacon.go +++ b/chain/beacon/beacon.go @@ -18,6 +18,23 @@ type Response struct { Err error } +type Schedule []BeaconPoint + +func (bs Schedule) BeaconForEpoch(e abi.ChainEpoch) RandomBeacon { + for i := len(bs) - 1; i >= 0; i-- { + bp := bs[i] + if e > bp.Start { + return bp.Beacon + } + } + return bs[0].Beacon +} + +type BeaconPoint struct { + Start abi.ChainEpoch + Beacon RandomBeacon +} + // RandomBeacon represents a system that provides randomness to Lotus. // Other components interrogate the RandomBeacon to acquire randomness that's // valid for a specific chain epoch. Also to verify beacon entries that have @@ -28,7 +45,11 @@ type RandomBeacon interface { MaxBeaconRoundForEpoch(abi.ChainEpoch, types.BeaconEntry) uint64 } -func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.BeaconEntry) error { +func ValidateBlockValues(bSchedule Schedule, h *types.BlockHeader, parentEpoch abi.ChainEpoch, + prevEntry types.BeaconEntry) error { + + // TODO: fork logic + b := bSchedule.BeaconForEpoch(h.Height) maxRound := b.MaxBeaconRoundForEpoch(h.Height, prevEntry) if maxRound == prevEntry.Round { if len(h.BeaconEntries) != 0 { @@ -56,10 +77,13 @@ func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.B return nil } -func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) { +func BeaconEntriesForBlock(ctx context.Context, bSchedule Schedule, epoch abi.ChainEpoch, parentEpoch abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) { + // TODO: fork logic + beacon := bSchedule.BeaconForEpoch(epoch) + start := build.Clock.Now() - maxRound := beacon.MaxBeaconRoundForEpoch(round, prev) + maxRound := beacon.MaxBeaconRoundForEpoch(epoch, prev) if maxRound == prev.Round { return nil, nil } @@ -82,7 +106,7 @@ func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.C out = append(out, resp.Entry) cur = resp.Entry.Round - 1 case <-ctx.Done(): - return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for round %d: %w", round, ctx.Err()) + return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for epoch %d: %w", epoch, ctx.Err()) } } diff --git a/chain/gen/gen.go b/chain/gen/gen.go index e6127508e..5f755b2ae 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -59,7 +59,7 @@ type ChainGen struct { cs *store.ChainStore - beacon beacon.RandomBeacon + beacon beacon.Schedule sm *stmgr.StateManager @@ -252,7 +252,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { miners := []address.Address{maddr1, maddr2} - beac := beacon.NewMockBeacon(time.Second) + beac := beacon.Schedule{{Start: 0, Beacon: beacon.NewMockBeacon(time.Second)}} //beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelaySecs) //if err != nil { //return nil, xerrors.Errorf("creating drand beacon: %w", err) @@ -338,7 +338,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add prev := mbi.PrevBeaconEntry - entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, prev) + entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, pts.Height(), prev) if err != nil { return nil, nil, nil, xerrors.Errorf("get beacon entries for block: %w", err) } @@ -559,7 +559,7 @@ type mca struct { w *wallet.Wallet sm *stmgr.StateManager pv ffiwrapper.Verifier - bcn beacon.RandomBeacon + bcn beacon.Schedule } func (mca mca) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) { diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index b21400da6..0cfc0e432 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -502,7 +502,7 @@ func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types. return lbts, nil } -func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBeacon, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) { +func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) { ts, err := sm.ChainStore().LoadTipSet(tsk) if err != nil { return nil, xerrors.Errorf("failed to load tipset for mining base: %w", err) @@ -517,7 +517,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe prev = &types.BeaconEntry{} } - entries, err := beacon.BeaconEntriesForBlock(ctx, bcn, round, *prev) + entries, err := beacon.BeaconEntriesForBlock(ctx, bcs, round, ts.Height(), *prev) if err != nil { return nil, err } diff --git a/chain/sync.go b/chain/sync.go index d64e68055..7cea20f9d 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -103,7 +103,7 @@ type Syncer struct { store *store.ChainStore // handle to the random beacon for verification - beacon beacon.RandomBeacon + beacon beacon.Schedule // the state manager handles making state queries sm *stmgr.StateManager @@ -141,7 +141,7 @@ type Syncer struct { } // NewSyncer creates a new Syncer object. -func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) { +func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*Syncer, error) { gen, err := sm.ChainStore().GetGenesis() if err != nil { return nil, xerrors.Errorf("getting genesis block: %w", err) @@ -879,7 +879,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er return nil } - if err := beacon.ValidateBlockValues(syncer.beacon, h, *prevBeacon); err != nil { + if err := beacon.ValidateBlockValues(syncer.beacon, h, baseTs.Height(), *prevBeacon); err != nil { return xerrors.Errorf("failed to validate blocks random beacon values: %w", err) } return nil diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 1cef5eaee..43f8fd4e0 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -53,7 +53,7 @@ type StateAPI struct { ProofVerifier ffiwrapper.Verifier StateManager *stmgr.StateManager Chain *store.ChainStore - Beacon beacon.RandomBeacon + Beacon beacon.Schedule } func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) { diff --git a/node/modules/chain.go b/node/modules/chain.go index cc86156b6..7b7e03e44 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -163,7 +163,7 @@ func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, return netName, err } -func NewSyncer(lc fx.Lifecycle, ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { +func NewSyncer(lc fx.Lifecycle, ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { syncer, err := chain.NewSyncer(ds, sm, exchange, h.ConnManager(), h.ID(), beacon, verifier) if err != nil { return nil, err From 64fa6fd9e5363bb546c4e17936d43ce15205b54d Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 9 Sep 2020 20:37:12 +0200 Subject: [PATCH 162/199] Draw the rest of the owl Signed-off-by: Jakub Sztandera --- build/drand.go | 23 ++++++++++++----- build/params_2k.go | 7 +++++- build/params_testnet.go | 4 +++ chain/beacon/beacon.go | 45 +++++++++++++++++++++++++++++++--- chain/beacon/drand/drand.go | 2 +- chain/beacon/mock.go | 6 +---- node/builder.go | 6 ++--- node/impl/full/beacon.go | 7 +++--- node/modules/core.go | 4 +-- node/modules/dtypes/beacon.go | 9 +++++++ node/modules/lp2p/pubsub.go | 4 +-- node/modules/services.go | 20 ++++++++++----- node/modules/testing/beacon.go | 7 ++++-- scripts/dev/sminer-init | 2 +- 14 files changed, 110 insertions(+), 36 deletions(-) diff --git a/build/drand.go b/build/drand.go index ef3f2c498..73299249a 100644 --- a/build/drand.go +++ b/build/drand.go @@ -1,15 +1,26 @@ package build -import "github.com/filecoin-project/lotus/node/modules/dtypes" +import ( + "sort" -var DrandNetwork = DrandIncentinet - -func DrandConfig() dtypes.DrandConfig { - return DrandConfigs[DrandNetwork] -} + "github.com/filecoin-project/lotus/node/modules/dtypes" +) type DrandEnum int +func DrandConfigSchedule() dtypes.DrandSchedule { + out := dtypes.DrandSchedule{} + for start, config := range DrandSchedule { + out = append(out, dtypes.DrandPoint{Start: start, Config: DrandConfigs[config]}) + } + + sort.Slice(out, func(i, j int) bool { + return out[i].Start < out[j].Start + }) + + return out +} + const ( DrandMainnet DrandEnum = iota + 1 DrandTestnet diff --git a/build/params_2k.go b/build/params_2k.go index 4bc7c2ecc..c7ca543e7 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -13,6 +13,11 @@ import ( const UpgradeBreezeHeight = -1 const BreezeGasTampingDuration = 0 +var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ + 0: DrandIncentinet, + 3: DrandMainnet, +} + func init() { power.ConsensusMinerMinPower = big.NewInt(2048) miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ @@ -23,7 +28,7 @@ func init() { BuildType |= Build2k } -const BlockDelaySecs = uint64(4) +const BlockDelaySecs = uint64(30) const PropagationDelaySecs = uint64(1) diff --git a/build/params_testnet.go b/build/params_testnet.go index 4a7523287..84eb09e89 100644 --- a/build/params_testnet.go +++ b/build/params_testnet.go @@ -12,6 +12,10 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/power" ) +var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ + 0: DrandIncentinet, +} + const UpgradeBreezeHeight = 41280 const BreezeGasTampingDuration = 120 diff --git a/chain/beacon/beacon.go b/chain/beacon/beacon.go index 0932c0c2a..feeaa158e 100644 --- a/chain/beacon/beacon.go +++ b/chain/beacon/beacon.go @@ -42,15 +42,30 @@ type BeaconPoint struct { type RandomBeacon interface { Entry(context.Context, uint64) <-chan Response VerifyEntry(types.BeaconEntry, types.BeaconEntry) error - MaxBeaconRoundForEpoch(abi.ChainEpoch, types.BeaconEntry) uint64 + MaxBeaconRoundForEpoch(abi.ChainEpoch) uint64 } func ValidateBlockValues(bSchedule Schedule, h *types.BlockHeader, parentEpoch abi.ChainEpoch, prevEntry types.BeaconEntry) error { + { + parentBeacon := bSchedule.BeaconForEpoch(parentEpoch) + currBeacon := bSchedule.BeaconForEpoch(h.Height) + if parentBeacon != currBeacon { + if len(h.BeaconEntries) != 2 { + return xerrors.Errorf("expected two beacon entries at beacon fork, got %d", len(h.BeaconEntries)) + } + err := currBeacon.VerifyEntry(h.BeaconEntries[1], h.BeaconEntries[0]) + if err != nil { + return xerrors.Errorf("beacon at fork point invalid: (%v, %v): %w", + h.BeaconEntries[1], h.BeaconEntries[0], err) + } + return nil + } + } // TODO: fork logic b := bSchedule.BeaconForEpoch(h.Height) - maxRound := b.MaxBeaconRoundForEpoch(h.Height, prevEntry) + maxRound := b.MaxBeaconRoundForEpoch(h.Height) if maxRound == prevEntry.Round { if len(h.BeaconEntries) != 0 { return xerrors.Errorf("expected not to have any beacon entries in this block, got %d", len(h.BeaconEntries)) @@ -78,12 +93,34 @@ func ValidateBlockValues(bSchedule Schedule, h *types.BlockHeader, parentEpoch a } func BeaconEntriesForBlock(ctx context.Context, bSchedule Schedule, epoch abi.ChainEpoch, parentEpoch abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) { - // TODO: fork logic + { + parentBeacon := bSchedule.BeaconForEpoch(parentEpoch) + currBeacon := bSchedule.BeaconForEpoch(epoch) + if parentBeacon != currBeacon { + // Fork logic + round := currBeacon.MaxBeaconRoundForEpoch(epoch) + out := make([]types.BeaconEntry, 2) + rch := currBeacon.Entry(ctx, round-1) + res := <-rch + if res.Err != nil { + return nil, xerrors.Errorf("getting entry %d returned error: %w", round-1, res.Err) + } + out[0] = res.Entry + rch = currBeacon.Entry(ctx, round) + res = <-rch + if res.Err != nil { + return nil, xerrors.Errorf("getting entry %d returned error: %w", round, res.Err) + } + out[1] = res.Entry + return out, nil + } + } + beacon := bSchedule.BeaconForEpoch(epoch) start := build.Clock.Now() - maxRound := beacon.MaxBeaconRoundForEpoch(epoch, prev) + maxRound := beacon.MaxBeaconRoundForEpoch(epoch) if maxRound == prev.Round { return nil, nil } diff --git a/chain/beacon/drand/drand.go b/chain/beacon/drand/drand.go index 6af39b65f..6e8e83a20 100644 --- a/chain/beacon/drand/drand.go +++ b/chain/beacon/drand/drand.go @@ -187,7 +187,7 @@ func (db *DrandBeacon) VerifyEntry(curr types.BeaconEntry, prev types.BeaconEntr return err } -func (db *DrandBeacon) MaxBeaconRoundForEpoch(filEpoch abi.ChainEpoch, prevEntry types.BeaconEntry) uint64 { +func (db *DrandBeacon) MaxBeaconRoundForEpoch(filEpoch abi.ChainEpoch) uint64 { // TODO: sometimes the genesis time for filecoin is zero and this goes negative latestTs := ((uint64(filEpoch) * db.filRoundTime) + db.filGenTime) - db.filRoundTime dround := (latestTs - db.drandGenTime) / uint64(db.interval.Seconds()) diff --git a/chain/beacon/mock.go b/chain/beacon/mock.go index 56a77df1c..502ff2ba5 100644 --- a/chain/beacon/mock.go +++ b/chain/beacon/mock.go @@ -53,11 +53,7 @@ func (mb *mockBeacon) VerifyEntry(from types.BeaconEntry, to types.BeaconEntry) return nil } -func (mb *mockBeacon) IsEntryForEpoch(e types.BeaconEntry, epoch abi.ChainEpoch, nulls int) (bool, error) { - return int64(e.Round) <= int64(epoch) && int64(epoch)-int64(nulls) >= int64(e.Round), nil -} - -func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch, prevEntry types.BeaconEntry) uint64 { +func (mb *mockBeacon) MaxBeaconRoundForEpoch(epoch abi.ChainEpoch) uint64 { return uint64(epoch) } diff --git a/node/builder.go b/node/builder.go index 128f44bd3..6c01258a6 100644 --- a/node/builder.go +++ b/node/builder.go @@ -226,7 +226,7 @@ func Online() Option { Override(new(dtypes.BootstrapPeers), modules.BuiltinBootstrap), Override(new(dtypes.DrandBootstrap), modules.DrandBootstrap), - Override(new(dtypes.DrandConfig), modules.BuiltinDrandConfig), + Override(new(dtypes.DrandSchedule), modules.BuiltinDrandConfig), Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages), @@ -272,7 +272,7 @@ func Online() Option { Override(new(modules.ClientDealFunds), modules.NewClientDealFunds), Override(new(storagemarket.StorageClient), modules.StorageClient), Override(new(storagemarket.StorageClientNode), storageadapter.NewClientNodeAdapter), - Override(new(beacon.RandomBeacon), modules.RandomBeacon), + Override(new(beacon.Schedule), modules.RandomSchedule), Override(new(*paychmgr.Store), paychmgr.NewStore), Override(new(*paychmgr.Manager), paychmgr.NewManager), @@ -535,6 +535,6 @@ func Test() Option { return Options( Unset(RunPeerMgrKey), Unset(new(*peermgr.PeerMgr)), - Override(new(beacon.RandomBeacon), testing.RandomBeacon), + Override(new(beacon.Schedule), testing.RandomBeacon), ) } diff --git a/node/impl/full/beacon.go b/node/impl/full/beacon.go index 725c6ff1f..bc7232c27 100644 --- a/node/impl/full/beacon.go +++ b/node/impl/full/beacon.go @@ -13,12 +13,13 @@ import ( type BeaconAPI struct { fx.In - Beacon beacon.RandomBeacon + Beacon beacon.Schedule } func (a *BeaconAPI) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) { - rr := a.Beacon.MaxBeaconRoundForEpoch(epoch, types.BeaconEntry{}) - e := a.Beacon.Entry(ctx, rr) + b := a.Beacon.BeaconForEpoch(epoch) + rr := b.MaxBeaconRoundForEpoch(epoch) + e := b.Entry(ctx, rr) select { case be, ok := <-e: diff --git a/node/modules/core.go b/node/modules/core.go index d73e4e25d..c0f016ab6 100644 --- a/node/modules/core.go +++ b/node/modules/core.go @@ -93,9 +93,9 @@ func BuiltinBootstrap() (dtypes.BootstrapPeers, error) { return build.BuiltinBootstrap() } -func DrandBootstrap(d dtypes.DrandConfig) (dtypes.DrandBootstrap, error) { +func DrandBootstrap(d dtypes.DrandSchedule) (dtypes.DrandBootstrap, error) { // TODO: retry resolving, don't fail if at least one resolve succeeds - addrs, err := addrutil.ParseAddresses(context.TODO(), d.Relays) + addrs, err := addrutil.ParseAddresses(context.TODO(), d[0].Config.Relays) if err != nil { log.Errorf("reoslving drand relays addresses: %+v", err) return nil, nil diff --git a/node/modules/dtypes/beacon.go b/node/modules/dtypes/beacon.go index 2231f0e08..28bbdf281 100644 --- a/node/modules/dtypes/beacon.go +++ b/node/modules/dtypes/beacon.go @@ -1,5 +1,14 @@ package dtypes +import "github.com/filecoin-project/go-state-types/abi" + +type DrandSchedule []DrandPoint + +type DrandPoint struct { + Start abi.ChainEpoch + Config DrandConfig +} + type DrandConfig struct { Servers []string Relays []string diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index 90c56f20d..41027672c 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -49,7 +49,7 @@ type GossipIn struct { Db dtypes.DrandBootstrap Cfg *config.Pubsub Sk *dtypes.ScoreKeeper - Dr dtypes.DrandConfig + Dr dtypes.DrandSchedule } func getDrandTopic(chainInfoJSON string) (string, error) { @@ -74,7 +74,7 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { } isBootstrapNode := in.Cfg.Bootstrapper - drandTopic, err := getDrandTopic(in.Dr.ChainInfoJSON) + drandTopic, err := getDrandTopic(in.Dr[0].Config.ChainInfoJSON) if err != nil { return nil, err } diff --git a/node/modules/services.go b/node/modules/services.go index b54a14bb1..c93cc558d 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -126,19 +126,27 @@ type RandomBeaconParams struct { PubSub *pubsub.PubSub `optional:"true"` Cs *store.ChainStore - DrandConfig dtypes.DrandConfig + DrandConfig dtypes.DrandSchedule } -func BuiltinDrandConfig() dtypes.DrandConfig { - return build.DrandConfig() +func BuiltinDrandConfig() dtypes.DrandSchedule { + return build.DrandConfigSchedule() } -func RandomBeacon(p RandomBeaconParams, _ dtypes.AfterGenesisSet) (beacon.RandomBeacon, error) { +func RandomSchedule(p RandomBeaconParams, _ dtypes.AfterGenesisSet) (beacon.Schedule, error) { gen, err := p.Cs.GetGenesis() if err != nil { return nil, err } - //return beacon.NewMockBeacon(build.BlockDelaySecs * time.Second) - return drand.NewDrandBeacon(gen.Timestamp, build.BlockDelaySecs, p.PubSub, p.DrandConfig) + shd := beacon.Schedule{} + for _, dc := range p.DrandConfig { + bc, err := drand.NewDrandBeacon(gen.Timestamp, build.BlockDelaySecs, p.PubSub, dc.Config) + if err != nil { + return nil, xerrors.Errorf("creating drand beacon: %w", err) + } + shd = append(shd, beacon.BeaconPoint{Start: dc.Start, Beacon: bc}) + } + + return shd, nil } diff --git a/node/modules/testing/beacon.go b/node/modules/testing/beacon.go index a4ef822fc..7876e1d05 100644 --- a/node/modules/testing/beacon.go +++ b/node/modules/testing/beacon.go @@ -7,6 +7,9 @@ import ( "github.com/filecoin-project/lotus/chain/beacon" ) -func RandomBeacon() (beacon.RandomBeacon, error) { - return beacon.NewMockBeacon(time.Duration(build.BlockDelaySecs) * time.Second), nil +func RandomBeacon() (beacon.Schedule, error) { + return beacon.Schedule{ + {Start: 0, + Beacon: beacon.NewMockBeacon(time.Duration(build.BlockDelaySecs) * time.Second), + }}, nil } diff --git a/scripts/dev/sminer-init b/scripts/dev/sminer-init index 767921511..2f4a3f7af 100755 --- a/scripts/dev/sminer-init +++ b/scripts/dev/sminer-init @@ -7,4 +7,4 @@ export TRUST_PARAMS=1 tag=${TAG:-debug} go run -tags=$tag ./cmd/lotus wallet import ~/.genesis-sectors/pre-seal-t01000.key -go run -tags=$tag ./cmd/lotus-miner init --actor=t01000 --genesis-miner --pre-sealed-sectors=~/.genesis-sectors --pre-sealed-metadata=~/.genesis-sectors/pre-seal-t01000.json +go run -tags=$tag ./cmd/lotus-storage-miner init --actor=t01000 --genesis-miner --pre-sealed-sectors=~/.genesis-sectors --pre-sealed-metadata=~/.genesis-sectors/pre-seal-t01000.json From 73e54352cdc07d76de1fa5d5c4dc894b804eba0e Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 9 Sep 2020 20:50:04 +0200 Subject: [PATCH 163/199] Fix off by one Signed-off-by: Jakub Sztandera --- chain/beacon/beacon.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/beacon/beacon.go b/chain/beacon/beacon.go index feeaa158e..9543bec54 100644 --- a/chain/beacon/beacon.go +++ b/chain/beacon/beacon.go @@ -23,7 +23,7 @@ type Schedule []BeaconPoint func (bs Schedule) BeaconForEpoch(e abi.ChainEpoch) RandomBeacon { for i := len(bs) - 1; i >= 0; i-- { bp := bs[i] - if e > bp.Start { + if e >= bp.Start { return bp.Beacon } } From bb0a7f91cc8058eda4d74a63bd58af9045f10672 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 9 Sep 2020 21:24:52 +0200 Subject: [PATCH 164/199] Fix drand non-test Signed-off-by: Jakub Sztandera --- chain/beacon/drand/drand_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain/beacon/drand/drand_test.go b/chain/beacon/drand/drand_test.go index 8d7c1b2cc..0cb9c2ba8 100644 --- a/chain/beacon/drand/drand_test.go +++ b/chain/beacon/drand/drand_test.go @@ -12,7 +12,7 @@ import ( ) func TestPrintGroupInfo(t *testing.T) { - server := build.DrandConfig().Servers[0] + server := build.DrandConfigs[build.DrandIncentinet].Servers[0] c, err := hclient.New(server, nil, nil) assert.NoError(t, err) cg := c.(interface { From 9a48ec194e0813aceefeccc79b257a01650667e9 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 9 Sep 2020 21:52:04 +0200 Subject: [PATCH 165/199] Add DrandSchedule to testground params Signed-off-by: Jakub Sztandera --- build/params_testground.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/params_testground.go b/build/params_testground.go index 06d4aecc5..d6594a819 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -72,4 +72,8 @@ var ( UpgradeBreezeHeight abi.ChainEpoch = 0 BreezeGasTampingDuration abi.ChainEpoch = 0 + + DrandSchedule = map[abi.ChainEpoch]DrandEnum{ + 0: DrandIncentinet, + } ) From 564d0ae974abf9c9e718893f4e90ebbfc3df7c02 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 9 Sep 2020 22:04:35 +0200 Subject: [PATCH 166/199] Upgrade drand Signed-off-by: Jakub Sztandera --- go.mod | 4 ++-- go.sum | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 903cfaae4..b04acf5e9 100644 --- a/go.mod +++ b/go.mod @@ -17,8 +17,8 @@ require ( github.com/detailyang/go-fallocate v0.0.0-20180908115635-432fa640bd2e github.com/dgraph-io/badger/v2 v2.0.3 github.com/docker/go-units v0.4.0 - github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4 - github.com/drand/kyber v1.1.1 + github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32 + github.com/drand/kyber v1.1.2 github.com/dustin/go-humanize v1.0.0 github.com/elastic/go-sysinfo v1.3.0 github.com/fatih/color v1.8.0 diff --git a/go.sum b/go.sum index 39970d325..016491cbc 100644 --- a/go.sum +++ b/go.sum @@ -91,6 +91,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/briandowns/spinner v1.11.1 h1:OixPqDEcX3juo5AjQZAnFPbeUA0jvkp2qzB5gOZJ/L0= github.com/briandowns/spinner v1.11.1/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ= github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= @@ -179,12 +180,12 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/drand/bls12-381 v0.3.2 h1:RImU8Wckmx8XQx1tp1q04OV73J9Tj6mmpQLYDP7V1XE= github.com/drand/bls12-381 v0.3.2/go.mod h1:dtcLgPtYT38L3NO6mPDYH0nbpc5tjPassDqiniuAt4Y= -github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4 h1:+Rov3bfUriGWFR/lUVXnpimx+HMr9BXRC4by0BxuQ8k= -github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4/go.mod h1:SnqWL9jksIMK63UKkfmWI6f9PDN8ROoCgg+Z4zWk7hg= +github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32 h1:sU+51aQRaDxg0KnjQg19KuYRIxDBEUHffBAICSnBys8= +github.com/drand/drand v1.1.2-0.20200905144319-79c957281b32/go.mod h1:0sQEVg+ngs1jaDPVIiEgY0lbENWJPaUlWxGHEaSmKVM= github.com/drand/kyber v1.0.1-0.20200110225416-8de27ed8c0e2/go.mod h1:UpXoA0Upd1N9l4TvRPHr1qAUBBERj6JQ/mnKI3BPEmw= github.com/drand/kyber v1.0.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= -github.com/drand/kyber v1.1.1 h1:mwCY2XGRB+Qc1MPfrnRuVuXELkPhcq/r9yMoJIcDhHI= -github.com/drand/kyber v1.1.1/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= +github.com/drand/kyber v1.1.2 h1:faemqlaFyLrbBSjZGRzzu5SG/do+uTYpHlnrJIHbAhQ= +github.com/drand/kyber v1.1.2/go.mod h1:x6KOpK7avKj0GJ4emhXFP5n7M7W7ChAPmnQh/OL6vRw= github.com/drand/kyber-bls12381 v0.1.0 h1:/P4C65VnyEwxzR5ZYYVMNzY1If+aYBrdUU5ukwh7LQw= github.com/drand/kyber-bls12381 v0.1.0/go.mod h1:N1emiHpm+jj7kMlxEbu3MUyOiooTgNySln564cgD9mk= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -1747,7 +1748,6 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v0.0.0-20200617041141-9a465503579e/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= From c71e1adc93a47a6537abb2b993e9a84ff9fa4584 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 10 Sep 2020 12:41:29 +0200 Subject: [PATCH 167/199] Integrate multiple drand networks with pubsub Signed-off-by: Jakub Sztandera --- node/modules/core.go | 17 ++- node/modules/lp2p/pubsub.go | 234 +++++++++++++++++++----------------- 2 files changed, 132 insertions(+), 119 deletions(-) diff --git a/node/modules/core.go b/node/modules/core.go index c0f016ab6..65b5eecb2 100644 --- a/node/modules/core.go +++ b/node/modules/core.go @@ -10,6 +10,7 @@ import ( "github.com/gbrlsnchs/jwt/v3" logging "github.com/ipfs/go-log/v2" + "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peerstore" record "github.com/libp2p/go-libp2p-record" "golang.org/x/xerrors" @@ -93,14 +94,18 @@ func BuiltinBootstrap() (dtypes.BootstrapPeers, error) { return build.BuiltinBootstrap() } -func DrandBootstrap(d dtypes.DrandSchedule) (dtypes.DrandBootstrap, error) { +func DrandBootstrap(ds dtypes.DrandSchedule) (dtypes.DrandBootstrap, error) { // TODO: retry resolving, don't fail if at least one resolve succeeds - addrs, err := addrutil.ParseAddresses(context.TODO(), d[0].Config.Relays) - if err != nil { - log.Errorf("reoslving drand relays addresses: %+v", err) - return nil, nil + res := []peer.AddrInfo{} + for _, d := range ds { + addrs, err := addrutil.ParseAddresses(context.TODO(), d.Config.Relays) + if err != nil { + log.Errorf("reoslving drand relays addresses: %+v", err) + return res, nil + } + res = append(res, addrs...) } - return addrs, nil + return res, nil } func SetupJournal(lr repo.LockedRepo) error { diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index 41027672c..aefb06d89 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -74,9 +74,126 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { } isBootstrapNode := in.Cfg.Bootstrapper - drandTopic, err := getDrandTopic(in.Dr[0].Config.ChainInfoJSON) - if err != nil { - return nil, err + + drandTopicParams := &pubsub.TopicScoreParams{ + // expected 2 beaconsn/min + TopicWeight: 0.5, // 5x block topic; max cap is 62.5 + + // 1 tick per second, maxes at 1 after 1 hour + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // deliveries decay after 1 hour, cap at 25 beacons + FirstMessageDeliveriesWeight: 5, // max value is 125 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 25, // the maximum expected in an hour is ~26, including the decay + + // Mesh Delivery Failure is currently turned off for beacons + // This is on purpose as + // - the traffic is very low for meaningful distribution of incoming edges. + // - the reaction time needs to be very slow -- in the order of 10 min at least + // so we might as well let opportunistic grafting repair the mesh on its own + // pace. + // - the network is too small, so large asymmetries can be expected between mesh + // edges. + // We should revisit this once the network grows. + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + } + + topicParams := map[string]*pubsub.TopicScoreParams{ + build.BlocksTopic(in.Nn): { + // expected 10 blocks/min + TopicWeight: 0.1, // max cap is 50, max mesh penalty is -10, single invalid message is -100 + + // 1 tick per second, maxes at 1 after 1 hour + TimeInMeshWeight: 0.00027, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // deliveries decay after 1 hour, cap at 100 blocks + FirstMessageDeliveriesWeight: 5, // max value is 500 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + FirstMessageDeliveriesCap: 100, // 100 blocks in an hour + + // Mesh Delivery Failure is currently turned off for blocks + // This is on purpose as + // - the traffic is very low for meaningful distribution of incoming edges. + // - the reaction time needs to be very slow -- in the order of 10 min at least + // so we might as well let opportunistic grafting repair the mesh on its own + // pace. + // - the network is too small, so large asymmetries can be expected between mesh + // edges. + // We should revisit this once the network grows. + // + // // tracks deliveries in the last minute + // // penalty activates at 1 minute and expects ~0.4 blocks + // MeshMessageDeliveriesWeight: -576, // max penalty is -100 + // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), + // MeshMessageDeliveriesCap: 10, // 10 blocks in a minute + // MeshMessageDeliveriesThreshold: 0.41666, // 10/12/2 blocks/min + // MeshMessageDeliveriesWindow: 10 * time.Millisecond, + // MeshMessageDeliveriesActivation: time.Minute, + // + // // decays after 15 min + // MeshFailurePenaltyWeight: -576, + // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(15 * time.Minute), + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + }, + build.MessagesTopic(in.Nn): { + // expected > 1 tx/second + TopicWeight: 0.1, // max cap is 5, single invalid message is -100 + + // 1 tick per second, maxes at 1 hour + TimeInMeshWeight: 0.0002778, // ~1/3600 + TimeInMeshQuantum: time.Second, + TimeInMeshCap: 1, + + // deliveries decay after 10min, cap at 100 tx + FirstMessageDeliveriesWeight: 0.5, // max value is 50 + FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(10 * time.Minute), + FirstMessageDeliveriesCap: 100, // 100 messages in 10 minutes + + // Mesh Delivery Failure is currently turned off for messages + // This is on purpose as the network is still too small, which results in + // asymmetries and potential unmeshing from negative scores. + // // tracks deliveries in the last minute + // // penalty activates at 1 min and expects 2.5 txs + // MeshMessageDeliveriesWeight: -16, // max penalty is -100 + // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), + // MeshMessageDeliveriesCap: 100, // 100 txs in a minute + // MeshMessageDeliveriesThreshold: 2.5, // 60/12/2 txs/minute + // MeshMessageDeliveriesWindow: 10 * time.Millisecond, + // MeshMessageDeliveriesActivation: time.Minute, + + // // decays after 5min + // MeshFailurePenaltyWeight: -16, + // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(5 * time.Minute), + + // invalid messages decay after 1 hour + InvalidMessageDeliveriesWeight: -1000, + InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), + }, + } + + pgTopicWeights := map[string]float64{ + build.BlocksTopic(in.Nn): 10, + build.MessagesTopic(in.Nn): 1, + } + + for _, d := range in.Dr { + topic, err := getDrandTopic(d.Config.ChainInfoJSON) + if err != nil { + return nil, err + } + topicParams[topic] = drandTopicParams + pgTopicWeights[topic] = 5 } options := []pubsub.Option{ @@ -124,111 +241,7 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { RetainScore: 6 * time.Hour, // topic parameters - Topics: map[string]*pubsub.TopicScoreParams{ - drandTopic: { - // expected 2 beaconsn/min - TopicWeight: 0.5, // 5x block topic; max cap is 62.5 - - // 1 tick per second, maxes at 1 after 1 hour - TimeInMeshWeight: 0.00027, // ~1/3600 - TimeInMeshQuantum: time.Second, - TimeInMeshCap: 1, - - // deliveries decay after 1 hour, cap at 25 beacons - FirstMessageDeliveriesWeight: 5, // max value is 125 - FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - FirstMessageDeliveriesCap: 25, // the maximum expected in an hour is ~26, including the decay - - // Mesh Delivery Failure is currently turned off for beacons - // This is on purpose as - // - the traffic is very low for meaningful distribution of incoming edges. - // - the reaction time needs to be very slow -- in the order of 10 min at least - // so we might as well let opportunistic grafting repair the mesh on its own - // pace. - // - the network is too small, so large asymmetries can be expected between mesh - // edges. - // We should revisit this once the network grows. - - // invalid messages decay after 1 hour - InvalidMessageDeliveriesWeight: -1000, - InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - }, - build.BlocksTopic(in.Nn): { - // expected 10 blocks/min - TopicWeight: 0.1, // max cap is 50, max mesh penalty is -10, single invalid message is -100 - - // 1 tick per second, maxes at 1 after 1 hour - TimeInMeshWeight: 0.00027, // ~1/3600 - TimeInMeshQuantum: time.Second, - TimeInMeshCap: 1, - - // deliveries decay after 1 hour, cap at 100 blocks - FirstMessageDeliveriesWeight: 5, // max value is 500 - FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - FirstMessageDeliveriesCap: 100, // 100 blocks in an hour - - // Mesh Delivery Failure is currently turned off for blocks - // This is on purpose as - // - the traffic is very low for meaningful distribution of incoming edges. - // - the reaction time needs to be very slow -- in the order of 10 min at least - // so we might as well let opportunistic grafting repair the mesh on its own - // pace. - // - the network is too small, so large asymmetries can be expected between mesh - // edges. - // We should revisit this once the network grows. - // - // // tracks deliveries in the last minute - // // penalty activates at 1 minute and expects ~0.4 blocks - // MeshMessageDeliveriesWeight: -576, // max penalty is -100 - // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), - // MeshMessageDeliveriesCap: 10, // 10 blocks in a minute - // MeshMessageDeliveriesThreshold: 0.41666, // 10/12/2 blocks/min - // MeshMessageDeliveriesWindow: 10 * time.Millisecond, - // MeshMessageDeliveriesActivation: time.Minute, - // - // // decays after 15 min - // MeshFailurePenaltyWeight: -576, - // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(15 * time.Minute), - - // invalid messages decay after 1 hour - InvalidMessageDeliveriesWeight: -1000, - InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - }, - build.MessagesTopic(in.Nn): { - // expected > 1 tx/second - TopicWeight: 0.1, // max cap is 5, single invalid message is -100 - - // 1 tick per second, maxes at 1 hour - TimeInMeshWeight: 0.0002778, // ~1/3600 - TimeInMeshQuantum: time.Second, - TimeInMeshCap: 1, - - // deliveries decay after 10min, cap at 100 tx - FirstMessageDeliveriesWeight: 0.5, // max value is 50 - FirstMessageDeliveriesDecay: pubsub.ScoreParameterDecay(10 * time.Minute), - FirstMessageDeliveriesCap: 100, // 100 messages in 10 minutes - - // Mesh Delivery Failure is currently turned off for messages - // This is on purpose as the network is still too small, which results in - // asymmetries and potential unmeshing from negative scores. - // // tracks deliveries in the last minute - // // penalty activates at 1 min and expects 2.5 txs - // MeshMessageDeliveriesWeight: -16, // max penalty is -100 - // MeshMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Minute), - // MeshMessageDeliveriesCap: 100, // 100 txs in a minute - // MeshMessageDeliveriesThreshold: 2.5, // 60/12/2 txs/minute - // MeshMessageDeliveriesWindow: 10 * time.Millisecond, - // MeshMessageDeliveriesActivation: time.Minute, - - // // decays after 5min - // MeshFailurePenaltyWeight: -16, - // MeshFailurePenaltyDecay: pubsub.ScoreParameterDecay(5 * time.Minute), - - // invalid messages decay after 1 hour - InvalidMessageDeliveriesWeight: -1000, - InvalidMessageDeliveriesDecay: pubsub.ScoreParameterDecay(time.Hour), - }, - }, + Topics: topicParams, }, &pubsub.PeerScoreThresholds{ GossipThreshold: -500, @@ -278,11 +291,6 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { } // validation queue RED - pgTopicWeights := map[string]float64{ - drandTopic: 5, - build.BlocksTopic(in.Nn): 10, - build.MessagesTopic(in.Nn): 1, - } var pgParams *pubsub.PeerGaterParams if isBootstrapNode { From d5d264d13b70930571a9118479ebe257660dd18e Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 10 Sep 2020 20:36:30 +0200 Subject: [PATCH 168/199] Add fork point Signed-off-by: Jakub Sztandera --- build/params_2k.go | 5 +++-- build/params_testground.go | 6 ++++-- build/params_testnet.go | 5 ++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/build/params_2k.go b/build/params_2k.go index c7ca543e7..0ef1d9b34 100644 --- a/build/params_2k.go +++ b/build/params_2k.go @@ -13,9 +13,10 @@ import ( const UpgradeBreezeHeight = -1 const BreezeGasTampingDuration = 0 +const UpgradeSmokeHeight = -1 + var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ - 0: DrandIncentinet, - 3: DrandMainnet, + 0: DrandMainnet, } func init() { diff --git a/build/params_testground.go b/build/params_testground.go index d6594a819..50ade70c0 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -70,10 +70,12 @@ var ( PackingEfficiencyNum int64 = 4 PackingEfficiencyDenom int64 = 5 - UpgradeBreezeHeight abi.ChainEpoch = 0 + UpgradeBreezeHeight abi.ChainEpoch = -1 BreezeGasTampingDuration abi.ChainEpoch = 0 + UpgradeSmokeHeight = -1 + DrandSchedule = map[abi.ChainEpoch]DrandEnum{ - 0: DrandIncentinet, + 0: DrandMainnet, } ) diff --git a/build/params_testnet.go b/build/params_testnet.go index 84eb09e89..932ad7a7d 100644 --- a/build/params_testnet.go +++ b/build/params_testnet.go @@ -13,12 +13,15 @@ import ( ) var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ - 0: DrandIncentinet, + 0: DrandIncentinet, + UpgradeSmokeHeight: DrandMainnet, } const UpgradeBreezeHeight = 41280 const BreezeGasTampingDuration = 120 +const UpgradeSmokeHeight = 51000 + func init() { power.ConsensusMinerMinPower = big.NewInt(10 << 40) miner.SupportedProofTypes = map[abi.RegisteredSealProof]struct{}{ From 316ac618757e03d97e93ad7cddf135366fc02b5e Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 10 Sep 2020 02:21:38 -0400 Subject: [PATCH 169/199] Update to go state types 3ca0d2890090 --- chain/stmgr/forks_test.go | 4 ++-- chain/stmgr/utils.go | 4 ++-- chain/vm/invoker.go | 6 ++---- chain/vm/invoker_test.go | 7 +++---- chain/vm/runtime.go | 3 +-- conformance/chaos/actor.go | 11 +++++------ go.mod | 4 +++- go.sum | 5 +++++ 8 files changed, 23 insertions(+), 21 deletions(-) diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index b5fb0c602..8a2865a7a 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -73,7 +73,7 @@ func (ta *testActor) Exports() []interface{} { } } -func (ta *testActor) Constructor(rt runtime.Runtime, params *adt.EmptyValue) *adt.EmptyValue { +func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() rt.State().Create(&testActorState{11}) fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Message().Receiver()) @@ -81,7 +81,7 @@ func (ta *testActor) Constructor(rt runtime.Runtime, params *adt.EmptyValue) *ad return adt.Empty } -func (ta *testActor) TestMethod(rt runtime.Runtime, params *adt.EmptyValue) *adt.EmptyValue { +func (ta *testActor) TestMethod(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() var st testActorState rt.State().Readonly(&st) diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 0cfc0e432..f77ec20ff 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -624,8 +624,8 @@ func init() { // Explicitly add send, it's special. methods[builtin.MethodSend] = MethodMeta{ Name: "Send", - Params: reflect.TypeOf(new(adt.EmptyValue)), - Ret: reflect.TypeOf(new(adt.EmptyValue)), + Params: reflect.TypeOf(new(abi.EmptyValue)), + Ret: reflect.TypeOf(new(abi.EmptyValue)), } // Learn method names from the builtin.Methods* structs. diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 2ec56a9db..c9d22cd4c 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -15,6 +15,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/actors/aerrors" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/cron" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" @@ -27,9 +28,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/system" "github.com/filecoin-project/specs-actors/actors/runtime" vmr "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/util/adt" - - "github.com/filecoin-project/lotus/chain/actors/aerrors" ) type Invoker struct { @@ -47,7 +45,7 @@ func NewInvoker() *Invoker { } // add builtInCode using: register(cid, singleton) - inv.Register(builtin.SystemActorCodeID, system.Actor{}, adt.EmptyValue{}) + inv.Register(builtin.SystemActorCodeID, system.Actor{}, abi.EmptyValue{}) inv.Register(builtin.InitActorCodeID, init_.Actor{}, init_.State{}) inv.Register(builtin.RewardActorCodeID, reward.Actor{}, reward.State{}) inv.Register(builtin.CronActorCodeID, cron.Actor{}, cron.State{}) diff --git a/chain/vm/invoker_test.go b/chain/vm/invoker_test.go index d19321c99..05f53ea51 100644 --- a/chain/vm/invoker_test.go +++ b/chain/vm/invoker_test.go @@ -13,7 +13,6 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors/aerrors" "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/util/adt" ) type basicContract struct{} @@ -60,17 +59,17 @@ func (b basicContract) Exports() []interface{} { } } -func (basicContract) InvokeSomething0(rt runtime.Runtime, params *basicParams) *adt.EmptyValue { +func (basicContract) InvokeSomething0(rt runtime.Runtime, params *basicParams) *abi.emptyvalue { rt.Abortf(exitcode.ExitCode(params.B), "params.B") return nil } -func (basicContract) BadParam(rt runtime.Runtime, params *basicParams) *adt.EmptyValue { +func (basicContract) BadParam(rt runtime.Runtime, params *basicParams) *abi.emptyvalue { rt.Abortf(255, "bad params") return nil } -func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams) *adt.EmptyValue { +func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams) *abi.emptyvalue { rt.Abortf(exitcode.ExitCode(params.B+10), "params.B") return nil } diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 043ea3a45..f0314d538 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -16,7 +16,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/runtime" vmr "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" @@ -136,7 +135,7 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act switch ret := ret.(type) { case []byte: return ret, nil - case *adt.EmptyValue: + case *abi.EmptyValue: return nil, nil case cbg.CBORMarshaler: buf := new(bytes.Buffer) diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index f3da42bb6..2ecd599e2 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -6,7 +6,6 @@ import ( "github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" typegen "github.com/whyrusleeping/cbor-gen" @@ -120,7 +119,7 @@ func (a Actor) Send(rt runtime.Runtime, args *SendArgs) *SendReturn { } // Constructor will panic because the Chaos actor is a singleton. -func (a Actor) Constructor(_ runtime.Runtime, _ *adt.EmptyValue) *adt.EmptyValue { +func (a Actor) Constructor(_ runtime.Runtime, _ *abi.EmptyValue) *abi.EmptyValue { panic("constructor should not be called; the Chaos actor is a singleton actor") } @@ -131,7 +130,7 @@ func (a Actor) Constructor(_ runtime.Runtime, _ *adt.EmptyValue) *adt.EmptyValue // CallerValidationBranchAddrNilSet validates against an empty caller // address set. // CallerValidationBranchTypeNilSet validates against an empty caller type set. -func (a Actor) CallerValidation(rt runtime.Runtime, branch *typegen.CborInt) *adt.EmptyValue { +func (a Actor) CallerValidation(rt runtime.Runtime, branch *typegen.CborInt) *abi.EmptyValue { switch CallerValidationBranch(*branch) { case CallerValidationBranchNone: case CallerValidationBranchTwice: @@ -161,7 +160,7 @@ type CreateActorArgs struct { } // CreateActor creates an actor with the supplied CID and Address. -func (a Actor) CreateActor(rt runtime.Runtime, args *CreateActorArgs) *adt.EmptyValue { +func (a Actor) CreateActor(rt runtime.Runtime, args *CreateActorArgs) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() var ( @@ -199,7 +198,7 @@ func (a Actor) ResolveAddress(rt runtime.Runtime, args *address.Address) *Resolv // DeleteActor deletes the executing actor from the state tree, transferring any // balance to beneficiary. -func (a Actor) DeleteActor(rt runtime.Runtime, beneficiary *address.Address) *adt.EmptyValue { +func (a Actor) DeleteActor(rt runtime.Runtime, beneficiary *address.Address) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() rt.DeleteActor(*beneficiary) return nil @@ -213,7 +212,7 @@ type MutateStateArgs struct { } // MutateState attempts to mutate a state value in the actor. -func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *adt.EmptyValue { +func (a Actor) MutateState(rt runtime.Runtime, args *MutateStateArgs) *abi.EmptyValue { rt.ValidateImmediateCallerAcceptAny() var st State switch args.Branch { diff --git a/go.mod b/go.mod index b04acf5e9..46c54958f 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 - github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df + github.com/filecoin-project/go-state-types v0.0.0-20200908000712-3ca0d2890090 github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b @@ -138,3 +138,5 @@ replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 replace github.com/filecoin-project/test-vectors => ./extern/test-vectors + +replace github.com/filecoin-project/specs-actors => ../specs-actors diff --git a/go.sum b/go.sum index 016491cbc..75bb6246d 100644 --- a/go.sum +++ b/go.sum @@ -227,6 +227,8 @@ github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= github.com/filecoin-project/go-fil-markets v0.6.0 h1:gfxMweUHo4u+2BZh2Q7/7+cV0/ttikuJfhkkxLRsE2Q= github.com/filecoin-project/go-fil-markets v0.6.0/go.mod h1:LhSFYLkjaoe0vFRKABGYyw1Jz+9jCpF1sPA7yOftLTw= +github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= +github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4= github.com/filecoin-project/go-multistore v0.0.3 h1:vaRBY4YiA2UZFPK57RNuewypB8u0DzzQwqsL0XarpnI= @@ -239,6 +241,9 @@ github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go github.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df h1:m2esXSuGBkuXlRyCsl1a/7/FkFam63o1OzIgzaHtOfI= github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200908000712-3ca0d2890090 h1:oFANhMdKCWXMeAUVO78oPoSpwOFVil4wvaNmpMk1agE= +github.com/filecoin-project/go-state-types v0.0.0-20200908000712-3ca0d2890090/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= From 86ba21029dcd6cfa72019669dd024cd4355e8ca7 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 10 Sep 2020 02:27:19 -0400 Subject: [PATCH 170/199] Update to go state types 001afaca718c --- chain/gen/genesis/genesis.go | 6 +++--- chain/gen/genesis/miners.go | 6 ++++-- chain/stmgr/stmgr.go | 10 +++++----- chain/vm/runtime.go | 4 +++- chain/vm/vm.go | 6 +++--- go.mod | 2 +- go.sum | 1 + 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index ac22b5b19..3035d3a11 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -6,7 +6,7 @@ import ( "encoding/json" "fmt" - "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/go-state-types/network" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" @@ -406,8 +406,8 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci verifNeeds := make(map[address.Address]abi.PaddedPieceSize) var sum abi.PaddedPieceSize - nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion { - return runtime.NetworkVersion1 + nwv := func(context.Context, abi.ChainEpoch) network.Version { + return network.Version1 } vmopt := vm.VMOpts{ diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index d8441c66c..4a352b7b7 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -6,6 +6,8 @@ import ( "fmt" "math/rand" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/lotus/chain/state" "github.com/ipfs/go-cid" @@ -61,8 +63,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid return big.Zero(), nil } - nwv := func(context.Context, abi.ChainEpoch) runtime.NetworkVersion { - return runtime.NetworkVersion1 + nwv := func(context.Context, abi.ChainEpoch) network.Version { + return network.Version1 } vmopt := &vm.VMOpts{ diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 929c9daf7..4929e6444 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -5,7 +5,7 @@ import ( "fmt" "sync" - "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/specs-actors/actors/builtin/power" @@ -1124,14 +1124,14 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha return csi.FilCirculating, nil } -func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) runtime.NetworkVersion { +func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version { if build.UpgradeBreezeHeight == 0 { - return runtime.NetworkVersion1 + return network.Version1 } if height <= build.UpgradeBreezeHeight { - return runtime.NetworkVersion0 + return network.Version0 } - return runtime.NetworkVersion1 + return network.Version1 } diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index f0314d538..7e9dd894b 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -8,6 +8,8 @@ import ( gruntime "runtime" "time" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" @@ -55,7 +57,7 @@ type Runtime struct { lastGasCharge *types.GasTrace } -func (rt *Runtime) NetworkVersion() vmr.NetworkVersion { +func (rt *Runtime) NetworkVersion() network.Version { return rt.vm.GetNtwkVersion(rt.ctx, rt.CurrEpoch()) } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index eb6c2f354..e389a3531 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -7,7 +7,7 @@ import ( "reflect" "time" - "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/go-state-types/network" bstore "github.com/filecoin-project/lotus/lib/blockstore" @@ -142,7 +142,7 @@ func (vm *UnsafeVM) MakeRuntime(ctx context.Context, msg *types.Message, origin } type CircSupplyCalculator func(context.Context, abi.ChainEpoch, *state.StateTree) (abi.TokenAmount, error) -type NtwkVersionGetter func(context.Context, abi.ChainEpoch) runtime.NetworkVersion +type NtwkVersionGetter func(context.Context, abi.ChainEpoch) network.Version type VM struct { cstate *state.StateTree @@ -722,7 +722,7 @@ func (vm *VM) SetInvoker(i *Invoker) { vm.inv = i } -func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) runtime.NetworkVersion { +func (vm *VM) GetNtwkVersion(ctx context.Context, ce abi.ChainEpoch) network.Version { return vm.ntwkVersion(ctx, ce) } diff --git a/go.mod b/go.mod index 46c54958f..e49ca1d97 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 - github.com/filecoin-project/go-state-types v0.0.0-20200908000712-3ca0d2890090 + github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b diff --git a/go.sum b/go.sum index 75bb6246d..b90f3c1b3 100644 --- a/go.sum +++ b/go.sum @@ -243,6 +243,7 @@ github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df h1 github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-state-types v0.0.0-20200908000712-3ca0d2890090 h1:oFANhMdKCWXMeAUVO78oPoSpwOFVil4wvaNmpMk1agE= github.com/filecoin-project/go-state-types v0.0.0-20200908000712-3ca0d2890090/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= +github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c h1:HHRMFpU8OrODDUja5NmGWNBAVGoSy4MRjxgZa+a0qIw= github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 h1:Jbburj7Ih2iaJ/o5Q9A+EAeTabME6YII7FLi9SKUf5c= From 774e06843692bd2d50a4834c71d7e5389f8646d7 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 10 Sep 2020 02:30:47 -0400 Subject: [PATCH 171/199] Update to specs-actors v0.9.8 --- api/api_full.go | 4 +++- api/apistruct/struct.go | 6 ++++-- chain/stmgr/forks_test.go | 5 ++--- chain/vm/invoker_test.go | 8 +++++--- go.mod | 4 +--- go.sum | 4 ++-- node/impl/client/client.go | 4 +++- node/impl/full/state.go | 4 +++- storage/miner.go | 4 +++- storage/wdpost_run.go | 8 +++++--- storage/wdpost_sched.go | 7 ++++--- 11 files changed, 35 insertions(+), 23 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index 02417bf78..a604028fb 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -5,6 +5,8 @@ import ( "fmt" "time" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/ipfs/go-cid" @@ -318,7 +320,7 @@ type FullNode interface { StateMinerActiveSectors(context.Context, address.Address, types.TipSetKey) ([]*ChainSectorInfo, error) // StateMinerProvingDeadline calculates the deadline at some epoch for a proving period // and returns the deadline-related calculations. - StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) + StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) // StateMinerPower returns the power of the indicated miner StateMinerPower(context.Context, address.Address, types.TipSetKey) (*MinerPower, error) // StateMinerInfo returns info about the indicated miner diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index ffb837785..6f32d204b 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -5,6 +5,8 @@ import ( "io" "time" + "github.com/filecoin-project/go-state-types/dline" + "github.com/ipfs/go-cid" metrics "github.com/libp2p/go-libp2p-core/metrics" "github.com/libp2p/go-libp2p-core/network" @@ -162,7 +164,7 @@ type FullNodeStruct struct { StateNetworkName func(context.Context) (dtypes.NetworkName, error) `perm:"read"` StateMinerSectors func(context.Context, address.Address, *bitfield.BitField, bool, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` StateMinerActiveSectors func(context.Context, address.Address, types.TipSetKey) ([]*api.ChainSectorInfo, error) `perm:"read"` - StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) `perm:"read"` + StateMinerProvingDeadline func(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) `perm:"read"` StateMinerPower func(context.Context, address.Address, types.TipSetKey) (*api.MinerPower, error) `perm:"read"` StateMinerInfo func(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) `perm:"read"` StateMinerDeadlines func(context.Context, address.Address, types.TipSetKey) ([]*miner.Deadline, error) `perm:"read"` @@ -738,7 +740,7 @@ func (c *FullNodeStruct) StateMinerActiveSectors(ctx context.Context, addr addre return c.Internal.StateMinerActiveSectors(ctx, addr, tsk) } -func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) { +func (c *FullNodeStruct) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) { return c.Internal.StateMinerProvingDeadline(ctx, addr, tsk) } diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index 8a2865a7a..e96d3f316 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -15,7 +15,6 @@ import ( "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/runtime" - "github.com/filecoin-project/specs-actors/actors/util/adt" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/actors" @@ -78,7 +77,7 @@ func (ta *testActor) Constructor(rt runtime.Runtime, params *abi.EmptyValue) *ab rt.State().Create(&testActorState{11}) fmt.Println("NEW ACTOR ADDRESS IS: ", rt.Message().Receiver()) - return adt.Empty + return abi.Empty } func (ta *testActor) TestMethod(rt runtime.Runtime, params *abi.EmptyValue) *abi.EmptyValue { @@ -96,7 +95,7 @@ func (ta *testActor) TestMethod(rt runtime.Runtime, params *abi.EmptyValue) *abi } } - return adt.Empty + return abi.Empty } func TestForkHeightTriggers(t *testing.T) { diff --git a/chain/vm/invoker_test.go b/chain/vm/invoker_test.go index 05f53ea51..3744aa8d2 100644 --- a/chain/vm/invoker_test.go +++ b/chain/vm/invoker_test.go @@ -5,6 +5,8 @@ import ( "io" "testing" + "github.com/filecoin-project/go-state-types/abi" + cbor "github.com/ipfs/go-ipld-cbor" "github.com/stretchr/testify/assert" cbg "github.com/whyrusleeping/cbor-gen" @@ -59,17 +61,17 @@ func (b basicContract) Exports() []interface{} { } } -func (basicContract) InvokeSomething0(rt runtime.Runtime, params *basicParams) *abi.emptyvalue { +func (basicContract) InvokeSomething0(rt runtime.Runtime, params *basicParams) *abi.EmptyValue { rt.Abortf(exitcode.ExitCode(params.B), "params.B") return nil } -func (basicContract) BadParam(rt runtime.Runtime, params *basicParams) *abi.emptyvalue { +func (basicContract) BadParam(rt runtime.Runtime, params *basicParams) *abi.EmptyValue { rt.Abortf(255, "bad params") return nil } -func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams) *abi.emptyvalue { +func (basicContract) InvokeSomething10(rt runtime.Runtime, params *basicParams) *abi.EmptyValue { rt.Abortf(exitcode.ExitCode(params.B+10), "params.B") return nil } diff --git a/go.mod b/go.mod index e49ca1d97..0cfa1ba9b 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/filecoin-project/go-statemachine v0.0.0-20200813232949-df9b130df370 github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b - github.com/filecoin-project/specs-actors v0.9.7 + github.com/filecoin-project/specs-actors v0.9.8 github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 github.com/filecoin-project/test-vectors/schema v0.0.1 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 @@ -138,5 +138,3 @@ replace github.com/filecoin-project/filecoin-ffi => ./extern/filecoin-ffi replace github.com/dgraph-io/badger/v2 => github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200716180832-3ab515320794 replace github.com/filecoin-project/test-vectors => ./extern/test-vectors - -replace github.com/filecoin-project/specs-actors => ../specs-actors diff --git a/go.sum b/go.sum index b90f3c1b3..1d18f7b42 100644 --- a/go.sum +++ b/go.sum @@ -241,8 +241,6 @@ github.com/filecoin-project/go-state-types v0.0.0-20200903145444-247639ffa6ad/go github.com/filecoin-project/go-state-types v0.0.0-20200904021452-1883f36ca2f4/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df h1:m2esXSuGBkuXlRyCsl1a/7/FkFam63o1OzIgzaHtOfI= github.com/filecoin-project/go-state-types v0.0.0-20200905071437-95828685f9df/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= -github.com/filecoin-project/go-state-types v0.0.0-20200908000712-3ca0d2890090 h1:oFANhMdKCWXMeAUVO78oPoSpwOFVil4wvaNmpMk1agE= -github.com/filecoin-project/go-state-types v0.0.0-20200908000712-3ca0d2890090/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c h1:HHRMFpU8OrODDUja5NmGWNBAVGoSy4MRjxgZa+a0qIw= github.com/filecoin-project/go-state-types v0.0.0-20200909080127-001afaca718c/go.mod h1:IQ0MBPnonv35CJHtWSN3YY1Hz2gkPru1Q9qoaYLxx9I= github.com/filecoin-project/go-statemachine v0.0.0-20200714194326-a77c3ae20989/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= @@ -255,6 +253,8 @@ github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/ github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4= github.com/filecoin-project/specs-actors v0.9.7 h1:7PAZ8kdqwBdmgf/23FCkQZLCXcVu02XJrkpkhBikiA8= github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= +github.com/filecoin-project/specs-actors v0.9.8 h1:45fnx/BsseFL3CtvSoR6CszFY26TFtsh9AHwCW2vkg8= +github.com/filecoin-project/specs-actors v0.9.8/go.mod h1:xFObDoWPySBNTNBrGXVVrutmgSZH/mMo46Q1bec/0hw= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796 h1:dJsTPWpG2pcTeojO2pyn0c6l+x/3MZYCBgo/9d11JEk= github.com/filecoin-project/specs-storage v0.1.1-0.20200907031224-ed2e5cd13796/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g= github.com/filecoin-project/test-vectors/schema v0.0.1 h1:5fNF76nl4qolEvcIsjc0kUADlTMVHO73tW4kXXPnsus= diff --git a/node/impl/client/client.go b/node/impl/client/client.go index d12a4ae73..7a107c2fd 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -6,6 +6,8 @@ import ( "io" "os" + "github.com/filecoin-project/go-state-types/dline" + datatransfer "github.com/filecoin-project/go-data-transfer" "github.com/filecoin-project/go-state-types/big" "golang.org/x/xerrors" @@ -80,7 +82,7 @@ type API struct { Host host.Host } -func calcDealExpiration(minDuration uint64, md *miner.DeadlineInfo, startEpoch abi.ChainEpoch) abi.ChainEpoch { +func calcDealExpiration(minDuration uint64, md *dline.Info, startEpoch abi.ChainEpoch) abi.ChainEpoch { // Make sure we give some time for the miner to seal minExp := startEpoch + abi.ChainEpoch(minDuration) diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 43f8fd4e0..e183fafa4 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -7,6 +7,8 @@ import ( "fmt" "strconv" + "github.com/filecoin-project/go-state-types/dline" + cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" @@ -145,7 +147,7 @@ func (a *StateAPI) StateMinerPartitions(ctx context.Context, m address.Address, })))))) } -func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*miner.DeadlineInfo, error) { +func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*dline.Info, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) diff --git a/storage/miner.go b/storage/miner.go index a9728433b..572a0d811 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -5,6 +5,8 @@ import ( "errors" "time" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/specs-actors/actors/runtime/proof" @@ -60,7 +62,7 @@ type storageMinerApi interface { StateSectorGetInfo(context.Context, address.Address, abi.SectorNumber, types.TipSetKey) (*miner.SectorOnChainInfo, error) StateSectorPartition(ctx context.Context, maddr address.Address, sectorNumber abi.SectorNumber, tok types.TipSetKey) (*api.SectorLocation, error) StateMinerInfo(context.Context, address.Address, types.TipSetKey) (api.MinerInfo, error) - StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*miner.DeadlineInfo, error) + StateMinerProvingDeadline(context.Context, address.Address, types.TipSetKey) (*dline.Info, error) StateMinerPreCommitDepositForPower(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) StateMinerInitialPledgeCollateral(context.Context, address.Address, miner.SectorPreCommitInfo, types.TipSetKey) (types.BigInt, error) StateSearchMsg(context.Context, cid.Cid) (*api.MsgLookup, error) diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index 090648dbb..84831ecf2 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -6,6 +6,8 @@ import ( "errors" "time" + "github.com/filecoin-project/go-state-types/dline" + "github.com/filecoin-project/specs-actors/actors/runtime/proof" "github.com/filecoin-project/go-bitfield" @@ -27,7 +29,7 @@ import ( var errNoPartitions = errors.New("no partitions") -func (s *WindowPoStScheduler) failPost(deadline *miner.DeadlineInfo) { +func (s *WindowPoStScheduler) failPost(deadline *dline.Info) { log.Errorf("TODO") /*s.failLk.Lock() if eps > s.failed { @@ -36,7 +38,7 @@ func (s *WindowPoStScheduler) failPost(deadline *miner.DeadlineInfo) { s.failLk.Unlock()*/ } -func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *miner.DeadlineInfo, ts *types.TipSet) { +func (s *WindowPoStScheduler) doPost(ctx context.Context, deadline *dline.Info, ts *types.TipSet) { ctx, abort := context.WithCancel(ctx) s.abort = abort @@ -286,7 +288,7 @@ func (s *WindowPoStScheduler) checkNextFaults(ctx context.Context, dlIdx uint64, return nil } -func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo, ts *types.TipSet) (*miner.SubmitWindowedPoStParams, error) { +func (s *WindowPoStScheduler) runPost(ctx context.Context, di dline.Info, ts *types.TipSet) (*miner.SubmitWindowedPoStParams, error) { ctx, span := trace.StartSpan(ctx, "storage.runPost") defer span.End() diff --git a/storage/wdpost_sched.go b/storage/wdpost_sched.go index b238a490d..905a2409c 100644 --- a/storage/wdpost_sched.go +++ b/storage/wdpost_sched.go @@ -4,11 +4,12 @@ import ( "context" "time" + "github.com/filecoin-project/go-state-types/dline" + "golang.org/x/xerrors" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" @@ -37,7 +38,7 @@ type WindowPoStScheduler struct { cur *types.TipSet // if a post is in progress, this indicates for which ElectionPeriodStart - activeDeadline *miner.DeadlineInfo + activeDeadline *dline.Info abort context.CancelFunc //failed abi.ChainEpoch // eps @@ -68,7 +69,7 @@ func NewWindowedPoStScheduler(api storageMinerApi, fc config.MinerFeeConfig, sb }, nil } -func deadlineEquals(a, b *miner.DeadlineInfo) bool { +func deadlineEquals(a, b *dline.Info) bool { if a == nil || b == nil { return b == a } From cbb693e99e7efaa9a6059bcdf5e56fb8eeea0d9d Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 10 Sep 2020 03:18:47 -0400 Subject: [PATCH 172/199] Update docs --- documentation/en/api-methods.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index 49582d6f8..7c2d91881 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -3633,7 +3633,12 @@ Response: "Open": 10101, "Close": 10101, "Challenge": 10101, - "FaultCutoff": 10101 + "FaultCutoff": 10101, + "WPoStPeriodDeadlines": 42, + "WPoStProvingPeriod": 10101, + "WPoStChallengeWindow": 10101, + "WPoStChallengeLookback": 10101, + "FaultDeclarationCutoff": 10101 } ``` From beba92aed42f70ef7cf4315cc1b728e2c8d41c67 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 10 Sep 2020 14:53:10 -0400 Subject: [PATCH 173/199] Improve network versioning logic --- build/params_shared_funcs.go | 8 ++++++++ build/params_shared_vals.go | 3 +++ chain/stmgr/stmgr.go | 10 +++++++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/build/params_shared_funcs.go b/build/params_shared_funcs.go index 2c9ef0b94..2c585271a 100644 --- a/build/params_shared_funcs.go +++ b/build/params_shared_funcs.go @@ -36,3 +36,11 @@ func MessagesTopic(netName dtypes.NetworkName) string { return "/fil/msgs/" + st func DhtProtocolName(netName dtypes.NetworkName) protocol.ID { return protocol.ID("/fil/kad/" + string(netName)) } + +func UseNewestNetwork() bool { + // TODO: Put these in a container we can iterate over + if UpgradeBreezeHeight <= 0 && UpgradeSmokeHeight <= 0 { + return true + } + return false +} diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index 7b4d4574b..4a46b7fd1 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -5,6 +5,8 @@ package build import ( "math/big" + "github.com/filecoin-project/go-state-types/network" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" @@ -20,6 +22,7 @@ const UnixfsLinksPerLevel = 1024 // Consensus / Network const AllowableClockDriftSecs = uint64(1) +const NewestNetworkVersion = network.Version2 // Epochs const ForkLengthThreshold = Finality diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 4929e6444..e6103e2b3 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -1125,13 +1125,17 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha } func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoch) network.Version { - if build.UpgradeBreezeHeight == 0 { - return network.Version1 + if build.UseNewestNetwork() { + return build.NewestNetworkVersion } if height <= build.UpgradeBreezeHeight { return network.Version0 } - return network.Version1 + if height <= build.UpgradeSmokeHeight { + return network.Version1 + } + + return build.NewestNetworkVersion } From 230ef2484dfa8c6bfb85b32794cf72ac18b5f1c1 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 10 Sep 2020 14:57:21 -0400 Subject: [PATCH 174/199] fix tests --- conformance/chaos/actor.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conformance/chaos/actor.go b/conformance/chaos/actor.go index 2ecd599e2..b9a181ba7 100644 --- a/conformance/chaos/actor.go +++ b/conformance/chaos/actor.go @@ -243,7 +243,7 @@ type AbortWithArgs struct { } // AbortWith simply causes a panic with the passed exit code. -func (a Actor) AbortWith(rt runtime.Runtime, args *AbortWithArgs) *adt.EmptyValue { +func (a Actor) AbortWith(rt runtime.Runtime, args *AbortWithArgs) *abi.EmptyValue { if args.Uncontrolled { // uncontrolled abort: directly panic panic(args.Message) } else { From 4170e18dea0e8c21ea96a8a1d22bf31fb1b53303 Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 10 Sep 2020 15:15:49 -0400 Subject: [PATCH 175/199] fix testground build --- build/params_testground.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/params_testground.go b/build/params_testground.go index 50ade70c0..395d2a855 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -11,6 +11,7 @@ import ( "math/big" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" ) @@ -73,9 +74,11 @@ var ( UpgradeBreezeHeight abi.ChainEpoch = -1 BreezeGasTampingDuration abi.ChainEpoch = 0 - UpgradeSmokeHeight = -1 + UpgradeSmokeHeight abi.ChainEpoch = -1 DrandSchedule = map[abi.ChainEpoch]DrandEnum{ 0: DrandMainnet, } + + NewestNetworkVersion = network.Version2 ) From 98a9042c072030c524c068fd851d4df608352c3c Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 10 Sep 2020 15:42:17 -0400 Subject: [PATCH 176/199] Use newest network version in genesiss setup stuff --- chain/gen/genesis/genesis.go | 2 +- chain/gen/genesis/miners.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 3035d3a11..0a9d58924 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -407,7 +407,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci var sum abi.PaddedPieceSize nwv := func(context.Context, abi.ChainEpoch) network.Version { - return network.Version1 + return build.NewestNetworkVersion } vmopt := vm.VMOpts{ diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index 4a352b7b7..b57608a5f 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -6,6 +6,8 @@ import ( "fmt" "math/rand" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/lotus/chain/state" @@ -64,7 +66,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid } nwv := func(context.Context, abi.ChainEpoch) network.Version { - return network.Version1 + return build.NewestNetworkVersion } vmopt := &vm.VMOpts{ From 7a46c5ff31a53df65559f5f5644d99ff12733e8c Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Wed, 2 Sep 2020 10:44:17 -0700 Subject: [PATCH 177/199] [WIP] Fix ticket randomness Signed-off-by: Jakub Sztandera --- chain/gen/gen.go | 4 +--- chain/sync.go | 6 +++--- cmd/lotus/debug_advance.go | 1 + miner/miner.go | 8 +++----- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 5f755b2ae..f2cd985f3 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -358,9 +358,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add return nil, nil, nil, xerrors.Errorf("failed to cbor marshal address: %w", err) } - if len(entries) == 0 { - buf.Write(pts.MinTicket().VRFProof) - } + buf.Write(pts.MinTicket().VRFProof) ticketRand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { diff --git a/chain/sync.go b/chain/sync.go index 7cea20f9d..67e925ae8 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -891,10 +891,10 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er return xerrors.Errorf("failed to marshal miner address to cbor: %w", err) } + buf.Write(baseTs.MinTicket().VRFProof) + beaconBase := *prevBeacon - if len(h.BeaconEntries) == 0 { - buf.Write(baseTs.MinTicket().VRFProof) - } else { + if len(h.BeaconEntries) != 0 { beaconBase = h.BeaconEntries[len(h.BeaconEntries)-1] } diff --git a/cmd/lotus/debug_advance.go b/cmd/lotus/debug_advance.go index 73eab49fc..4e74a995f 100644 --- a/cmd/lotus/debug_advance.go +++ b/cmd/lotus/debug_advance.go @@ -46,6 +46,7 @@ func init() { return xerrors.Errorf("StateMinerWorker: %w", err) } + // XXX: This can't be right rand, err := api.ChainGetRandomnessFromTickets(ctx, head.Key(), crypto.DomainSeparationTag_TicketProduction, head.Height(), addr.Bytes()) if err != nil { return xerrors.Errorf("failed to get randomness: %w", err) diff --git a/miner/miner.go b/miner/miner.go index 9c11dcc46..b08b9c38a 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -362,7 +362,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg, rbase = bvals[len(bvals)-1] } - ticket, err := m.computeTicket(ctx, &rbase, base, len(bvals) > 0) + ticket, err := m.computeTicket(ctx, &rbase, base) if err != nil { return nil, xerrors.Errorf("scratching ticket failed: %w", err) } @@ -432,7 +432,7 @@ func (m *Miner) mineOne(ctx context.Context, base *MiningBase) (*types.BlockMsg, return b, nil } -func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, base *MiningBase, haveNewEntries bool) (*types.Ticket, error) { +func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, base *MiningBase) (*types.Ticket, error) { mi, err := m.api.StateMinerInfo(ctx, m.address, types.EmptyTSK) if err != nil { return nil, err @@ -447,9 +447,7 @@ func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, bas return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err) } - if !haveNewEntries { - buf.Write(base.TipSet.MinTicket().VRFProof) - } + buf.Write(base.TipSet.MinTicket().VRFProof) input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, base.TipSet.Height()+base.NullRounds+1-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { From db6bd890d9b6a7a89672b44f2a725fd77efed175 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Wed, 9 Sep 2020 20:06:23 -0700 Subject: [PATCH 178/199] condition randomness changes on fork height Signed-off-by: Jakub Sztandera --- chain/gen/gen.go | 4 +++- chain/sync.go | 4 +++- miner/miner.go | 7 +++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/chain/gen/gen.go b/chain/gen/gen.go index f2cd985f3..d661411fe 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -358,7 +358,9 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add return nil, nil, nil, xerrors.Errorf("failed to cbor marshal address: %w", err) } - buf.Write(pts.MinTicket().VRFProof) + if round > build.UpgradeSmokeHeight { + buf.Write(pts.MinTicket().VRFProof) + } ticketRand, err := store.DrawRandomness(rbase.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { diff --git a/chain/sync.go b/chain/sync.go index 67e925ae8..9864600dd 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -891,7 +891,9 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er return xerrors.Errorf("failed to marshal miner address to cbor: %w", err) } - buf.Write(baseTs.MinTicket().VRFProof) + if h.Height > build.UpgradeSmokeHeight { + buf.Write(baseTs.MinTicket().VRFProof) + } beaconBase := *prevBeacon if len(h.BeaconEntries) != 0 { diff --git a/miner/miner.go b/miner/miner.go index b08b9c38a..1b0f0c766 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -447,9 +447,12 @@ func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, bas return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err) } - buf.Write(base.TipSet.MinTicket().VRFProof) + round := base.TipSet.Height() + base.NullRounds + 1 + if round > build.UpgradeSmokeHeight { + buf.Write(base.TipSet.MinTicket().VRFProof) + } - input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, base.TipSet.Height()+base.NullRounds+1-build.TicketRandomnessLookback, buf.Bytes()) + input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes()) if err != nil { return nil, err } From fd714cbcebbb618bdf26b4fbf903d256e14b274f Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 10 Sep 2020 12:22:49 +0200 Subject: [PATCH 179/199] Remove PackingEfficiency consideration from base fee in an upgrade Signed-off-by: Jakub Sztandera --- chain/store/basefee.go | 18 ++++++++++++------ chain/store/basefee_test.go | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/chain/store/basefee.go b/chain/store/basefee.go index 69970dd96..4c39bb75b 100644 --- a/chain/store/basefee.go +++ b/chain/store/basefee.go @@ -11,14 +11,20 @@ import ( "golang.org/x/xerrors" ) -func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int) types.BigInt { - // deta := 1/PackingEfficiency * gasLimitUsed/noOfBlocks - build.BlockGasTarget - // change := baseFee * deta / BlockGasTarget / BaseFeeMaxChangeDenom +func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int, epoch abi.ChainEpoch) types.BigInt { + // deta := gasLimitUsed/noOfBlocks - build.BlockGasTarget + // change := baseFee * deta / BlockGasTarget // nextBaseFee = baseFee + change // nextBaseFee = max(nextBaseFee, build.MinimumBaseFee) - delta := build.PackingEfficiencyDenom * gasLimitUsed / (int64(noOfBlocks) * build.PackingEfficiencyNum) - delta -= build.BlockGasTarget + var delta int64 + if epoch > build.UpgradeSmokeHeight { + delta = gasLimitUsed / int64(noOfBlocks) + delta -= build.BlockGasTarget + } else { + delta = build.PackingEfficiencyDenom * gasLimitUsed / (int64(noOfBlocks) * build.PackingEfficiencyNum) + delta -= build.BlockGasTarget + } // cap change at 12.5% (BaseFeeMaxChangeDenom) by capping delta if delta > build.BlockGasTarget { @@ -73,5 +79,5 @@ func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi } parentBaseFee := ts.Blocks()[0].ParentBaseFee - return computeNextBaseFee(parentBaseFee, totalLimit, len(ts.Blocks())), nil + return computeNextBaseFee(parentBaseFee, totalLimit, len(ts.Blocks()), ts.Height()), nil } diff --git a/chain/store/basefee_test.go b/chain/store/basefee_test.go index 7a7cae911..3449246bb 100644 --- a/chain/store/basefee_test.go +++ b/chain/store/basefee_test.go @@ -27,7 +27,7 @@ func TestBaseFee(t *testing.T) { 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) + output := computeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, 0) assert.Equal(t, fmt.Sprintf("%d", test.output), output.String()) }) } From 6813ab4e65fb54751825a6be160ebfda039c7100 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Thu, 10 Sep 2020 16:26:34 +0200 Subject: [PATCH 180/199] Add additional metrics Signed-off-by: Jakub Sztandera --- chain/store/basefee.go | 4 ++-- chain/store/basefee_test.go | 2 +- tools/stats/metrics.go | 32 ++++++++++++++++++++++++++------ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/chain/store/basefee.go b/chain/store/basefee.go index 4c39bb75b..45785240e 100644 --- a/chain/store/basefee.go +++ b/chain/store/basefee.go @@ -11,7 +11,7 @@ import ( "golang.org/x/xerrors" ) -func computeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int, epoch abi.ChainEpoch) types.BigInt { +func ComputeNextBaseFee(baseFee types.BigInt, gasLimitUsed int64, noOfBlocks int, epoch abi.ChainEpoch) types.BigInt { // deta := gasLimitUsed/noOfBlocks - build.BlockGasTarget // change := baseFee * deta / BlockGasTarget // nextBaseFee = baseFee + change @@ -79,5 +79,5 @@ func (cs *ChainStore) ComputeBaseFee(ctx context.Context, ts *types.TipSet) (abi } parentBaseFee := ts.Blocks()[0].ParentBaseFee - return computeNextBaseFee(parentBaseFee, totalLimit, len(ts.Blocks()), ts.Height()), nil + return ComputeNextBaseFee(parentBaseFee, totalLimit, len(ts.Blocks()), ts.Height()), nil } diff --git a/chain/store/basefee_test.go b/chain/store/basefee_test.go index 3449246bb..b4757f70e 100644 --- a/chain/store/basefee_test.go +++ b/chain/store/basefee_test.go @@ -27,7 +27,7 @@ func TestBaseFee(t *testing.T) { 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, 0) + output := ComputeNextBaseFee(types.NewInt(test.basefee), test.limitUsed, test.noOfBlocks, 0) assert.Equal(t, fmt.Sprintf("%d", test.output), output.String()) }) } diff --git a/tools/stats/metrics.go b/tools/stats/metrics.go index 39fecf47b..ae79d9273 100644 --- a/tools/stats/metrics.go +++ b/tools/stats/metrics.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "fmt" + "math" "math/big" "strings" "time" @@ -12,6 +13,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/power" @@ -131,12 +133,6 @@ func RecordTipsetPoints(ctx context.Context, api api.FullNode, pl *PointList, ti p = NewPoint("chain.blocktime", tsTime.Unix()) pl.AddPoint(p) - baseFeeBig := tipset.Blocks()[0].ParentBaseFee.Copy() - baseFeeRat := new(big.Rat).SetFrac(baseFeeBig.Int, new(big.Int).SetUint64(build.FilecoinPrecision)) - baseFeeFloat, _ := baseFeeRat.Float64() - p = NewPoint("chain.basefee", baseFeeFloat) - pl.AddPoint(p) - totalGasLimit := int64(0) totalUniqGasLimit := int64(0) seen := make(map[cid.Cid]struct{}) @@ -178,6 +174,30 @@ func RecordTipsetPoints(ctx context.Context, api api.FullNode, pl *PointList, ti p = NewPoint("chain.gas_limit_uniq_total", totalUniqGasLimit) pl.AddPoint(p) + { + baseFeeIn := tipset.Blocks()[0].ParentBaseFee + newBaseFee := store.ComputeNextBaseFee(baseFeeIn, totalUniqGasLimit, len(tipset.Blocks()), tipset.Height()) + + baseFeeRat := new(big.Rat).SetFrac(newBaseFee.Int, new(big.Int).SetUint64(build.FilecoinPrecision)) + baseFeeFloat, _ := baseFeeRat.Float64() + p = NewPoint("chain.basefee", baseFeeFloat) + pl.AddPoint(p) + + baseFeeChange := new(big.Rat).SetFrac(newBaseFee.Int, baseFeeIn.Int) + baseFeeChangeF, _ := baseFeeChange.Float64() + p = NewPoint("chain.basefee_change_log", math.Log(baseFeeChangeF)/math.Log(1.125)) + pl.AddPoint(p) + } + { + blks := len(cids) + p = NewPoint("chain.gas_fill_ratio", float64(totalGasLimit)/float64(blks*build.BlockGasTarget)) + pl.AddPoint(p) + p = NewPoint("chain.gas_capacity_ratio", float64(totalUniqGasLimit)/float64(blks*build.BlockGasTarget)) + pl.AddPoint(p) + p = NewPoint("chain.gas_waste_ratio", float64(totalGasLimit-totalUniqGasLimit)/float64(blks*build.BlockGasTarget)) + pl.AddPoint(p) + } + return nil } From e7edc46dafdfd76f0b8c2ac275595d02327c014f Mon Sep 17 00:00:00 2001 From: Aayush Rajasekaran Date: Thu, 10 Sep 2020 17:41:07 -0400 Subject: [PATCH 181/199] Lotus version 0.7.0 --- CHANGELOG.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++- build/version.go | 2 +- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3d85ab6f..8617554a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,60 @@ # Lotus changelog +# 0.7.0 / 2020-09-10 + +This consensus-breaking release of Lotus is designed to test a network upgrade on the space race testnet. The changes that break consensus are: + +- Upgrading the Drand network used from the test Drand network to the League of Entropy main drand network. This is the same Drand network that will be used in the Filecoin mainnet. +- Upgrading to specs-actors v0.9.8, which adds a new method to the Multisig actor. + +## Changes + +#### Core Lotus + +- Fix IsAncestorOf (https://github.com/filecoin-project/lotus/pull/3717) +- Update to specs-actors v0.9.8 (https://github.com/filecoin-project/lotus/pull/3725) +- Increase chain throughput by 20% (https://github.com/filecoin-project/lotus/pull/3732) +- Updare to go-libp2p-pubsub `master` (https://github.com/filecoin-project/lotus/pull/3735) +- Drand upgrade (https://github.com/filecoin-project/lotus/pull/3670) +- Multisig API additions (https://github.com/filecoin-project/lotus/pull/3590) + +#### Storage Miner + +- Increase the number of times precommit2 is attempted before moving back to precommit1 (https://github.com/filecoin-project/lotus/pull/3720) + +#### Message pool + +- Relax mpool add strictness checks for local pushes (https://github.com/filecoin-project/lotus/pull/3724) + + +#### Maintenance + +- Fix devnets (https://github.com/filecoin-project/lotus/pull/3712) +- Fix(chainwatch): compare prev miner with cur miner (https://github.com/filecoin-project/lotus/pull/3715) +- CI: fix statediff build; make optional (https://github.com/filecoin-project/lotus/pull/3729) +- Feat: Chaos abort (https://github.com/filecoin-project/lotus/pull/3733) + +## Contributors + +The following contributors had commits go into this release. +We are grateful for every contribution! + +| Contributor | Commits | Lines ± | +|--------------------|---------|---------------| +| arajasek | 28 | +1144/-239 | +| Kubuxu | 19 | +452/-261 | +| whyrusleeping | 13 | +456/-87 | +| vyzo | 11 | +318/-20 | +| raulk | 10 | +1289/-350 | +| magik6k | 6 | +188/-55 | +| dirkmc | 3 | +31/-8 | +| alanshaw | 3 | +176/-37 | +| Stebalien | 2 | +9/-12 | +| lanzafame | 1 | +1/-1 | +| frrist | 1 | +1/-1 | +| mishmosh | 1 | +1/-1 | +| nonsense | 1 | +1/-0 | + # 0.6.2 / 2020-09-09 This release introduces some critical fixes to message selection and gas estimation logic. It also adds the ability for nodes to mark a certain tipset as checkpointed, as well as various minor improvements and bugfixes. @@ -38,7 +93,6 @@ This release introduces some critical fixes to message selection and gas estimat - Paych: add docs on how to use paych status (https://github.com/filecoin-project/lotus/pull/3690) - Initial CODEOWNERS (https://github.com/filecoin-project/lotus/pull/3691) - # 0.6.1 / 2020-09-08 This optional release introduces a minor improvement to the sync process, ensuring nodes don't fall behind and then resync. diff --git a/build/version.go b/build/version.go index ba5519a7c..2466d8023 100644 --- a/build/version.go +++ b/build/version.go @@ -29,7 +29,7 @@ func buildType() string { } // BuildVersion is the local build version, set by build system -const BuildVersion = "0.6.2" +const BuildVersion = "0.7.0" func UserVersion() string { return BuildVersion + buildType() + CurrentCommit From 2865a0367bdbed5fad9d4e641d9dc7dc7398a98d Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 11 Sep 2020 00:59:57 +0200 Subject: [PATCH 182/199] Fix mpool replace --auto Signed-off-by: Jakub Sztandera --- chain/messagepool/messagepool.go | 17 +++++++++++++++++ cli/mpool.go | 23 ++++++++++++++++++++--- go.sum | 5 +++++ node/impl/full/gas.go | 18 +----------------- 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 06cbe65e7..653844c02 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -12,6 +12,7 @@ import ( "time" "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/crypto" "github.com/hashicorp/go-multierror" lru "github.com/hashicorp/golang-lru" @@ -160,6 +161,22 @@ func ComputeMinRBF(curPrem abi.TokenAmount) abi.TokenAmount { return types.BigAdd(minPrice, types.NewInt(1)) } +func CapGasFee(msg *types.Message, maxFee abi.TokenAmount) { + if maxFee.Equals(big.Zero()) { + maxFee = types.NewInt(build.FilecoinPrecision / 10) + } + + gl := types.NewInt(uint64(msg.GasLimit)) + totalFee := types.BigMul(msg.GasFeeCap, gl) + + if totalFee.LessThanEqual(maxFee) { + return + } + + msg.GasFeeCap = big.Div(maxFee, gl) + msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap +} + func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict bool) (bool, error) { nextNonce := ms.nextNonce nonceGap := false diff --git a/cli/mpool.go b/cli/mpool.go index 6ae94356a..65f4ef942 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -303,6 +303,10 @@ var mpoolReplaceCmd = &cli.Command{ Name: "auto", Usage: "automatically reprice the specified message", }, + &cli.StringFlag{ + Name: "max-fee", + Usage: "Spend up to X FIL for this message (applicable for auto mode)", + }, }, ArgsUsage: "[from] [nonce]", Action: func(cctx *cli.Context) error { @@ -353,17 +357,30 @@ var mpoolReplaceCmd = &cli.Command{ msg := found.Message if cctx.Bool("auto") { + minRBF := messagepool.ComputeMinRBF(msg.GasPremium) + + var mss *lapi.MessageSendSpec + if cctx.IsSet("max-fee") { + maxFee, err := types.BigFromString(cctx.String("max-fee")) + if err != nil { + return fmt.Errorf("parsing max-spend: %w", err) + } + mss = &lapi.MessageSendSpec{ + MaxFee: maxFee, + } + } + // msg.GasLimit = 0 // TODO: need to fix the way we estimate gas limits to account for the messages already being in the mempool msg.GasFeeCap = abi.NewTokenAmount(0) msg.GasPremium = abi.NewTokenAmount(0) - retm, err := api.GasEstimateMessageGas(ctx, &msg, &lapi.MessageSendSpec{}, types.EmptyTSK) + retm, err := api.GasEstimateMessageGas(ctx, &msg, mss, types.EmptyTSK) if err != nil { return fmt.Errorf("failed to estimate gas values: %w", err) } - msg.GasFeeCap = retm.GasFeeCap - minRBF := messagepool.ComputeMinRBF(msg.GasPremium) msg.GasPremium = big.Max(retm.GasPremium, minRBF) + msg.GasFeeCap = big.Max(retm.GasFeeCap, msg.GasPremium) + messagepool.CapGasFee(&msg, mss.Get().MaxFee) } else { msg.GasLimit = cctx.Int64("gas-limit") msg.GasPremium, err = types.BigFromString(cctx.String("gas-premium")) diff --git a/go.sum b/go.sum index 1d18f7b42..18ebc816f 100644 --- a/go.sum +++ b/go.sum @@ -211,10 +211,13 @@ 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/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= +github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= github.com/filecoin-project/go-address v0.0.3 h1:eVfbdjEbpbzIrbiSa+PiGUY+oDK9HnUn+M1R/ggoHf8= github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= +github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= +github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= github.com/filecoin-project/go-bitfield v0.2.0 h1:gCtLcjskIPtdg4NfN7gQZSQF9yrBQ7mkT0qCJxzGI2Q= github.com/filecoin-project/go-bitfield v0.2.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:av5fw6wmm58FYMgJeoB/lK9XXrgdugYiTqkdxjTy9k8= @@ -250,6 +253,7 @@ github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIi github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= +github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4= github.com/filecoin-project/specs-actors v0.9.7 h1:7PAZ8kdqwBdmgf/23FCkQZLCXcVu02XJrkpkhBikiA8= github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= @@ -504,6 +508,7 @@ github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28 github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= github.com/ipfs/go-graphsync v0.1.2 h1:25Ll9kIXCE+DY0dicvfS3KMw+U5sd01b/FJbA7KAbhg= github.com/ipfs/go-graphsync v0.1.2/go.mod h1:sLXVXm1OxtE2XYPw62MuXCdAuNwkAdsbnfrmos5odbA= +github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk= github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 40ab88b6b..a597059e4 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -211,23 +211,7 @@ func (a *GasAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, msg.GasFeeCap = feeCap } - capGasFee(msg, spec.Get().MaxFee) + messagepool.CapGasFee(msg, spec.Get().MaxFee) return msg, nil } - -func capGasFee(msg *types.Message, maxFee abi.TokenAmount) { - if maxFee.Equals(big.Zero()) { - maxFee = types.NewInt(build.FilecoinPrecision / 10) - } - - gl := types.NewInt(uint64(msg.GasLimit)) - totalFee := types.BigMul(msg.GasFeeCap, gl) - - if totalFee.LessThanEqual(maxFee) { - return - } - - msg.GasFeeCap = big.Div(maxFee, gl) - msg.GasPremium = big.Min(msg.GasFeeCap, msg.GasPremium) // cap premium at FeeCap -} From 56b237e7b8b73b6075b5c871a9fc6ad472ae7f29 Mon Sep 17 00:00:00 2001 From: hannahhoward Date: Thu, 10 Sep 2020 16:00:23 -0700 Subject: [PATCH 183/199] fix(paych): add status command to list Add paych status cmd to list of payment channel sub commands --- cli/paych.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/paych.go b/cli/paych.go index bcd8e33f0..57fd1c142 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -28,6 +28,7 @@ var paychCmd = &cli.Command{ paychListCmd, paychVoucherCmd, paychSettleCmd, + paychStatusCmd, paychCloseCmd, }, } From 0e3dd3cb3b0f9e1a8f66f85bb2e1924577558081 Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Thu, 10 Sep 2020 17:28:25 -0700 Subject: [PATCH 184/199] Add faster and slimmer option to chain export via lotus-shed --- chain/store/store.go | 12 ++-- chain/store/store_test.go | 2 +- cmd/lotus-shed/export.go | 123 ++++++++++++++++++++++++++++++++++++++ cmd/lotus-shed/main.go | 1 + node/impl/full/chain.go | 2 +- 5 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 cmd/lotus-shed/export.go diff --git a/chain/store/store.go b/chain/store/store.go index c85f547a1..d5ecf95ef 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -1159,7 +1159,7 @@ func recurseLinks(bs bstore.Blockstore, walked *cid.Set, root cid.Cid, in []cid. return in, rerr } -func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, w io.Writer) error { +func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRoots abi.ChainEpoch, skipOldMsgs bool, w io.Writer) error { if ts == nil { ts = cs.GetHeaviestTipSet() } @@ -1197,9 +1197,13 @@ func (cs *ChainStore) Export(ctx context.Context, ts *types.TipSet, inclRecentRo return xerrors.Errorf("unmarshaling block header (cid=%s): %w", blk, err) } - cids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages}) - if err != nil { - return xerrors.Errorf("recursing messages failed: %w", err) + var cids []cid.Cid + if !skipOldMsgs || b.Height > ts.Height()-inclRecentRoots { + mcids, err := recurseLinks(cs.bs, walked, b.Messages, []cid.Cid{b.Messages}) + if err != nil { + return xerrors.Errorf("recursing messages failed: %w", err) + } + cids = mcids } if b.Height > 0 { diff --git a/chain/store/store_test.go b/chain/store/store_test.go index 1e3673f44..e56bab4c9 100644 --- a/chain/store/store_test.go +++ b/chain/store/store_test.go @@ -96,7 +96,7 @@ func TestChainExportImport(t *testing.T) { } buf := new(bytes.Buffer) - if err := cg.ChainStore().Export(context.TODO(), last, 0, buf); err != nil { + if err := cg.ChainStore().Export(context.TODO(), last, 0, false, buf); err != nil { t.Fatal(err) } diff --git a/cmd/lotus-shed/export.go b/cmd/lotus-shed/export.go new file mode 100644 index 000000000..6fa8d63f6 --- /dev/null +++ b/cmd/lotus-shed/export.go @@ -0,0 +1,123 @@ +package main + +import ( + "context" + "fmt" + "os" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" + + "github.com/filecoin-project/go-state-types/abi" + "github.com/filecoin-project/lotus/chain/store" + "github.com/filecoin-project/lotus/chain/types" + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/lib/blockstore" + "github.com/filecoin-project/lotus/node/repo" +) + +var exportChainCmd = &cli.Command{ + Name: "export", + Description: "Export chain from repo (requires node to be offline)", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "repo", + Value: "~/.lotus", + }, + &cli.StringFlag{ + Name: "tipset", + Usage: "tipset to export from", + }, + &cli.Int64Flag{ + Name: "recent-stateroots", + }, + &cli.BoolFlag{ + Name: "full-state", + }, + &cli.BoolFlag{ + Name: "skip-old-msgs", + }, + }, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return lcli.ShowHelp(cctx, fmt.Errorf("must specifiy file name to write export to")) + } + + ctx := context.TODO() + + r, err := repo.NewFS(cctx.String("repo")) + if err != nil { + return xerrors.Errorf("opening fs repo: %w", err) + } + + exists, err := r.Exists() + if err != nil { + return err + } + if !exists { + return xerrors.Errorf("lotus repo doesn't exist") + } + + lr, err := r.Lock(repo.FullNode) + if err != nil { + return err + } + defer lr.Close() //nolint:errcheck + + fi, err := os.Create(cctx.Args().First()) + if err != nil { + return xerrors.Errorf("opening the output file: %w", err) + } + + defer fi.Close() + + ds, err := lr.Datastore("/chain") + if err != nil { + return err + } + + mds, err := lr.Datastore("/metadata") + if err != nil { + return err + } + + bs := blockstore.NewBlockstore(ds) + + cs := store.NewChainStore(bs, mds, nil) + if err := cs.Load(); err != nil { + return err + } + + nroots := abi.ChainEpoch(cctx.Int64("recent-stateroots")) + fullstate := cctx.Bool("full-state") + skipoldmsgs := cctx.Bool("skip-old-msgs") + + var ts *types.TipSet + if tss := cctx.String("tipset"); tss != "" { + cids, err := lcli.ParseTipSetString(tss) + if err != nil { + return xerrors.Errorf("failed to parse tipset (%q): %w", tss, err) + } + + tsk := types.NewTipSetKey(cids...) + + selts, err := cs.LoadTipSet(tsk) + if err != nil { + return xerrors.Errorf("loading tipset: %w", err) + } + ts = selts + } else { + ts = cs.GetHeaviestTipSet() + } + + if fullstate { + nroots = ts.Height() + 1 + } + + if err := cs.Export(ctx, ts, nroots, skipoldmsgs, fi); err != nil { + return xerrors.Errorf("export failed: %w", err) + } + + return nil + }, +} diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index 4944b67aa..cff3059b6 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -34,6 +34,7 @@ func main() { genesisVerifyCmd, mathCmd, mpoolStatsCmd, + exportChainCmd, } app := &cli.App{ diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index c5dd5c9a9..13b9dd00b 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -508,7 +508,7 @@ func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk t bw := bufio.NewWriterSize(w, 1<<20) defer bw.Flush() //nolint:errcheck // it is a write to a pipe - if err := a.Chain.Export(ctx, ts, nroots, bw); err != nil { + if err := a.Chain.Export(ctx, ts, nroots, false, bw); err != nil { log.Errorf("chain export call failed: %s", err) return } From 0efe5ee7d5c2e23e188a8990eeafb158b947bcef Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Thu, 10 Sep 2020 17:32:30 -0700 Subject: [PATCH 185/199] include some other changes --- cli/state.go | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/cli/state.go b/cli/state.go index f84375782..1036e8fe5 100644 --- a/cli/state.go +++ b/cli/state.go @@ -27,6 +27,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/exitcode" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/exported" @@ -122,7 +123,7 @@ var stateMinerInfo = &cli.Command{ }, } -func parseTipSetString(ts string) ([]cid.Cid, error) { +func ParseTipSetString(ts string) ([]cid.Cid, error) { strs := strings.Split(ts, ",") var cids []cid.Cid @@ -160,7 +161,7 @@ func ParseTipSetRef(ctx context.Context, api api.FullNode, tss string) (*types.T return api.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(h), types.EmptyTSK) } - cids, err := parseTipSetString(tss) + cids, err := ParseTipSetString(tss) if err != nil { return nil, err } @@ -1384,7 +1385,7 @@ var stateCallCmd = &cli.Command{ } if ret.MsgRct.ExitCode != 0 { - return fmt.Errorf("invocation failed (exit: %d): %s", ret.MsgRct.ExitCode, ret.Error) + return fmt.Errorf("invocation failed (exit: %d, gasUsed: %d): %s", ret.MsgRct.ExitCode, ret.MsgRct.GasUsed, ret.Error) } s, err := formatOutput(cctx.String("ret"), ret.MsgRct.Return) @@ -1392,6 +1393,7 @@ var stateCallCmd = &cli.Command{ return fmt.Errorf("failed to format output: %s", err) } + fmt.Printf("gas used: %d\n", ret.MsgRct.GasUsed) fmt.Printf("return: %s\n", s) return nil @@ -1465,11 +1467,11 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er f := methods[method] rf := reflect.TypeOf(f) - if rf.NumIn() != 3 { + if rf.NumIn() != 2 { return nil, fmt.Errorf("expected referenced method to have three arguments") } - paramObj := rf.In(2).Elem() + paramObj := rf.In(1).Elem() if paramObj.NumField() != len(args) { return nil, fmt.Errorf("not enough arguments given to call that method (expecting %d)", paramObj.NumField()) } @@ -1489,6 +1491,18 @@ func parseParamsForMethod(act cid.Cid, method uint64, args []string) ([]byte, er return nil, err } p.Elem().Field(i).Set(reflect.ValueOf(val)) + case reflect.TypeOf(abi.ChainEpoch(0)): + val, err := strconv.ParseInt(args[i], 10, 64) + if err != nil { + return nil, err + } + p.Elem().Field(i).Set(reflect.ValueOf(abi.ChainEpoch(val))) + case reflect.TypeOf(big.Int{}): + val, err := big.FromString(args[i]) + if err != nil { + return nil, err + } + p.Elem().Field(i).Set(reflect.ValueOf(val)) case reflect.TypeOf(peer.ID("")): pid, err := peer.Decode(args[i]) if err != nil { From 72eb17d314e54886287e81f12aba4ee149c5479e Mon Sep 17 00:00:00 2001 From: whyrusleeping Date: Thu, 10 Sep 2020 17:40:47 -0700 Subject: [PATCH 186/199] wire skip old messages option through the api --- api/api_full.go | 3 ++- api/apistruct/struct.go | 6 +++--- cli/chain.go | 11 ++++++++++- node/impl/full/chain.go | 4 ++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index a604028fb..23226443a 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -118,7 +118,8 @@ type FullNode interface { // The exported chain data includes the header chain from the given tipset // back to genesis, the entire genesis state, and the most recent 'nroots' // state trees. - ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) + // If oldmsgskip is set, messages from before the requested roots are also not included. + ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error) // MethodGroup: Beacon // The Beacon method group contains methods for interacting with the random beacon (DRAND) diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 6f32d204b..fdb9843ff 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -95,7 +95,7 @@ type FullNodeStruct struct { ChainGetNode func(ctx context.Context, p string) (*api.IpldObject, error) `perm:"read"` ChainGetMessage func(context.Context, cid.Cid) (*types.Message, error) `perm:"read"` ChainGetPath func(context.Context, types.TipSetKey, types.TipSetKey) ([]*api.HeadChange, error) `perm:"read"` - ChainExport func(context.Context, abi.ChainEpoch, types.TipSetKey) (<-chan []byte, error) `perm:"read"` + ChainExport func(context.Context, abi.ChainEpoch, bool, types.TipSetKey) (<-chan []byte, error) `perm:"read"` BeaconGetEntry func(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"` @@ -692,8 +692,8 @@ func (c *FullNodeStruct) ChainGetPath(ctx context.Context, from types.TipSetKey, return c.Internal.ChainGetPath(ctx, from, to) } -func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) { - return c.Internal.ChainExport(ctx, nroots, tsk) +func (c *FullNodeStruct) ChainExport(ctx context.Context, nroots abi.ChainEpoch, iom bool, tsk types.TipSetKey) (<-chan []byte, error) { + return c.Internal.ChainExport(ctx, nroots, iom, tsk) } func (c *FullNodeStruct) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch) (*types.BeaconEntry, error) { diff --git a/cli/chain.go b/cli/chain.go index ce1660641..36288c7d7 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -844,6 +844,9 @@ var chainExportCmd = &cli.Command{ Name: "recent-stateroots", Usage: "specify the number of recent state roots to include in the export", }, + &cli.BoolFlag{ + Name: "skip-old-msgs", + }, }, Action: func(cctx *cli.Context) error { api, closer, err := GetFullNodeAPI(cctx) @@ -878,7 +881,13 @@ var chainExportCmd = &cli.Command{ return err } - stream, err := api.ChainExport(ctx, rsrs, ts.Key()) + skipold := cctx.Bool("skip-old-msgs") + + if rsrs == 0 && skipold { + return fmt.Errorf("must pass recent stateroots along with skip-old-msgs") + } + + stream, err := api.ChainExport(ctx, rsrs, skipold, ts.Key()) if err != nil { return err } diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 13b9dd00b..ad2c2944c 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -495,7 +495,7 @@ func (a *ChainAPI) ChainGetMessage(ctx context.Context, mc cid.Cid) (*types.Mess return cm.VMMessage(), nil } -func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk types.TipSetKey) (<-chan []byte, error) { +func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, skipoldmsgs bool, tsk types.TipSetKey) (<-chan []byte, error) { ts, err := a.Chain.GetTipSetFromKey(tsk) if err != nil { return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err) @@ -508,7 +508,7 @@ func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, tsk t bw := bufio.NewWriterSize(w, 1<<20) defer bw.Flush() //nolint:errcheck // it is a write to a pipe - if err := a.Chain.Export(ctx, ts, nroots, false, bw); err != nil { + if err := a.Chain.Export(ctx, ts, nroots, skipoldmsgs, bw); err != nil { log.Errorf("chain export call failed: %s", err) return } From c4b3970c70cd01537cfeb914448108c17833cdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 11 Sep 2020 10:41:24 +0200 Subject: [PATCH 187/199] mod tidy --- go.sum | 5 ----- 1 file changed, 5 deletions(-) diff --git a/go.sum b/go.sum index 18ebc816f..1d18f7b42 100644 --- a/go.sum +++ b/go.sum @@ -211,13 +211,10 @@ 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/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= -github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= github.com/filecoin-project/go-address v0.0.3 h1:eVfbdjEbpbzIrbiSa+PiGUY+oDK9HnUn+M1R/ggoHf8= github.com/filecoin-project/go-address v0.0.3/go.mod h1:jr8JxKsYx+lQlQZmF5i2U0Z+cGQ59wMIps/8YW/lDj8= -github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= -github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= github.com/filecoin-project/go-bitfield v0.2.0 h1:gCtLcjskIPtdg4NfN7gQZSQF9yrBQ7mkT0qCJxzGI2Q= github.com/filecoin-project/go-bitfield v0.2.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:av5fw6wmm58FYMgJeoB/lK9XXrgdugYiTqkdxjTy9k8= @@ -253,7 +250,6 @@ github.com/filecoin-project/go-statestore v0.1.0 h1:t56reH59843TwXHkMcwyuayStBIi github.com/filecoin-project/go-statestore v0.1.0/go.mod h1:LFc9hD+fRxPqiHiaqUEZOinUJB4WARkRfNl10O7kTnI= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b h1:fkRZSPrYpk42PV3/lIXiL0LHetxde7vyYYvSsttQtfg= github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/go.mod h1:Q0GQOBtKf1oE10eSXSlhN45kDBdGvEcVOqMiffqX+N8= -github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= github.com/filecoin-project/specs-actors v0.9.4/go.mod h1:BStZQzx5x7TmCkLv0Bpa07U6cPKol6fd3w9KjMPZ6Z4= github.com/filecoin-project/specs-actors v0.9.7 h1:7PAZ8kdqwBdmgf/23FCkQZLCXcVu02XJrkpkhBikiA8= github.com/filecoin-project/specs-actors v0.9.7/go.mod h1:wM2z+kwqYgXn5Z7scV1YHLyd1Q1cy0R8HfTIWQ0BFGU= @@ -508,7 +504,6 @@ github.com/ipfs/go-fs-lock v0.0.6/go.mod h1:OTR+Rj9sHiRubJh3dRhD15Juhd/+w6VPOY28 github.com/ipfs/go-graphsync v0.1.0/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= github.com/ipfs/go-graphsync v0.1.2 h1:25Ll9kIXCE+DY0dicvfS3KMw+U5sd01b/FJbA7KAbhg= github.com/ipfs/go-graphsync v0.1.2/go.mod h1:sLXVXm1OxtE2XYPw62MuXCdAuNwkAdsbnfrmos5odbA= -github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk= github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= From aeb3437a9fd7e9a9cb71bb77af678b46420561a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 11 Sep 2020 10:55:10 +0200 Subject: [PATCH 188/199] lint, docsgen --- cmd/lotus-shed/export.go | 4 ++-- documentation/en/api-methods.md | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/lotus-shed/export.go b/cmd/lotus-shed/export.go index 6fa8d63f6..c12cbd82d 100644 --- a/cmd/lotus-shed/export.go +++ b/cmd/lotus-shed/export.go @@ -40,7 +40,7 @@ var exportChainCmd = &cli.Command{ }, Action: func(cctx *cli.Context) error { if !cctx.Args().Present() { - return lcli.ShowHelp(cctx, fmt.Errorf("must specifiy file name to write export to")) + return lcli.ShowHelp(cctx, fmt.Errorf("must specify file name to write export to")) } ctx := context.TODO() @@ -69,7 +69,7 @@ var exportChainCmd = &cli.Command{ return xerrors.Errorf("opening the output file: %w", err) } - defer fi.Close() + defer fi.Close() //nolint:errcheck ds, err := lr.Datastore("/chain") if err != nil { diff --git a/documentation/en/api-methods.md b/documentation/en/api-methods.md index 7c2d91881..27875eca1 100644 --- a/documentation/en/api-methods.md +++ b/documentation/en/api-methods.md @@ -284,6 +284,7 @@ ChainExport returns a stream of bytes with CAR dump of chain data. The exported chain data includes the header chain from the given tipset back to genesis, the entire genesis state, and the most recent 'nroots' state trees. +If oldmsgskip is set, messages from before the requested roots are also not included. Perms: read @@ -292,6 +293,7 @@ Inputs: ```json [ 10101, + true, [ { "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" From 3dfb3e641b5edad5a19d1df738f52c5f164f2558 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 11 Sep 2020 12:15:03 +0300 Subject: [PATCH 189/199] refactor getBaseFeeLowerBound, use it to prune less aggressively --- chain/messagepool/messagepool.go | 11 ++++++++++- chain/messagepool/pruning.go | 3 ++- chain/messagepool/repub.go | 6 +----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index 06cbe65e7..88fb1dcfc 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -399,7 +399,7 @@ func (mp *MessagePool) verifyMsgBeforeAdd(m *types.SignedMessage, curTs *types.T publish := local if strictBaseFeeValidation && len(curTs.Blocks()) > 0 { baseFee := curTs.Blocks()[0].ParentBaseFee - baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) + baseFeeLowerBound := getBaseFeeLowerBound(baseFee) if m.Message.GasFeeCap.LessThan(baseFeeLowerBound) { if local { log.Warnf("local message will not be immediately published because GasFeeCap doesn't meet the lower bound for inclusion in the next 20 blocks (GasFeeCap: %s, baseFeeLowerBound: %s)", @@ -1282,3 +1282,12 @@ func (mp *MessagePool) Clear(local bool) { delete(mp.pending, a) } } + +func getBaseFeeLowerBound(baseFee types.BigInt) types.BigInt { + baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) + if baseFeeLowerBound.LessThan(minimumBaseFee) { + baseFeeLowerBound = minimumBaseFee + } + + return baseFeeLowerBound +} diff --git a/chain/messagepool/pruning.go b/chain/messagepool/pruning.go index d1290e386..76b183808 100644 --- a/chain/messagepool/pruning.go +++ b/chain/messagepool/pruning.go @@ -46,6 +46,7 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro if err != nil { return xerrors.Errorf("computing basefee: %w", err) } + baseFeeLowerBound := getBaseFeeLowerBound(baseFee) pending, _ := mp.getPendingMessages(ts, ts) @@ -72,7 +73,7 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro for _, m := range mset { pruneMsgs[m.Message.Cid()] = m } - actorChains := mp.createMessageChains(actor, mset, baseFee, ts) + actorChains := mp.createMessageChains(actor, mset, baseFeeLowerBound, ts) chains = append(chains, actorChains...) } diff --git a/chain/messagepool/repub.go b/chain/messagepool/repub.go index fd0324d0a..7e651e426 100644 --- a/chain/messagepool/repub.go +++ b/chain/messagepool/repub.go @@ -27,11 +27,7 @@ func (mp *MessagePool) republishPendingMessages() error { mp.curTsLk.Unlock() return xerrors.Errorf("computing basefee: %w", err) } - - baseFeeLowerBound := types.BigDiv(baseFee, baseFeeLowerBoundFactor) - if baseFeeLowerBoundFactor.LessThan(minimumBaseFee) { - baseFeeLowerBound = minimumBaseFee - } + baseFeeLowerBound := getBaseFeeLowerBound(baseFee) pending := make(map[address.Address]map[uint64]*types.SignedMessage) mp.lk.Lock() From 62b2963781300ad9ac8bbdc4c6255f6886299a0c Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Fri, 11 Sep 2020 16:58:09 +0530 Subject: [PATCH 190/199] retry add piece --- extern/storage-sealing/sealing.go | 4 +++- markets/storageadapter/provider.go | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/extern/storage-sealing/sealing.go b/extern/storage-sealing/sealing.go index 45b95e18c..28df664aa 100644 --- a/extern/storage-sealing/sealing.go +++ b/extern/storage-sealing/sealing.go @@ -28,6 +28,8 @@ import ( const SectorStorePrefix = "/sectors" +var ErrTooManySectorsSealing = xerrors.New("too many sectors sealing") + var log = logging.Logger("sectors") type SectorLocation struct { @@ -280,7 +282,7 @@ func (m *Sealing) newDealSector() (abi.SectorNumber, error) { if cfg.MaxSealingSectorsForDeals > 0 { if m.stats.curSealing() > cfg.MaxSealingSectorsForDeals { - return 0, xerrors.Errorf("too many sectors sealing") + return 0, ErrTooManySectorsSealing } } diff --git a/markets/storageadapter/provider.go b/markets/storageadapter/provider.go index 9c4a5946e..677e21455 100644 --- a/markets/storageadapter/provider.go +++ b/markets/storageadapter/provider.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "io" + "time" "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" @@ -35,6 +36,7 @@ import ( "github.com/filecoin-project/lotus/storage/sectorblocks" ) +var addPieceRetryWait = 5 * time.Minute var log = logging.Logger("storageadapter") type ProviderNodeAdapter struct { @@ -91,7 +93,7 @@ func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagema return nil, xerrors.Errorf("deal.PublishCid can't be nil") } - p, offset, err := n.secb.AddPiece(ctx, pieceSize, pieceData, sealing.DealInfo{ + sdInfo := sealing.DealInfo{ DealID: deal.DealID, PublishCid: deal.PublishCid, DealSchedule: sealing.DealSchedule{ @@ -99,7 +101,18 @@ func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagema EndEpoch: deal.ClientDealProposal.Proposal.EndEpoch, }, KeepUnsealed: deal.FastRetrieval, - }) + } + + p, offset, err := n.secb.AddPiece(ctx, pieceSize, pieceData, sdInfo) + if xerrors.Is(err, sealing.ErrTooManySectorsSealing) { + select { + case <-time.After(addPieceRetryWait): + p, offset, err = n.secb.AddPiece(ctx, pieceSize, pieceData, sdInfo) + case <-ctx.Done(): + return nil, xerrors.New("context expired while waiting to retry AddPiece") + } + } + if err != nil { return nil, xerrors.Errorf("AddPiece failed: %s", err) } From 16f7d5801b5d8c815a38cffe89d96a27928525f2 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Fri, 11 Sep 2020 15:25:59 +0100 Subject: [PATCH 191/199] fix: chaos tests --- conformance/chaos/actor_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conformance/chaos/actor_test.go b/conformance/chaos/actor_test.go index 97c3b85cf..a08267022 100644 --- a/conformance/chaos/actor_test.go +++ b/conformance/chaos/actor_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/exitcode" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/support/mock" atesting "github.com/filecoin-project/specs-actors/support/testing" ) @@ -19,7 +19,7 @@ func TestSingleton(t *testing.T) { msg := "constructor should not be called; the Chaos actor is a singleton actor" rt.ExpectAssertionFailure(msg, func() { - rt.Call(a.Constructor, adt.Empty) + rt.Call(a.Constructor, abi.Empty) }) rt.Verify() } From cf9820137cbc1bea526256f4ac861530341a0d94 Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 11 Sep 2020 20:32:52 +0300 Subject: [PATCH 192/199] don't prune locally published messages --- chain/messagepool/pruning.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/chain/messagepool/pruning.go b/chain/messagepool/pruning.go index 76b183808..cd20b462b 100644 --- a/chain/messagepool/pruning.go +++ b/chain/messagepool/pruning.go @@ -56,6 +56,13 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro priority[actor] = struct{}{} } + // we also never prune locally published messages + mp.lk.Lock() + for actor := range mp.localAddrs { + priority[actor] = struct{}{} + } + mp.lk.Unlock() + // Collect all messages to track which ones to remove and create chains for block inclusion pruneMsgs := make(map[cid.Cid]*types.SignedMessage, mp.currentSize) keepCount := 0 From eabdf74946e7668334d11a2ed760012791f43dea Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Fri, 11 Sep 2020 23:15:57 +0530 Subject: [PATCH 193/199] changes as per review --- markets/storageadapter/provider.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/markets/storageadapter/provider.go b/markets/storageadapter/provider.go index 677e21455..ed714ab61 100644 --- a/markets/storageadapter/provider.go +++ b/markets/storageadapter/provider.go @@ -37,6 +37,7 @@ import ( ) var addPieceRetryWait = 5 * time.Minute +var addPieceRetryTimeout = 6 * time.Hour var log = logging.Logger("storageadapter") type ProviderNodeAdapter struct { @@ -104,7 +105,11 @@ func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagema } p, offset, err := n.secb.AddPiece(ctx, pieceSize, pieceData, sdInfo) - if xerrors.Is(err, sealing.ErrTooManySectorsSealing) { + curTime := time.Now() + for time.Since(curTime) < addPieceRetryTimeout { + if !xerrors.Is(err, sealing.ErrTooManySectorsSealing) { + break + } select { case <-time.After(addPieceRetryWait): p, offset, err = n.secb.AddPiece(ctx, pieceSize, pieceData, sdInfo) From 2e3ff9e4017eadad0a277d02ecbb26193279a2be Mon Sep 17 00:00:00 2001 From: Ingar Shu Date: Fri, 11 Sep 2020 11:00:42 -0700 Subject: [PATCH 194/199] Update market client/provider adapters to WaitForMessage API --- go.mod | 2 +- go.sum | 4 ++-- markets/storageadapter/client.go | 6 +++--- markets/storageadapter/provider.go | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 901f990b1..4cedea65f 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 github.com/filecoin-project/go-data-transfer v0.6.3 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.6.0 + github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 github.com/filecoin-project/go-multistore v0.0.3 github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20 diff --git a/go.sum b/go.sum index c91d316e7..d5eb25358 100644 --- a/go.sum +++ b/go.sum @@ -227,8 +227,8 @@ github.com/filecoin-project/go-data-transfer v0.6.3 h1:7TLwm8nuodHYD/uiwJjKc/PGR github.com/filecoin-project/go-data-transfer v0.6.3/go.mod h1:PmBKVXkhh67/tnEdJXQwDHl5mT+7Tbcwe1NPninqhnM= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= -github.com/filecoin-project/go-fil-markets v0.6.0 h1:gfxMweUHo4u+2BZh2Q7/7+cV0/ttikuJfhkkxLRsE2Q= -github.com/filecoin-project/go-fil-markets v0.6.0/go.mod h1:LhSFYLkjaoe0vFRKABGYyw1Jz+9jCpF1sPA7yOftLTw= +github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c h1:YGoyYmELQ0LHwDj/WcOvY3oYt+3iM0wdrAhqJQUAIy4= +github.com/filecoin-project/go-fil-markets v0.6.1-0.20200911011457-2959ccca6a3c/go.mod h1:PLr9svZxsnHkae1Ky7+66g7fP9AlneVxIVu+oSMq56A= github.com/filecoin-project/go-hamt-ipld v0.1.5 h1:uoXrKbCQZ49OHpsTCkrThPNelC4W3LPEk0OrS/ytIBM= github.com/filecoin-project/go-hamt-ipld v0.1.5/go.mod h1:6Is+ONR5Cd5R6XZoCse1CWaXZc0Hdb/JeX+EQCQzX24= github.com/filecoin-project/go-jsonrpc v0.1.2-0.20200822201400-474f4fdccc52 h1:FXtCp0ybqdQL9knb3OGDpkNTaBbPxgkqPeWKotUwkH0= diff --git a/markets/storageadapter/client.go b/markets/storageadapter/client.go index 4f7361d00..4168792da 100644 --- a/markets/storageadapter/client.go +++ b/markets/storageadapter/client.go @@ -501,12 +501,12 @@ func (c *ClientNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetToke return head.Key().Bytes(), head.Height(), nil } -func (c *ClientNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error { +func (c *ClientNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, finalCid cid.Cid, err error) error) error { receipt, err := c.StateWaitMsg(ctx, mcid, build.MessageConfidence) if err != nil { - return cb(0, nil, err) + return cb(0, nil, cid.Undef, err) } - return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil) + return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, receipt.Message, nil) } func (c *ClientNodeAdapter) GetMinerInfo(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*storagemarket.StorageProviderInfo, error) { diff --git a/markets/storageadapter/provider.go b/markets/storageadapter/provider.go index 9c4a5946e..49be6fe41 100644 --- a/markets/storageadapter/provider.go +++ b/markets/storageadapter/provider.go @@ -355,12 +355,12 @@ func (n *ProviderNodeAdapter) GetChainHead(ctx context.Context) (shared.TipSetTo return head.Key().Bytes(), head.Height(), nil } -func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, err error) error) error { +func (n *ProviderNodeAdapter) WaitForMessage(ctx context.Context, mcid cid.Cid, cb func(code exitcode.ExitCode, bytes []byte, finalCid cid.Cid, err error) error) error { receipt, err := n.StateWaitMsg(ctx, mcid, 2*build.MessageConfidence) if err != nil { - return cb(0, nil, err) + return cb(0, nil, cid.Undef, err) } - return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, nil) + return cb(receipt.Receipt.ExitCode, receipt.Receipt.Return, receipt.Message, nil) } func (n *ProviderNodeAdapter) GetDataCap(ctx context.Context, addr address.Address, encodedTs shared.TipSetToken) (*verifreg.DataCap, error) { From bf1036c78fa694f9fe8f4cad5cbce3d88d06c61c Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 11 Sep 2020 21:12:11 +0300 Subject: [PATCH 195/199] rename priority variable to protected --- chain/messagepool/pruning.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/chain/messagepool/pruning.go b/chain/messagepool/pruning.go index cd20b462b..f40007f34 100644 --- a/chain/messagepool/pruning.go +++ b/chain/messagepool/pruning.go @@ -50,16 +50,18 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro pending, _ := mp.getPendingMessages(ts, ts) - // priority actors -- not pruned - priority := make(map[address.Address]struct{}) + // protected actors -- not pruned + protected := make(map[address.Address]struct{}) + + // we never prune priority addresses for _, actor := range mp.cfg.PriorityAddrs { - priority[actor] = struct{}{} + protected[actor] = struct{}{} } // we also never prune locally published messages mp.lk.Lock() for actor := range mp.localAddrs { - priority[actor] = struct{}{} + protected[actor] = struct{}{} } mp.lk.Unlock() @@ -69,14 +71,14 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro var chains []*msgChain for actor, mset := range pending { - // we never prune priority actors - _, keep := priority[actor] + // we never prune protected actors + _, keep := protected[actor] if keep { keepCount += len(mset) continue } - // not a priority actor, track the messages and create chains + // not a protected actor, track the messages and create chains for _, m := range mset { pruneMsgs[m.Message.Cid()] = m } From b78fe0b8980bbac20dd980d793cf006b2fd7f35c Mon Sep 17 00:00:00 2001 From: vyzo Date: Fri, 11 Sep 2020 21:40:25 +0300 Subject: [PATCH 196/199] fix deadlock --- chain/messagepool/pruning.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/chain/messagepool/pruning.go b/chain/messagepool/pruning.go index f40007f34..fd8199b89 100644 --- a/chain/messagepool/pruning.go +++ b/chain/messagepool/pruning.go @@ -59,11 +59,9 @@ func (mp *MessagePool) pruneMessages(ctx context.Context, ts *types.TipSet) erro } // we also never prune locally published messages - mp.lk.Lock() for actor := range mp.localAddrs { protected[actor] = struct{}{} } - mp.lk.Unlock() // Collect all messages to track which ones to remove and create chains for block inclusion pruneMsgs := make(map[cid.Cid]*types.SignedMessage, mp.currentSize) From d5aef296ea18cc39f99d9bbd0de4a71831e58faf Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Fri, 11 Sep 2020 21:59:51 +0200 Subject: [PATCH 197/199] Increase the FeeCap estimation to 20 blocks in a future FeeCap will be set to 10x the current running rate Signed-off-by: Jakub Sztandera --- node/impl/full/gas.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 40ab88b6b..c1f3bd16c 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -204,7 +204,7 @@ func (a *GasAPI) GasEstimateMessageGas(ctx context.Context, msg *types.Message, } if msg.GasFeeCap == types.EmptyInt || types.BigCmp(msg.GasFeeCap, types.NewInt(0)) == 0 { - feeCap, err := a.GasEstimateFeeCap(ctx, msg, 10, types.EmptyTSK) + feeCap, err := a.GasEstimateFeeCap(ctx, msg, 20, types.EmptyTSK) if err != nil { return nil, xerrors.Errorf("estimating fee cap: %w", err) } From 6c61ff0e9e0f7118cc0ccb3a42151dccbf8c1ce7 Mon Sep 17 00:00:00 2001 From: Aarsh Shah Date: Mon, 14 Sep 2020 12:04:50 +0530 Subject: [PATCH 198/199] log error --- markets/storageadapter/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/markets/storageadapter/provider.go b/markets/storageadapter/provider.go index ed714ab61..50773af93 100644 --- a/markets/storageadapter/provider.go +++ b/markets/storageadapter/provider.go @@ -108,6 +108,7 @@ func (n *ProviderNodeAdapter) OnDealComplete(ctx context.Context, deal storagema curTime := time.Now() for time.Since(curTime) < addPieceRetryTimeout { if !xerrors.Is(err, sealing.ErrTooManySectorsSealing) { + log.Errorf("failed to addPiece for deal %d, err: %w", deal.DealID, err) break } select { From dcae513487524eb4dd3feb6cacaf205fe7b9a19d Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 14 Sep 2020 16:49:35 +0800 Subject: [PATCH 199/199] make nested dir --- node/repo/fsrepo.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/repo/fsrepo.go b/node/repo/fsrepo.go index 14085d4ac..709d78d3a 100644 --- a/node/repo/fsrepo.go +++ b/node/repo/fsrepo.go @@ -101,7 +101,7 @@ func (fsr *FsRepo) Init(t RepoType) error { } log.Infof("Initializing repo at '%s'", fsr.path) - err = os.Mkdir(fsr.path, 0755) //nolint: gosec + err = os.MkdirAll(fsr.path, 0755) //nolint: gosec if err != nil && !os.IsExist(err) { return err }