Merge pull request #7404 from filecoin-project/asr/specs-update
Update to actors master
This commit is contained in:
commit
89d61ca238
@ -1,6 +1,7 @@
|
||||
package market
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@ -103,7 +104,28 @@ type DealProposals interface {
|
||||
}
|
||||
|
||||
type PublishStorageDealsParams = market0.PublishStorageDealsParams
|
||||
type PublishStorageDealsReturn = market0.PublishStorageDealsReturn
|
||||
|
||||
type PublishStorageDealsReturn interface {
|
||||
DealIDs() ([]abi.DealID, error)
|
||||
// Note that this index is based on the batch of deals that were published, NOT the DealID
|
||||
IsDealValid(index uint64) (bool, error)
|
||||
}
|
||||
|
||||
func DecodePublishStorageDealsReturn(b []byte, nv network.Version) (PublishStorageDealsReturn, error) {
|
||||
av, err := actors.VersionForNetwork(nv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch av {
|
||||
{{range .versions}}
|
||||
case actors.Version{{.}}:
|
||||
return decodePublishStorageDealsReturn{{.}}(b)
|
||||
{{end}}
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor version %d", av)
|
||||
}
|
||||
|
||||
type VerifyDealsForActivationParams = market0.VerifyDealsForActivationParams
|
||||
type WithdrawBalanceParams = market0.WithdrawBalanceParams
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package market
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@ -177,7 +178,43 @@ type DealProposals interface {
|
||||
}
|
||||
|
||||
type PublishStorageDealsParams = market0.PublishStorageDealsParams
|
||||
type PublishStorageDealsReturn = market0.PublishStorageDealsReturn
|
||||
|
||||
type PublishStorageDealsReturn interface {
|
||||
DealIDs() ([]abi.DealID, error)
|
||||
// Note that this index is based on the batch of deals that were published, NOT the DealID
|
||||
IsDealValid(index uint64) (bool, error)
|
||||
}
|
||||
|
||||
func DecodePublishStorageDealsReturn(b []byte, nv network.Version) (PublishStorageDealsReturn, error) {
|
||||
av, err := actors.VersionForNetwork(nv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch av {
|
||||
|
||||
case actors.Version0:
|
||||
return decodePublishStorageDealsReturn0(b)
|
||||
|
||||
case actors.Version2:
|
||||
return decodePublishStorageDealsReturn2(b)
|
||||
|
||||
case actors.Version3:
|
||||
return decodePublishStorageDealsReturn3(b)
|
||||
|
||||
case actors.Version4:
|
||||
return decodePublishStorageDealsReturn4(b)
|
||||
|
||||
case actors.Version5:
|
||||
return decodePublishStorageDealsReturn5(b)
|
||||
|
||||
case actors.Version6:
|
||||
return decodePublishStorageDealsReturn6(b)
|
||||
|
||||
}
|
||||
return nil, xerrors.Errorf("unknown actor version %d", av)
|
||||
}
|
||||
|
||||
type VerifyDealsForActivationParams = market0.VerifyDealsForActivationParams
|
||||
type WithdrawBalanceParams = market0.WithdrawBalanceParams
|
||||
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -236,3 +237,31 @@ func fromV{{.v}}DealProposal(v{{.v}} market{{.v}}.DealProposal) DealProposal {
|
||||
func (s *state{{.v}}) GetState() interface{} {
|
||||
return &s.State
|
||||
}
|
||||
|
||||
var _ PublishStorageDealsReturn = (*publishStorageDealsReturn{{.v}})(nil)
|
||||
|
||||
func decodePublishStorageDealsReturn{{.v}}(b []byte) (PublishStorageDealsReturn, error) {
|
||||
var retval market{{.v}}.PublishStorageDealsReturn
|
||||
if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
||||
return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err)
|
||||
}
|
||||
|
||||
return &publishStorageDealsReturn{{.v}}{retval}, nil
|
||||
}
|
||||
|
||||
type publishStorageDealsReturn{{.v}} struct {
|
||||
market{{.v}}.PublishStorageDealsReturn
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn{{.v}}) IsDealValid(index uint64) (bool, error) {
|
||||
{{if (ge .v 6)}}
|
||||
return r.ValidDeals.IsSet(index)
|
||||
{{else}}
|
||||
// PublishStorageDeals only succeeded if all deals were valid in this version of actors
|
||||
return true, nil
|
||||
{{end}}
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn{{.v}}) DealIDs() ([]abi.DealID, error) {
|
||||
return r.IDs, nil
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -229,3 +230,29 @@ func fromV0DealProposal(v0 market0.DealProposal) DealProposal {
|
||||
func (s *state0) GetState() interface{} {
|
||||
return &s.State
|
||||
}
|
||||
|
||||
var _ PublishStorageDealsReturn = (*publishStorageDealsReturn0)(nil)
|
||||
|
||||
func decodePublishStorageDealsReturn0(b []byte) (PublishStorageDealsReturn, error) {
|
||||
var retval market0.PublishStorageDealsReturn
|
||||
if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
||||
return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err)
|
||||
}
|
||||
|
||||
return &publishStorageDealsReturn0{retval}, nil
|
||||
}
|
||||
|
||||
type publishStorageDealsReturn0 struct {
|
||||
market0.PublishStorageDealsReturn
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn0) IsDealValid(index uint64) (bool, error) {
|
||||
|
||||
// PublishStorageDeals only succeeded if all deals were valid in this version of actors
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn0) DealIDs() ([]abi.DealID, error) {
|
||||
return r.IDs, nil
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -229,3 +230,29 @@ func fromV2DealProposal(v2 market2.DealProposal) DealProposal {
|
||||
func (s *state2) GetState() interface{} {
|
||||
return &s.State
|
||||
}
|
||||
|
||||
var _ PublishStorageDealsReturn = (*publishStorageDealsReturn2)(nil)
|
||||
|
||||
func decodePublishStorageDealsReturn2(b []byte) (PublishStorageDealsReturn, error) {
|
||||
var retval market2.PublishStorageDealsReturn
|
||||
if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
||||
return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err)
|
||||
}
|
||||
|
||||
return &publishStorageDealsReturn2{retval}, nil
|
||||
}
|
||||
|
||||
type publishStorageDealsReturn2 struct {
|
||||
market2.PublishStorageDealsReturn
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn2) IsDealValid(index uint64) (bool, error) {
|
||||
|
||||
// PublishStorageDeals only succeeded if all deals were valid in this version of actors
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn2) DealIDs() ([]abi.DealID, error) {
|
||||
return r.IDs, nil
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -224,3 +225,29 @@ func fromV3DealProposal(v3 market3.DealProposal) DealProposal {
|
||||
func (s *state3) GetState() interface{} {
|
||||
return &s.State
|
||||
}
|
||||
|
||||
var _ PublishStorageDealsReturn = (*publishStorageDealsReturn3)(nil)
|
||||
|
||||
func decodePublishStorageDealsReturn3(b []byte) (PublishStorageDealsReturn, error) {
|
||||
var retval market3.PublishStorageDealsReturn
|
||||
if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
||||
return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err)
|
||||
}
|
||||
|
||||
return &publishStorageDealsReturn3{retval}, nil
|
||||
}
|
||||
|
||||
type publishStorageDealsReturn3 struct {
|
||||
market3.PublishStorageDealsReturn
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn3) IsDealValid(index uint64) (bool, error) {
|
||||
|
||||
// PublishStorageDeals only succeeded if all deals were valid in this version of actors
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn3) DealIDs() ([]abi.DealID, error) {
|
||||
return r.IDs, nil
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -224,3 +225,29 @@ func fromV4DealProposal(v4 market4.DealProposal) DealProposal {
|
||||
func (s *state4) GetState() interface{} {
|
||||
return &s.State
|
||||
}
|
||||
|
||||
var _ PublishStorageDealsReturn = (*publishStorageDealsReturn4)(nil)
|
||||
|
||||
func decodePublishStorageDealsReturn4(b []byte) (PublishStorageDealsReturn, error) {
|
||||
var retval market4.PublishStorageDealsReturn
|
||||
if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
||||
return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err)
|
||||
}
|
||||
|
||||
return &publishStorageDealsReturn4{retval}, nil
|
||||
}
|
||||
|
||||
type publishStorageDealsReturn4 struct {
|
||||
market4.PublishStorageDealsReturn
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn4) IsDealValid(index uint64) (bool, error) {
|
||||
|
||||
// PublishStorageDeals only succeeded if all deals were valid in this version of actors
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn4) DealIDs() ([]abi.DealID, error) {
|
||||
return r.IDs, nil
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -224,3 +225,29 @@ func fromV5DealProposal(v5 market5.DealProposal) DealProposal {
|
||||
func (s *state5) GetState() interface{} {
|
||||
return &s.State
|
||||
}
|
||||
|
||||
var _ PublishStorageDealsReturn = (*publishStorageDealsReturn5)(nil)
|
||||
|
||||
func decodePublishStorageDealsReturn5(b []byte) (PublishStorageDealsReturn, error) {
|
||||
var retval market5.PublishStorageDealsReturn
|
||||
if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
||||
return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err)
|
||||
}
|
||||
|
||||
return &publishStorageDealsReturn5{retval}, nil
|
||||
}
|
||||
|
||||
type publishStorageDealsReturn5 struct {
|
||||
market5.PublishStorageDealsReturn
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn5) IsDealValid(index uint64) (bool, error) {
|
||||
|
||||
// PublishStorageDeals only succeeded if all deals were valid in this version of actors
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn5) DealIDs() ([]abi.DealID, error) {
|
||||
return r.IDs, nil
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -224,3 +225,28 @@ func fromV6DealProposal(v6 market6.DealProposal) DealProposal {
|
||||
func (s *state6) GetState() interface{} {
|
||||
return &s.State
|
||||
}
|
||||
|
||||
var _ PublishStorageDealsReturn = (*publishStorageDealsReturn6)(nil)
|
||||
|
||||
func decodePublishStorageDealsReturn6(b []byte) (PublishStorageDealsReturn, error) {
|
||||
var retval market6.PublishStorageDealsReturn
|
||||
if err := retval.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
||||
return nil, xerrors.Errorf("failed to unmarshal PublishStorageDealsReturn: %w", err)
|
||||
}
|
||||
|
||||
return &publishStorageDealsReturn6{retval}, nil
|
||||
}
|
||||
|
||||
type publishStorageDealsReturn6 struct {
|
||||
market6.PublishStorageDealsReturn
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn6) IsDealValid(index uint64) (bool, error) {
|
||||
|
||||
return r.ValidDeals.IsSet(index)
|
||||
|
||||
}
|
||||
|
||||
func (r *publishStorageDealsReturn6) DealIDs() ([]abi.DealID, error) {
|
||||
return r.IDs, nil
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
@ -193,12 +195,22 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create genesis miner (publish deals): %w", err)
|
||||
}
|
||||
var ids market.PublishStorageDealsReturn
|
||||
if err := ids.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||
return xerrors.Errorf("unmarsahling publishStorageDeals result: %w", err)
|
||||
|
||||
retval, err := market.DecodePublishStorageDealsReturn(ret, nv)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create genesis miner (decoding published deals): %w", err)
|
||||
}
|
||||
|
||||
minerInfos[i].dealIDs = append(minerInfos[i].dealIDs, ids.IDs...)
|
||||
ids, err := retval.DealIDs()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to create genesis miner (getting published dealIDs): %w", err)
|
||||
}
|
||||
|
||||
if len(ids) != len(params.Deals) {
|
||||
return xerrors.Errorf("failed to create genesis miner (at least one deal was invalid on publication")
|
||||
}
|
||||
|
||||
minerInfos[i].dealIDs = append(minerInfos[i].dealIDs, ids...)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -389,11 +401,24 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sys vm.Syscal
|
||||
}
|
||||
|
||||
// Commit one-by-one, otherwise pledge math tends to explode
|
||||
confirmParams := &builtin0.ConfirmSectorProofsParams{
|
||||
Sectors: []abi.SectorNumber{preseal.SectorID},
|
||||
var paramBytes []byte
|
||||
|
||||
if av >= actors.Version6 {
|
||||
// TODO: fixup
|
||||
confirmParams := &builtin6.ConfirmSectorProofsParams{
|
||||
Sectors: []abi.SectorNumber{preseal.SectorID},
|
||||
}
|
||||
|
||||
paramBytes = mustEnc(confirmParams)
|
||||
} else {
|
||||
confirmParams := &builtin0.ConfirmSectorProofsParams{
|
||||
Sectors: []abi.SectorNumber{preseal.SectorID},
|
||||
}
|
||||
|
||||
paramBytes = mustEnc(confirmParams)
|
||||
}
|
||||
|
||||
_, err = doExecValue(ctx, vm, minerInfos[i].maddr, power.Address, big.Zero(), miner.Methods.ConfirmSectorProofsValid, mustEnc(confirmParams))
|
||||
_, err = doExecValue(ctx, vm, minerInfos[i].maddr, power.Address, big.Zero(), miner.Methods.ConfirmSectorProofsValid, paramBytes)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to confirm presealed sectors: %w", err)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@ -9,6 +10,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@ -528,6 +531,11 @@ var walletMarketWithdraw = &cli.Command{
|
||||
Usage: "Market address to withdraw from (account or miner actor address, defaults to --wallet address)",
|
||||
Aliases: []string{"a"},
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "confidence",
|
||||
Usage: "number of block confirmations to wait for",
|
||||
Value: int(build.MessageConfidence),
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
@ -614,6 +622,28 @@ var walletMarketWithdraw = &cli.Command{
|
||||
|
||||
fmt.Printf("WithdrawBalance message cid: %s\n", smsg)
|
||||
|
||||
// wait for it to get mined into a block
|
||||
wait, err := api.StateWaitMsg(ctx, smsg, uint64(cctx.Int("confidence")))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
fmt.Println(cctx.App.Writer, "withdrawal failed!")
|
||||
return err
|
||||
}
|
||||
|
||||
var withdrawn abi.TokenAmount
|
||||
if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully withdrew %s FIL\n", withdrawn)
|
||||
if withdrawn != amt {
|
||||
fmt.Printf("Note that this is less than the requested amount of %s FIL\n", amt)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
@ -207,6 +208,13 @@ var actorWithdrawCmd = &cli.Command{
|
||||
Name: "withdraw",
|
||||
Usage: "withdraw available balance",
|
||||
ArgsUsage: "[amount (FIL)]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.IntFlag{
|
||||
Name: "confidence",
|
||||
Usage: "number of block confirmations to wait for",
|
||||
Value: int(build.MessageConfidence),
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||
if err != nil {
|
||||
@ -271,6 +279,28 @@ var actorWithdrawCmd = &cli.Command{
|
||||
|
||||
fmt.Printf("Requested rewards withdrawal in message %s\n", smsg.Cid())
|
||||
|
||||
// wait for it to get mined into a block
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), uint64(cctx.Int("confidence")))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
fmt.Println(cctx.App.Writer, "withdrawal failed!")
|
||||
return err
|
||||
}
|
||||
|
||||
var withdrawn abi.TokenAmount
|
||||
if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully withdrew %s FIL\n", withdrawn)
|
||||
if withdrawn != amount {
|
||||
fmt.Printf("Note that this is less than the requested amount of %s FIL\n", amount)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@ -44,6 +45,11 @@ var actorWithdrawCmd = &cli.Command{
|
||||
Name: "actor",
|
||||
Usage: "specify the address of miner actor",
|
||||
},
|
||||
&cli.IntFlag{
|
||||
Name: "confidence",
|
||||
Usage: "number of block confirmations to wait for",
|
||||
Value: int(build.MessageConfidence),
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
var maddr address.Address
|
||||
@ -120,6 +126,28 @@ var actorWithdrawCmd = &cli.Command{
|
||||
|
||||
fmt.Printf("Requested rewards withdrawal in message %s\n", smsg.Cid())
|
||||
|
||||
// wait for it to get mined into a block
|
||||
wait, err := nodeAPI.StateWaitMsg(ctx, smsg.Cid(), uint64(cctx.Int("confidence")))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
fmt.Println(cctx.App.Writer, "withdrawal failed!")
|
||||
return err
|
||||
}
|
||||
|
||||
var withdrawn abi.TokenAmount
|
||||
if err := withdrawn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully withdrew %s FIL\n", withdrawn)
|
||||
if withdrawn != amount {
|
||||
fmt.Printf("Note that this is less than the requested amount of %s FIL\n", amount)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -278,7 +278,8 @@ USAGE:
|
||||
lotus-miner actor withdraw [command options] [amount (FIL)]
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
--confidence value number of block confirmations to wait for (default: 5)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
|
@ -388,6 +388,7 @@ USAGE:
|
||||
OPTIONS:
|
||||
--wallet value, -w value Specify address to withdraw funds to, otherwise it will use the default wallet address
|
||||
--address value, -a value Market address to withdraw from (account or miner actor address, defaults to --wallet address)
|
||||
--confidence value number of block confirmations to wait for (default: 5)
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
53
extern/storage-sealing/currentdealinfo.go
vendored
53
extern/storage-sealing/currentdealinfo.go
vendored
@ -4,6 +4,8 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
"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/exitcode"
|
||||
@ -20,6 +22,7 @@ type CurrentDealInfoAPI interface {
|
||||
StateLookupID(context.Context, address.Address, TipSetToken) (address.Address, error)
|
||||
StateMarketStorageDeal(context.Context, abi.DealID, TipSetToken) (*api.MarketDeal, error)
|
||||
StateSearchMsg(context.Context, cid.Cid) (*MsgLookup, error)
|
||||
StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error)
|
||||
}
|
||||
|
||||
type CurrentDealInfo struct {
|
||||
@ -77,27 +80,38 @@ func (mgr *CurrentDealInfoManager) dealIDFromPublishDealsMsg(ctx context.Context
|
||||
return dealID, nil, xerrors.Errorf("looking for publish deal message %s: non-ok exit code: %s", publishCid, lookup.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
var retval market.PublishStorageDealsReturn
|
||||
if err := retval.UnmarshalCBOR(bytes.NewReader(lookup.Receipt.Return)); err != nil {
|
||||
return dealID, nil, xerrors.Errorf("looking for publish deal message %s: unmarshalling message return: %w", publishCid, err)
|
||||
nv, err := mgr.CDAPI.StateNetworkVersion(ctx, lookup.TipSetTok)
|
||||
if err != nil {
|
||||
return dealID, nil, xerrors.Errorf("getting network version: %w", err)
|
||||
}
|
||||
|
||||
retval, err := market.DecodePublishStorageDealsReturn(lookup.Receipt.Return, nv)
|
||||
if err != nil {
|
||||
return dealID, nil, xerrors.Errorf("looking for publish deal message %s: decoding message return: %w", publishCid, err)
|
||||
}
|
||||
|
||||
dealIDs, err := retval.DealIDs()
|
||||
if err != nil {
|
||||
return dealID, nil, xerrors.Errorf("looking for publish deal message %s: getting dealIDs: %w", publishCid, err)
|
||||
}
|
||||
|
||||
// TODO: Can we delete this? We're well past the point when we first introduced the proposals into sealing deal info
|
||||
// Previously, publish deals messages contained a single deal, and the
|
||||
// deal proposal was not included in the sealing deal info.
|
||||
// So check if the proposal is nil and check the number of deals published
|
||||
// in the message.
|
||||
if proposal == nil {
|
||||
if len(retval.IDs) > 1 {
|
||||
if len(dealIDs) > 1 {
|
||||
return dealID, nil, xerrors.Errorf(
|
||||
"getting deal ID from publish deal message %s: "+
|
||||
"no deal proposal supplied but message return value has more than one deal (%d deals)",
|
||||
publishCid, len(retval.IDs))
|
||||
publishCid, len(dealIDs))
|
||||
}
|
||||
|
||||
// There is a single deal in this publish message and no deal proposal
|
||||
// was supplied, so we have nothing to compare against. Just assume
|
||||
// the deal ID is correct.
|
||||
return retval.IDs[0], lookup.TipSetTok, nil
|
||||
// the deal ID is correct and that it was valid
|
||||
return dealIDs[0], lookup.TipSetTok, nil
|
||||
}
|
||||
|
||||
// Get the parameters to the publish deals message
|
||||
@ -129,13 +143,22 @@ func (mgr *CurrentDealInfoManager) dealIDFromPublishDealsMsg(ctx context.Context
|
||||
return dealID, nil, xerrors.Errorf("could not find deal in publish deals message %s", publishCid)
|
||||
}
|
||||
|
||||
if dealIdx >= len(retval.IDs) {
|
||||
if dealIdx >= len(dealIDs) {
|
||||
return dealID, nil, xerrors.Errorf(
|
||||
"deal index %d out of bounds of deals (len %d) in publish deals message %s",
|
||||
dealIdx, len(retval.IDs), publishCid)
|
||||
dealIdx, len(dealIDs), publishCid)
|
||||
}
|
||||
|
||||
return retval.IDs[dealIdx], lookup.TipSetTok, nil
|
||||
valid, err := retval.IsDealValid(uint64(dealIdx))
|
||||
if err != nil {
|
||||
return dealID, nil, xerrors.Errorf("determining deal validity: %w", err)
|
||||
}
|
||||
|
||||
if !valid {
|
||||
return dealID, nil, xerrors.New("deal was invalid at publication")
|
||||
}
|
||||
|
||||
return dealIDs[dealIdx], lookup.TipSetTok, nil
|
||||
}
|
||||
|
||||
func (mgr *CurrentDealInfoManager) CheckDealEquality(ctx context.Context, tok TipSetToken, p1, p2 market.DealProposal) (bool, error) {
|
||||
@ -165,6 +188,7 @@ type CurrentDealInfoTskAPI interface {
|
||||
StateLookupID(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
StateMarketStorageDeal(context.Context, abi.DealID, types.TipSetKey) (*api.MarketDeal, error)
|
||||
StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error)
|
||||
StateNetworkVersion(context.Context, types.TipSetKey) (network.Version, error)
|
||||
}
|
||||
|
||||
type CurrentDealInfoAPIAdapter struct {
|
||||
@ -210,4 +234,13 @@ func (c *CurrentDealInfoAPIAdapter) StateSearchMsg(ctx context.Context, k cid.Ci
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *CurrentDealInfoAPIAdapter) StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error) {
|
||||
tsk, err := types.TipSetKeyFromBytes(tok)
|
||||
if err != nil {
|
||||
return network.VersionMax, xerrors.Errorf("failed to unmarshal TipSetToken to TipSetKey: %w", err)
|
||||
}
|
||||
|
||||
return c.CurrentDealInfoTskAPI.StateNetworkVersion(ctx, tsk)
|
||||
}
|
||||
|
||||
var _ CurrentDealInfoAPI = (*CurrentDealInfoAPIAdapter)(nil)
|
||||
|
12
extern/storage-sealing/currentdealinfo_test.go
vendored
12
extern/storage-sealing/currentdealinfo_test.go
vendored
@ -8,6 +8,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
@ -207,7 +211,7 @@ func TestGetCurrentDealInfo(t *testing.T) {
|
||||
},
|
||||
targetProposal: &proposal,
|
||||
expectedDealID: zeroDealID,
|
||||
expectedError: xerrors.Errorf("looking for publish deal message %s: unmarshalling message return: cbor input should be of type array", dummyCid),
|
||||
expectedError: xerrors.Errorf("looking for publish deal message %s: decoding message return: failed to unmarshal PublishStorageDealsReturn: cbor input should be of type array", dummyCid),
|
||||
},
|
||||
}
|
||||
runTestCase := func(testCase string, data testCaseData) {
|
||||
@ -305,9 +309,13 @@ func (mapi *CurrentDealInfoMockAPI) StateSearchMsg(ctx context.Context, c cid.Ci
|
||||
return mapi.SearchMessageLookup, mapi.SearchMessageErr
|
||||
}
|
||||
|
||||
func (mapi *CurrentDealInfoMockAPI) StateNetworkVersion(ctx context.Context, tok TipSetToken) (network.Version, error) {
|
||||
return network.Version0, nil
|
||||
}
|
||||
|
||||
func makePublishDealsReturnBytes(t *testing.T, dealIDs []abi.DealID) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
dealsReturn := market.PublishStorageDealsReturn{
|
||||
dealsReturn := market0.PublishStorageDealsReturn{
|
||||
IDs: dealIDs,
|
||||
}
|
||||
err := dealsReturn.MarshalCBOR(buf)
|
||||
|
7
extern/storage-sealing/states_failed_test.go
vendored
7
extern/storage-sealing/states_failed_test.go
vendored
@ -5,6 +5,10 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/ipfs/go-cid"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
@ -52,11 +56,12 @@ func TestStateRecoverDealIDs(t *testing.T) {
|
||||
api.EXPECT().StateSearchMsg(ctx, pc).Return(&sealing.MsgLookup{
|
||||
Receipt: sealing.MessageReceipt{
|
||||
ExitCode: exitcode.Ok,
|
||||
Return: cborRet(&market.PublishStorageDealsReturn{
|
||||
Return: cborRet(&market0.PublishStorageDealsReturn{
|
||||
IDs: []abi.DealID{dealId},
|
||||
}),
|
||||
},
|
||||
}, nil)
|
||||
api.EXPECT().StateNetworkVersion(ctx, nil).Return(network.Version0, nil)
|
||||
api.EXPECT().StateMarketStorageDeal(ctx, dealId, nil).Return(&api2.MarketDeal{
|
||||
Proposal: dealProposal,
|
||||
}, nil)
|
||||
|
2
go.mod
2
go.mod
@ -49,7 +49,7 @@ require (
|
||||
github.com/filecoin-project/specs-actors/v3 v3.1.1
|
||||
github.com/filecoin-project/specs-actors/v4 v4.0.1
|
||||
github.com/filecoin-project/specs-actors/v5 v5.0.4
|
||||
github.com/filecoin-project/specs-actors/v6 v6.0.0-20210920194404-d0e4e92671fa
|
||||
github.com/filecoin-project/specs-actors/v6 v6.0.0-20210929155130-9dcf49dee05b
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.5
|
||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
|
||||
|
4
go.sum
4
go.sum
@ -344,8 +344,8 @@ github.com/filecoin-project/specs-actors/v4 v4.0.1/go.mod h1:TkHXf/l7Wyw4ZejyXIP
|
||||
github.com/filecoin-project/specs-actors/v5 v5.0.0-20210512015452-4fe3889fff57/go.mod h1:283yBMMUSDB2abcjP/hhrwTkhb9h3sfM6KGrep/ZlBI=
|
||||
github.com/filecoin-project/specs-actors/v5 v5.0.4 h1:OY7BdxJWlUfUFXWV/kpNBYGXNPasDIedf42T3sGx08s=
|
||||
github.com/filecoin-project/specs-actors/v5 v5.0.4/go.mod h1:5BAKRAMsOOlD8+qCw4UvT/lTLInCJ3JwOWZbX8Ipwq4=
|
||||
github.com/filecoin-project/specs-actors/v6 v6.0.0-20210920194404-d0e4e92671fa h1:sSCa1OskxuMMeLaun9btVuyBJu3U5V0akp+JeuJB9QA=
|
||||
github.com/filecoin-project/specs-actors/v6 v6.0.0-20210920194404-d0e4e92671fa/go.mod h1:lPcgekzy5rFamHRZtTo0ukLggIFex2ecEAWxrk5AT1o=
|
||||
github.com/filecoin-project/specs-actors/v6 v6.0.0-20210929155130-9dcf49dee05b h1:q/ez+gqSlqmzWUb/1bs5ynUqH5G5L1jcFCiOAPfkE8k=
|
||||
github.com/filecoin-project/specs-actors/v6 v6.0.0-20210929155130-9dcf49dee05b/go.mod h1:V1AYfi5GkHXipx1mnVivoICZh3wtwPxDVuds+fbfQtk=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506 h1:Ur/l2+6qN+lQiqjozWWc5p9UDaAMDZKTlDS98oRnlIw=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20201105051918-5188d9774506/go.mod h1:nJRRM7Aa9XVvygr3W9k6xGF46RWzr2zxF/iGoAIfA/g=
|
||||
github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg=
|
||||
|
@ -6,6 +6,9 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
market0 "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
||||
builtin6 "github.com/filecoin-project/specs-actors/v6/actors/builtin"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"go.uber.org/fx"
|
||||
"golang.org/x/xerrors"
|
||||
@ -19,9 +22,6 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
|
||||
miner2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
market2 "github.com/filecoin-project/specs-actors/v2/actors/builtin/market"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
marketactor "github.com/filecoin-project/lotus/chain/actors/builtin/market"
|
||||
@ -108,10 +108,10 @@ func (c *ClientNodeAdapter) VerifySignature(ctx context.Context, sig crypto.Sign
|
||||
func (c *ClientNodeAdapter) AddFunds(ctx context.Context, addr address.Address, amount abi.TokenAmount) (cid.Cid, error) {
|
||||
// (Provider Node API)
|
||||
smsg, err := c.MpoolPushMessage(ctx, &types.Message{
|
||||
To: miner2.StorageMarketActorAddr,
|
||||
To: marketactor.Address,
|
||||
From: addr,
|
||||
Value: amount,
|
||||
Method: miner2.MethodsMarket.AddBalance,
|
||||
Method: builtin6.MethodsMarket.AddBalance,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return cid.Undef, err
|
||||
@ -171,19 +171,20 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !pubOk {
|
||||
return 0, xerrors.Errorf("deal wasn't published by storage provider: from=%s, provider=%s,%+v", pubmsg.From, deal.Proposal.Provider, pubAddrs)
|
||||
}
|
||||
|
||||
if pubmsg.To != miner2.StorageMarketActorAddr {
|
||||
if pubmsg.To != marketactor.Address {
|
||||
return 0, xerrors.Errorf("deal publish message wasn't set to StorageMarket actor (to=%s)", pubmsg.To)
|
||||
}
|
||||
|
||||
if pubmsg.Method != miner2.MethodsMarket.PublishStorageDeals {
|
||||
if pubmsg.Method != builtin6.MethodsMarket.PublishStorageDeals {
|
||||
return 0, xerrors.Errorf("deal publish message called incorrect method (method=%s)", pubmsg.Method)
|
||||
}
|
||||
|
||||
var params market2.PublishStorageDealsParams
|
||||
var params marketactor.PublishStorageDealsParams
|
||||
if err := params.UnmarshalCBOR(bytes.NewReader(pubmsg.Params)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -215,12 +216,37 @@ func (c *ClientNodeAdapter) ValidatePublishedDeal(ctx context.Context, deal stor
|
||||
return 0, xerrors.Errorf("deal publish failed: exit=%d", ret.Receipt.ExitCode)
|
||||
}
|
||||
|
||||
var res market2.PublishStorageDealsReturn
|
||||
if err := res.UnmarshalCBOR(bytes.NewReader(ret.Receipt.Return)); err != nil {
|
||||
return 0, err
|
||||
nv, err := c.StateNetworkVersion(ctx, ret.TipSet)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("getting network version: %w", err)
|
||||
}
|
||||
|
||||
return res.IDs[dealIdx], nil
|
||||
res, err := marketactor.DecodePublishStorageDealsReturn(ret.Receipt.Return, nv)
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("decoding deal publish return: %w", err)
|
||||
}
|
||||
|
||||
dealIDs, err := res.DealIDs()
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("getting dealIDs: %w", err)
|
||||
}
|
||||
|
||||
if dealIdx >= len(dealIDs) {
|
||||
return 0, xerrors.Errorf(
|
||||
"deal index %d out of bounds of deals (len %d) in publish deals message %s",
|
||||
dealIdx, len(dealIDs), pubmsg.Cid())
|
||||
}
|
||||
|
||||
valid, err := res.IsDealValid(uint64(dealIdx))
|
||||
if err != nil {
|
||||
return 0, xerrors.Errorf("determining deal validity: %w", err)
|
||||
}
|
||||
|
||||
if !valid {
|
||||
return 0, xerrors.New("deal was invalid at publication")
|
||||
}
|
||||
|
||||
return dealIDs[dealIdx], nil
|
||||
}
|
||||
|
||||
var clientOverestimation = struct {
|
||||
@ -243,12 +269,12 @@ func (c *ClientNodeAdapter) DealProviderCollateralBounds(ctx context.Context, si
|
||||
}
|
||||
|
||||
// TODO: Remove dealID parameter, change publishCid to be cid.Cid (instead of pointer)
|
||||
func (c *ClientNodeAdapter) OnDealSectorPreCommitted(ctx context.Context, provider address.Address, dealID abi.DealID, proposal market2.DealProposal, publishCid *cid.Cid, cb storagemarket.DealSectorPreCommittedCallback) error {
|
||||
func (c *ClientNodeAdapter) OnDealSectorPreCommitted(ctx context.Context, provider address.Address, dealID abi.DealID, proposal market0.DealProposal, publishCid *cid.Cid, cb storagemarket.DealSectorPreCommittedCallback) error {
|
||||
return c.scMgr.OnDealSectorPreCommitted(ctx, provider, marketactor.DealProposal(proposal), *publishCid, cb)
|
||||
}
|
||||
|
||||
// TODO: Remove dealID parameter, change publishCid to be cid.Cid (instead of pointer)
|
||||
func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider address.Address, dealID abi.DealID, sectorNumber abi.SectorNumber, proposal market2.DealProposal, publishCid *cid.Cid, cb storagemarket.DealSectorCommittedCallback) error {
|
||||
func (c *ClientNodeAdapter) OnDealSectorCommitted(ctx context.Context, provider address.Address, dealID abi.DealID, sectorNumber abi.SectorNumber, proposal market0.DealProposal, publishCid *cid.Cid, cb storagemarket.DealSectorCommittedCallback) error {
|
||||
return c.scMgr.OnDealSectorCommitted(ctx, provider, sectorNumber, marketactor.DealProposal(proposal), *publishCid, cb)
|
||||
}
|
||||
|
||||
@ -342,7 +368,7 @@ func (c *ClientNodeAdapter) OnDealExpiredOrSlashed(ctx context.Context, dealID a
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Address, proposal market2.DealProposal) (*market2.ClientDealProposal, error) {
|
||||
func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Address, proposal market0.DealProposal) (*marketactor.ClientDealProposal, error) {
|
||||
// TODO: output spec signed proposal
|
||||
buf, err := cborutil.Dump(&proposal)
|
||||
if err != nil {
|
||||
@ -361,7 +387,7 @@ func (c *ClientNodeAdapter) SignProposal(ctx context.Context, signer address.Add
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &market2.ClientDealProposal{
|
||||
return &marketactor.ClientDealProposal{
|
||||
Proposal: proposal,
|
||||
ClientSignature: *sig,
|
||||
}, nil
|
||||
|
@ -16,8 +16,9 @@ require (
|
||||
github.com/filecoin-project/lotus v0.0.0-00010101000000-000000000000
|
||||
github.com/filecoin-project/specs-actors v0.9.14
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/gorilla/mux v1.7.4
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
github.com/influxdata/influxdb v1.9.4 // indirect
|
||||
github.com/ipfs/go-cid v0.1.0
|
||||
github.com/ipfs/go-datastore v0.4.5
|
||||
github.com/ipfs/go-ipfs-files v0.0.8
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user