diff --git a/Makefile b/Makefile index 6c3a6049f..b30f8712f 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ townhall: rm -f townhall go build -o townhall ./cmd/lotus-townhall (cd ./cmd/lotus-townhall/townhall && npm i && npm run build) - go run github.com/GeertJohan/go.rice/rice append --exec townhall -i ./cmd/lotus-townhall + go run github.com/GeertJohan/go.rice/rice append --exec townhall -i ./cmd/lotus-townhall -i ./build .PHONY: townhall fountain: diff --git a/README.md b/README.md index 08faa247a..c3c710864 100644 --- a/README.md +++ b/README.md @@ -92,19 +92,20 @@ $ lotus wallet balance [optional address (t3...)] ### Mining -Ensure that at least one BLS address (`t3..`) in your wallet has enough funds to -cover pledge collateral: +Ensure that at least one BLS address (`t3..`) in your wallet exists ```sh -$ lotus state pledge-collateral -1234 -$ lotus wallet balance [t3...] -8999 +$ lotus wallet list +t3... ``` -(Balance must be higher than the returned pledge collateral for the next step to work) +With this address, go to https://lotus-faucet.kittyhawk.wtf/miner.html, and +click `Create Miner` + +Wait for a page telling you the address of the newly created storage miner to +appear - It should be saying: `New storage miners address is: t0..` Initialize storage miner: ```sh -$ lotus-storage-miner init --owner=t3... +$ lotus-storage-miner init --actor=t01.. --owner=t3.... ``` This command should return successfully after miner is setup on-chain (30-60s) diff --git a/api/api.go b/api/api.go index 5e6373fac..989d42ee8 100644 --- a/api/api.go +++ b/api/api.go @@ -12,6 +12,7 @@ import ( "github.com/libp2p/go-libp2p-core/peer" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -101,7 +102,7 @@ type FullNode interface { // ClientImport imports file under the specified path into filestore ClientImport(ctx context.Context, path string) (cid.Cid, error) - ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) + ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, epochPrice types.BigInt, blocksDuration uint64) (*cid.Cid, error) ClientListDeals(ctx context.Context) ([]DealInfo, error) ClientHasLocal(ctx context.Context, root cid.Cid) (bool, error) ClientFindData(ctx context.Context, root cid.Cid) ([]QueryOffer, error) // TODO: specify serialization mode we want (defaults to unixfs for now) @@ -122,16 +123,20 @@ type FullNode interface { StateGetActor(ctx context.Context, actor address.Address, ts *types.TipSet) (*types.Actor, error) StateReadState(ctx context.Context, act *types.Actor, ts *types.TipSet) (*ActorState, error) - StateMinerSectors(context.Context, address.Address) ([]*SectorInfo, error) + StateMinerSectors(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error) StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error) StateMinerPower(context.Context, address.Address, *types.TipSet) (MinerPower, error) StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) + StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error) StatePledgeCollateral(context.Context, *types.TipSet) (types.BigInt, error) StateWaitMsg(context.Context, cid.Cid) (*MsgWait, error) StateListMiners(context.Context, *types.TipSet) ([]address.Address, error) StateListActors(context.Context, *types.TipSet) ([]address.Address, error) + StateMarketBalance(context.Context, address.Address, *types.TipSet) (actors.StorageParticipantBalance, error) + StateMarketParticipants(context.Context, *types.TipSet) (map[string]actors.StorageParticipantBalance, error) + StateMarketDeals(context.Context, *types.TipSet) (map[string]actors.OnChainDeal, error) PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) PaychList(context.Context) ([]address.Address, error) @@ -162,9 +167,6 @@ type StorageMiner interface { // List all staged sectors SectorsList(context.Context) ([]uint64, error) - // Seal all staged sectors - SectorsStagedSeal(context.Context) error - SectorsRefs(context.Context) (map[string][]SealedRef, error) } @@ -179,6 +181,9 @@ type Version struct { APIVersion uint32 // TODO: git commit / os / genesis cid? + + // Seconds + BlockDelay uint64 } func (v Version) String() string { @@ -196,14 +201,13 @@ type Import struct { type DealInfo struct { ProposalCid cid.Cid State DealState - Miner address.Address + Provider address.Address - PieceRef cid.Cid - CommP []byte + PieceRef []byte // cid bytes Size uint64 - TotalPrice types.BigInt - Duration uint64 + PricePerEpoch types.BigInt + Duration uint64 } type MsgWait struct { diff --git a/api/struct.go b/api/struct.go index b4bd36758..3fbbf619c 100644 --- a/api/struct.go +++ b/api/struct.go @@ -8,6 +8,7 @@ import ( "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -85,20 +86,24 @@ type FullNodeStruct struct { ClientRetrieve func(ctx context.Context, order RetrievalOrder, path string) error `perm:"admin"` ClientQueryAsk func(ctx context.Context, p peer.ID, miner address.Address) (*types.SignedStorageAsk, error) `perm:"read"` - StateMinerSectors func(context.Context, address.Address) ([]*SectorInfo, error) `perm:"read"` - StateMinerProvingSet func(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error) `perm:"read"` - StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"` - StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"` - StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"` - StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"` - StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"` - StateReplay func(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error) `perm:"read"` - StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"` - StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"` - StatePledgeCollateral func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"` - StateWaitMsg func(context.Context, cid.Cid) (*MsgWait, error) `perm:"read"` - StateListMiners func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"` - StateListActors func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"` + StateMinerSectors func(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error) `perm:"read"` + StateMinerProvingSet func(context.Context, address.Address, *types.TipSet) ([]*SectorInfo, error) `perm:"read"` + StateMinerPower func(context.Context, address.Address, *types.TipSet) (MinerPower, error) `perm:"read"` + StateMinerWorker func(context.Context, address.Address, *types.TipSet) (address.Address, error) `perm:"read"` + StateMinerPeerID func(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) `perm:"read"` + StateMinerProvingPeriodEnd func(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) `perm:"read"` + StateMinerSectorSize func(context.Context, address.Address, *types.TipSet) (uint64, error) `perm:"read"` + StateCall func(context.Context, *types.Message, *types.TipSet) (*types.MessageReceipt, error) `perm:"read"` + StateReplay func(context.Context, *types.TipSet, cid.Cid) (*ReplayResults, error) `perm:"read"` + StateGetActor func(context.Context, address.Address, *types.TipSet) (*types.Actor, error) `perm:"read"` + StateReadState func(context.Context, *types.Actor, *types.TipSet) (*ActorState, error) `perm:"read"` + StatePledgeCollateral func(context.Context, *types.TipSet) (types.BigInt, error) `perm:"read"` + StateWaitMsg func(context.Context, cid.Cid) (*MsgWait, error) `perm:"read"` + StateListMiners func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"` + StateListActors func(context.Context, *types.TipSet) ([]address.Address, error) `perm:"read"` + StateMarketBalance func(context.Context, address.Address, *types.TipSet) (actors.StorageParticipantBalance, error) `perm:"read"` + StateMarketParticipants func(context.Context, *types.TipSet) (map[string]actors.StorageParticipantBalance, error) `perm:"read"` + StateMarketDeals func(context.Context, *types.TipSet) (map[string]actors.OnChainDeal, error) `perm:"read"` PaychGet func(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) `perm:"sign"` PaychList func(context.Context) ([]address.Address, error) `perm:"read"` @@ -124,9 +129,8 @@ type StorageMinerStruct struct { StoreGarbageData func(context.Context) (uint64, error) `perm:"write"` - SectorsStatus func(context.Context, uint64) (sectorbuilder.SectorSealingStatus, error) `perm:"read"` - SectorsList func(context.Context) ([]uint64, error) `perm:"read"` - SectorsStagedSeal func(context.Context) error `perm:"write"` + SectorsStatus func(context.Context, uint64) (sectorbuilder.SectorSealingStatus, error) `perm:"read"` + SectorsList func(context.Context) ([]uint64, error) `perm:"read"` SectorsRefs func(context.Context) (map[string][]SealedRef, error) `perm:"read"` } @@ -334,8 +338,8 @@ func (c *FullNodeStruct) SyncSubmitBlock(ctx context.Context, blk *types.BlockMs return c.Internal.SyncSubmitBlock(ctx, blk) } -func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address) ([]*SectorInfo, error) { - return c.Internal.StateMinerSectors(ctx, addr) +func (c *FullNodeStruct) StateMinerSectors(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*SectorInfo, error) { + return c.Internal.StateMinerSectors(ctx, addr, ts) } func (c *FullNodeStruct) StateMinerProvingSet(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*SectorInfo, error) { @@ -353,10 +357,15 @@ func (c *FullNodeStruct) StateMinerWorker(ctx context.Context, m address.Address func (c *FullNodeStruct) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) { return c.Internal.StateMinerPeerID(ctx, m, ts) } + func (c *FullNodeStruct) StateMinerProvingPeriodEnd(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) { return c.Internal.StateMinerProvingPeriodEnd(ctx, actor, ts) } +func (c *FullNodeStruct) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) { + return c.Internal.StateMinerSectorSize(ctx, actor, ts) +} + func (c *FullNodeStruct) StateCall(ctx context.Context, msg *types.Message, ts *types.TipSet) (*types.MessageReceipt, error) { return c.Internal.StateCall(ctx, msg, ts) } @@ -388,6 +397,18 @@ func (c *FullNodeStruct) StateListActors(ctx context.Context, ts *types.TipSet) return c.Internal.StateListActors(ctx, ts) } +func (c *FullNodeStruct) StateMarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) { + return c.Internal.StateMarketBalance(ctx, addr, ts) +} + +func (c *FullNodeStruct) StateMarketParticipants(ctx context.Context, ts *types.TipSet) (map[string]actors.StorageParticipantBalance, error) { + return c.Internal.StateMarketParticipants(ctx, ts) +} + +func (c *FullNodeStruct) StateMarketDeals(ctx context.Context, ts *types.TipSet) (map[string]actors.OnChainDeal, error) { + return c.Internal.StateMarketDeals(ctx, ts) +} + func (c *FullNodeStruct) PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) { return c.Internal.PaychGet(ctx, from, to, ensureFunds) } @@ -454,11 +475,6 @@ func (c *StorageMinerStruct) SectorsList(ctx context.Context) ([]uint64, error) return c.Internal.SectorsList(ctx) } -// Seal all staged sectors -func (c *StorageMinerStruct) SectorsStagedSeal(ctx context.Context) error { - return c.Internal.SectorsStagedSeal(ctx) -} - func (c *StorageMinerStruct) SectorsRefs(ctx context.Context) (map[string][]SealedRef, error) { return c.Internal.SectorsRefs(ctx) } diff --git a/api/types.go b/api/types.go index 588227de2..6a5153328 100644 --- a/api/types.go +++ b/api/types.go @@ -6,22 +6,21 @@ import ( ma "github.com/multiformats/go-multiaddr" ) -type DealState int +type DealState = uint64 const ( - DealUnknown = DealState(iota) - DealRejected - DealAccepted - DealStarted + DealUnknown = DealState(iota) + DealRejected // Provider didn't like the proposal + DealAccepted // Proposal accepted, data moved + DealStaged // Data put into the sector + DealSealing // Data in process of being sealed + DealFailed - DealStaged - DealSealing DealComplete // Internal DealError // deal failed with an unexpected error - DealExpired DealNoUpdate = DealUnknown ) diff --git a/api/utils.go b/api/utils.go new file mode 100644 index 000000000..9927d44d0 --- /dev/null +++ b/api/utils.go @@ -0,0 +1,28 @@ +package api + +import ( + "context" + + "github.com/filecoin-project/lotus/chain/address" + "github.com/filecoin-project/lotus/chain/types" +) + +type SignFunc = func(context.Context, []byte) (*types.Signature, error) + +type Signer func(context.Context, address.Address, []byte) (*types.Signature, error) + +type Signable interface { + Sign(context.Context, SignFunc) error +} + +func SignWith(ctx context.Context, signer Signer, addr address.Address, signable ...Signable) error { + for _, s := range signable { + err := s.Sign(ctx, func(ctx context.Context, b []byte) (*types.Signature, error) { + return signer(ctx, addr, b) + }) + if err != nil { + return err + } + } + return nil +} diff --git a/build/bootstrap/bootstrappers.pi b/build/bootstrap/bootstrappers.pi index 031804bbd..0319a6d97 100644 --- a/build/bootstrap/bootstrappers.pi +++ b/build/bootstrap/bootstrappers.pi @@ -1 +1 @@ -/ip4/147.75.80.17/tcp/1347/p2p/12D3KooWQ3NBPgTbXFRGnmpZUpYBSPJtwJfxuAFHBuWJ8LumCYf2 +/ip4/147.75.80.17/tcp/1347/p2p/12D3KooWPTYfTi7B1mQpbyRaCT65Trf7zW9npmihcF1xPfZogrzh diff --git a/build/bootstrap/root.pi b/build/bootstrap/root.pi index f1f0ea3a5..b03183ddf 100644 --- a/build/bootstrap/root.pi +++ b/build/bootstrap/root.pi @@ -1 +1 @@ -/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWGU8C1mFsEtz4bXmHUH3kQTnQnxVy8cigwGV94qCpYJw7 \ No newline at end of file +/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWEwGkxuG4BSvWUU8Sf69rxUYjWHAMT2qFVBhzGJZAXc6v diff --git a/build/genesis/devnet.car b/build/genesis/devnet.car index a629514c1..ea19dc0d7 100644 Binary files a/build/genesis/devnet.car and b/build/genesis/devnet.car differ diff --git a/build/paramfetch.go b/build/paramfetch.go index 7816a2cca..abfeca08b 100644 --- a/build/paramfetch.go +++ b/build/paramfetch.go @@ -8,16 +8,20 @@ import ( "os" "path/filepath" "strings" + "sync" rice "github.com/GeertJohan/go.rice" logging "github.com/ipfs/go-log" "github.com/minio/blake2b-simd" + "go.uber.org/multierr" + "golang.org/x/xerrors" pb "gopkg.in/cheggaaa/pb.v1" ) var log = logging.Logger("build") -const gateway = "http://198.211.99.118/ipfs/" +//const gateway = "http://198.211.99.118/ipfs/" +const gateway = "https://ipfs.io/ipfs/" const paramdir = "/var/tmp/filecoin-proof-parameters" type paramFile struct { @@ -26,6 +30,13 @@ type paramFile struct { SectorSize uint64 `json:"sector_size"` } +type fetch struct { + wg sync.WaitGroup + fetchLk sync.Mutex + + errs []error +} + func GetParams(storage bool) error { if err := os.Mkdir(paramdir, 0755); err != nil && !os.IsExist(err) { return err @@ -38,43 +49,71 @@ func GetParams(storage bool) error { return err } + ft := &fetch{} + for name, info := range params { - if info.SectorSize != SectorSize { + if !SupportedSectorSize(info.SectorSize) { continue } if !storage && strings.HasSuffix(name, ".params") { continue } - if err := maybeFetch(name, info); err != nil { - return err - } + ft.maybeFetchAsync(name, info) } - return nil + return ft.wait() } -func maybeFetch(name string, info paramFile) error { - path := filepath.Join(paramdir, name) +func (ft *fetch) maybeFetchAsync(name string, info paramFile) { + ft.wg.Add(1) + + go func() { + defer ft.wg.Done() + + path := filepath.Join(paramdir, name) + + err := ft.checkFile(path, info) + if !os.IsNotExist(err) && err != nil { + log.Warn(err) + } + if err == nil { + return + } + + ft.fetchLk.Lock() + defer ft.fetchLk.Unlock() + + if err := doFetch(path, info); err != nil { + ft.errs = append(ft.errs, xerrors.Errorf("fetching file %s: %w", path, err)) + } + }() +} + +func (ft *fetch) checkFile(path string, info paramFile) error { f, err := os.Open(path) - if err == nil { - defer f.Close() + if err != nil { + return err + } + defer f.Close() - h := blake2b.New512() - if _, err := io.Copy(h, f); err != nil { - return err - } - - sum := h.Sum(nil) - strSum := hex.EncodeToString(sum[:16]) - if strSum == info.Digest { - return nil - } - - log.Warnf("Checksum mismatch in param file %s, %s != %s", name, strSum, info.Digest) + h := blake2b.New512() + if _, err := io.Copy(h, f); err != nil { + return err } - return doFetch(path, info) + sum := h.Sum(nil) + strSum := hex.EncodeToString(sum[:16]) + if strSum == info.Digest { + return nil + } + + return xerrors.Errorf("checksum mismatch in param file %s, %s != %s", path, strSum, info.Digest) +} + +func (ft *fetch) wait() error { + ft.wg.Wait() + return multierr.Combine(ft.errs...) } func doFetch(out string, info paramFile) error { diff --git a/build/params.go b/build/params.go index 4f27abe60..e810ff45f 100644 --- a/build/params.go +++ b/build/params.go @@ -1,6 +1,8 @@ package build -import "math/big" +import ( + "math/big" +) // Core network constants @@ -10,7 +12,20 @@ import "math/big" const UnixfsChunkSize uint64 = 1 << 20 const UnixfsLinksPerLevel = 1024 -const SectorSize = 16 << 20 +var SectorSizes = []uint64{ + 16 << 20, + 256 << 20, + 1 << 30, +} + +func SupportedSectorSize(ssize uint64) bool { + for _, ss := range SectorSizes { + if ssize == ss { + return true + } + } + return false +} // ///// // Payments @@ -18,19 +33,11 @@ const SectorSize = 16 << 20 // Blocks const PaymentChannelClosingDelay = 6 * 60 * 2 // six hours -// Blocks -const DealVoucherSkewLimit = 10 - -// Blocks -const MinDealVoucherIncrement = ProvingPeriodDuration - -const MaxVouchersPerDeal = 768 // roughly one voucher per 10h over a year - // ///// // Consensus / Network // Seconds -const BlockDelay = 30 +const BlockDelay = 10 // Seconds const AllowableClockDrift = BlockDelay * 2 @@ -39,19 +46,36 @@ const AllowableClockDrift = BlockDelay * 2 const ForkLengthThreshold = 100 // Blocks (e) -const BlocksPerEpoch = 1 +const BlocksPerEpoch = 3 + +// Blocks +const Finality = 500 // ///// -// Proofs / Mining +// Proofs // Blocks -const RandomnessLookback = 20 +const ProvingPeriodDuration = 60 + +// PoStChallangeTime sets the window in which post computation should happen +// Blocks +const PoStChallangeTime = ProvingPeriodDuration - 6 + +// PoStRandomnessLookback is additional randomness lookback for PoSt computation +// To compute randomness epoch in a given proving period: +// RandH = PPE - PoStChallangeTime - PoStRandomnessLookback +// +// Blocks +const PoStRandomnessLookback = 1 // Blocks -const ProvingPeriodDuration = 40 +const SealRandomnessLookback = Finality + +// ///// +// Mining // Blocks -const PoSTChallangeTime = 20 +const EcRandomnessLookback = 300 const PowerCollateralProportion = 5 const PerCapitaCollateralProportion = 1 diff --git a/build/proof-params/parameters.json b/build/proof-params/parameters.json index 723570a3d..0460fb226 100644 --- a/build/proof-params/parameters.json +++ b/build/proof-params/parameters.json @@ -1,82 +1,82 @@ { - "v12-proof-of-spacetime-rational-535d1050e3adca2a0dfe6c3c0c4fa12097c9a7835fb969042f82a507b13310e0.params": { - "cid": "QmZ6Y88jRbRjjYQzhh8o85bcUeChj7NGyo9yK6VbywhJ9F", - "digest": "3d245479d9b5fc668d58c493da5f3ee1", + "v14-proof-of-spacetime-rational-535d1050e3adca2a0dfe6c3c0c4fa12097c9a7835fb969042f82a507b13310e0.params": { + "cid": "QmT22f1Np1GpW29NXD7Zrv3Ae4poMYhmkDjyscqL8QrJXY", + "digest": "989fd8d989e0f7f1fe21bb010cf1b231", "sector_size": 16777216 }, - "v12-proof-of-spacetime-rational-535d1050e3adca2a0dfe6c3c0c4fa12097c9a7835fb969042f82a507b13310e0.vk": { - "cid": "QmbGgBLMTCnRc1E1fsUCPyZE4SYzrtAYEWCqCtL55AgxE2", - "digest": "29bd4c152096f878f41257b433159d81", + "v14-proof-of-spacetime-rational-535d1050e3adca2a0dfe6c3c0c4fa12097c9a7835fb969042f82a507b13310e0.vk": { + "cid": "QmVqSdc23to4UwduCCb25223rpSccvtcgPMfRKY1qjucDc", + "digest": "c6d258c37243b8544238a98100e3e399", "sector_size": 16777216 }, - "v12-proof-of-spacetime-rational-b99f15d0bdaaf4ffb68b2ca72b69ea8d915f66a2a56f667430ad69d87aa5febd.params": { - "cid": "Qmdm8vhWeRsZUUaHdysDr91gv6u6RFeC18hHxGnnzPrwcW", - "digest": "c67fd415a65e6d1caf4278597cf3462e", + "v14-proof-of-spacetime-rational-b99f15d0bdaaf4ffb68b2ca72b69ea8d915f66a2a56f667430ad69d87aa5febd.params": { + "cid": "QmRTCqgokEGTMfWVaSr7qFXTNotmpd2QBEi8RsvSQKmPLz", + "digest": "ff77a5e270afc6e1c7fbc19e48348fac", "sector_size": 1073741824 }, - "v12-proof-of-spacetime-rational-b99f15d0bdaaf4ffb68b2ca72b69ea8d915f66a2a56f667430ad69d87aa5febd.vk": { - "cid": "Qmc3xssw1syaZDZKmiM7TbCRnoDPfmD6V8ec1eTESidJQS", - "digest": "870355c10000010b9a4ece80892acca2", + "v14-proof-of-spacetime-rational-b99f15d0bdaaf4ffb68b2ca72b69ea8d915f66a2a56f667430ad69d87aa5febd.vk": { + "cid": "QmRssVAXRN3xp9VdSpTq1pNjkob3QiikoFZiM5hqrmh1VU", + "digest": "b41f35ac26224258e366327716a835a4", "sector_size": 1073741824 }, - "v12-proof-of-spacetime-rational-ba14a058a9dea194f68596f8ecf6537074f038a15c8d1a8550e10e31d4728912.params": { - "cid": "QmZBvF2F9wTYKLBxWSCQKe34D3M7vkNNc7ou8mxnNhZkZc", - "digest": "5d854e0ecfbd12cb7fa1247a6e6a0315", + "v14-proof-of-spacetime-rational-ba14a058a9dea194f68596f8ecf6537074f038a15c8d1a8550e10e31d4728912.params": { + "cid": "QmYNVRVzjXkuxJfnHTU5vmEcUBQf8dabXZ4m53SzqMkBv5", + "digest": "d156b685e4a1fe3a1f7230b6a39b5ad4", "sector_size": 1024 }, - "v12-proof-of-spacetime-rational-ba14a058a9dea194f68596f8ecf6537074f038a15c8d1a8550e10e31d4728912.vk": { - "cid": "QmZfdHrnk2oN3Gx7hhjpRGXu8qY6FcqLjpHQ6jt1BBDg5R", - "digest": "aca566faa466f05fb9d622bec39e4b6d", + "v14-proof-of-spacetime-rational-ba14a058a9dea194f68596f8ecf6537074f038a15c8d1a8550e10e31d4728912.vk": { + "cid": "QmaCEcsCFVuepMKdC5WURbr5ucEyLMNGxQaB7HqSnr2KGh", + "digest": "06ff067ac78cdab5d7bbc82170882241", "sector_size": 1024 }, - "v12-proof-of-spacetime-rational-c2ae2b440e693ee69fd6da9e85c4294c5c70c1a46d5785ca5f2a676d6cd4c8de.params": { - "cid": "QmYdGGwQXpaBGTVWXqMFVXUP2CZhtsV29jxPkRm54ArAdT", - "digest": "eb2d3c4cb7b32c87ead5326bcbd495f3", + "v14-proof-of-spacetime-rational-c2ae2b440e693ee69fd6da9e85c4294c5c70c1a46d5785ca5f2a676d6cd4c8de.params": { + "cid": "QmVuabRvJ797NwLisGKwRURASGxopBBgg4rfNsbZoSYzAc", + "digest": "0e1ceb79a459a60508f480e5b1fed7ac", "sector_size": 268435456 }, - "v12-proof-of-spacetime-rational-c2ae2b440e693ee69fd6da9e85c4294c5c70c1a46d5785ca5f2a676d6cd4c8de.vk": { - "cid": "QmeTtWQ2hCUq34BpHTy21jJqVqHbPJdNhQRqW4SF4ZNA7v", - "digest": "c83eca165ba94233861227578d658a22", + "v14-proof-of-spacetime-rational-c2ae2b440e693ee69fd6da9e85c4294c5c70c1a46d5785ca5f2a676d6cd4c8de.vk": { + "cid": "QmdWENZBAbuUty1vVNn9vmvj1XbJ5UC8qzpcVD35s5AJxG", + "digest": "1b755c74b9d6823c014f6a7ef76249f2", "sector_size": 268435456 }, - "v12-zigzag-proof-of-replication-0ed875801b4a99e4a6b46e58703e6857277ce020510fc9080041f6cfd5e0d286.params": { - "cid": "QmTkeyz3mfec4MqCbbiwuVWAQicY231zpdxSjdxN5U84PD", - "digest": "cf7118ac2273e2ccb6b451a5acd5f6e0", - "sector_size": 1073741824 - }, - "v12-zigzag-proof-of-replication-0ed875801b4a99e4a6b46e58703e6857277ce020510fc9080041f6cfd5e0d286.vk": { - "cid": "QmaGzJCwJNpQAD63QAKb8y4MKS1AMHeKyYzg3C5WyRSRRM", - "digest": "288c792f4fe09c85f8f35673fb9d5ed0", - "sector_size": 1073741824 - }, - "v12-zigzag-proof-of-replication-5efcf852a15bd74808bc65d6f2df146de817baea96c96e3b752e6a3349957644.params": { - "cid": "QmNSuxq15JPFCTehxVpgJydNZ79rpLoNwnLzQMGA9EziXg", - "digest": "818cd9cc2e0e47210a05bd073847ab5a", - "sector_size": 268435456 - }, - "v12-zigzag-proof-of-replication-5efcf852a15bd74808bc65d6f2df146de817baea96c96e3b752e6a3349957644.vk": { - "cid": "Qmbc8LcydZXsVqQrkNMeLEu31Vxi1VigQGJ2ehytxWPALH", - "digest": "a6636e2ee1a176161e022296bc045e79", - "sector_size": 268435456 - }, - "v12-zigzag-proof-of-replication-6496c180c2eab89ee0638bc73879ced01daf512486eb38b9e1c9402ba578e010.params": { - "cid": "QmUBpwbVwu5uzjTS8n1yesJ2QUaVbWJ8D9p2VaSsfjgAUr", - "digest": "e7aa73a1b06290d30f567bfac8324bf1", + "v14-stacked-proof-of-replication-0c0b444c6f31d11c8e98003cc99a3b938db26b77a296d4253cda8945c234266d.params": { + "cid": "QmPG38HmDNVFiQJskqKe9sfSjyHfvZRihcfry78rt22FDT", + "digest": "8ea0b47e72250d5d6dab5d4f859e65de", "sector_size": 16777216 }, - "v12-zigzag-proof-of-replication-6496c180c2eab89ee0638bc73879ced01daf512486eb38b9e1c9402ba578e010.vk": { - "cid": "Qme2uK8sQJUT3DzF291p2b91eFQzn7cKSJFiKVBsvrjTgt", - "digest": "d318cd116803c8ccbd3ac4cded9400ad", + "v14-stacked-proof-of-replication-0c0b444c6f31d11c8e98003cc99a3b938db26b77a296d4253cda8945c234266d.vk": { + "cid": "Qmd3pNM22pgAoRT24tNyEZmeEWK2GtoZznBvzjie2YgqCn", + "digest": "e39f344757c919ae6bbc9b61311c73b2", "sector_size": 16777216 }, - "v12-zigzag-proof-of-replication-a09b5cf44f640589b1b02cf823fa28269850342bcefa4878189b9b5c9ec4d2bb.params": { - "cid": "QmTfhTnkFvbpFfw8UydFdnPCDfxgAxEcw4fRdGsELpcFnh", - "digest": "906b6c0c9dc5bb581d9641c11b54e197", + "v14-stacked-proof-of-replication-967b11bb59be11b7dc6f2b627520ba450a3aa50846dbbf886cb8b735fe25c4e7.params": { + "cid": "QmQsS6RqWmgdwPnHCwhBJH3WDPcAxhKfbQUs2bwa8D9su8", + "digest": "09879a69abcc51de5c1095f347c84e2b", + "sector_size": 268435456 + }, + "v14-stacked-proof-of-replication-967b11bb59be11b7dc6f2b627520ba450a3aa50846dbbf886cb8b735fe25c4e7.vk": { + "cid": "QmSFBL5rg2TJv8QjLzrbr4c2KV2uDNN13RBVNUgwemJgM1", + "digest": "db0f245f7e9989879d2fa6328bd57d32", + "sector_size": 268435456 + }, + "v14-stacked-proof-of-replication-d01cd22091627b721c60a3375b5219af653fb9f6928c70aa7400587d396bc07a.params": { + "cid": "QmZ9UVBfviaNFsKyazA4k8GZcM1tHNDpDyrEK9qkxaMJXx", + "digest": "402a7c7c82eaa4af9fba3c7e4402b65b", + "sector_size": 1073741824 + }, + "v14-stacked-proof-of-replication-d01cd22091627b721c60a3375b5219af653fb9f6928c70aa7400587d396bc07a.vk": { + "cid": "QmNmDcPVJ1bFFDcNCcRnEoQ6vNDNpKadLPHyEpUoF47gxV", + "digest": "2741c456346a3758e88249d1f4c0d227", + "sector_size": 1073741824 + }, + "v14-stacked-proof-of-replication-f464b92d805d03de6e2c20e2530135b2c8ec96045ec58f342d6feb90282bff8a.params": { + "cid": "QmNqgCv6UjdKDNMuiwDweZ22TQYMd3gV6nWiA5PjMtNDVu", + "digest": "a9d316d0dbca152e653d41ad8e40058a", "sector_size": 1024 }, - "v12-zigzag-proof-of-replication-a09b5cf44f640589b1b02cf823fa28269850342bcefa4878189b9b5c9ec4d2bb.vk": { - "cid": "QmRDcUxfpPY9a1vR3T4vRgxHtWHyy9m3xuMQtj8P749r4e", - "digest": "3632776cd23e376694c625390b9a73ea", + "v14-stacked-proof-of-replication-f464b92d805d03de6e2c20e2530135b2c8ec96045ec58f342d6feb90282bff8a.vk": { + "cid": "QmTGQGThNFEjaMFgP32YLubACrtpkRoeVEfhDaWi5g6w8u", + "digest": "021b3e81e2980a50fd1ac07424d29a8d", "sector_size": 1024 } -} +} \ No newline at end of file diff --git a/chain/actors/actor_init.go b/chain/actors/actor_init.go index 64a154b71..82b507d49 100644 --- a/chain/actors/actor_init.go +++ b/chain/actors/actor_init.go @@ -162,7 +162,7 @@ func (ia InitActor) Exec(act *types.Actor, vmctx types.VMContext, p *ExecParams) func IsBuiltinActor(code cid.Cid) bool { switch code { - case StorageMarketActorCodeCid, StorageMinerCodeCid, AccountActorCodeCid, InitActorCodeCid, MultisigActorCodeCid, PaymentChannelActorCodeCid: + case StorageMarketCodeCid, StoragePowerCodeCid, StorageMinerCodeCid, AccountCodeCid, InitCodeCid, MultisigCodeCid, PaymentChannelCodeCid: return true default: return false @@ -170,12 +170,11 @@ func IsBuiltinActor(code cid.Cid) bool { } func IsSingletonActor(code cid.Cid) bool { - return code == StorageMarketActorCodeCid || code == InitActorCodeCid + return code == StoragePowerCodeCid || code == StorageMarketCodeCid || code == InitCodeCid } func (ias *InitActorState) AddActor(cst *hamt.CborIpldStore, addr address.Address) (address.Address, error) { nid := ias.NextID - ias.NextID++ amap, err := hamt.LoadNode(context.TODO(), cst, ias.AddressMap) if err != nil { @@ -195,6 +194,7 @@ func (ias *InitActorState) AddActor(cst *hamt.CborIpldStore, addr address.Addres return address.Undef, err } ias.AddressMap = ncid + ias.NextID++ return NewIDAddress(nid) } diff --git a/chain/actors/actor_miner.go b/chain/actors/actor_miner.go index de7e4d225..baa35d0d5 100644 --- a/chain/actors/actor_miner.go +++ b/chain/actors/actor_miner.go @@ -18,8 +18,6 @@ import ( "golang.org/x/xerrors" ) -const POST_SECTORS_COUNT = 8192 - type StorageMinerActor struct{} type StorageMinerActorState struct { @@ -89,40 +87,38 @@ type MinerInfo struct { PeerID peer.ID // Amount of space in each sector committed to the network by this miner. - SectorSize types.BigInt + SectorSize uint64 } type StorageMinerConstructorParams struct { Owner address.Address Worker address.Address - SectorSize types.BigInt + SectorSize uint64 PeerID peer.ID } type maMethods struct { - Constructor uint64 - CommitSector uint64 - SubmitPoSt uint64 - SlashStorageFault uint64 - GetCurrentProvingSet uint64 - ArbitrateDeal uint64 - DePledge uint64 - GetOwner uint64 - GetWorkerAddr uint64 - GetPower uint64 - GetPeerID uint64 - GetSectorSize uint64 - UpdatePeerID uint64 - ChangeWorker uint64 - IsSlashed uint64 - IsLate uint64 - PaymentVerifyInclusion uint64 - PaymentVerifySector uint64 - AddFaults uint64 - SlashConsensusFault uint64 + Constructor uint64 + CommitSector uint64 + SubmitPoSt uint64 + SlashStorageFault uint64 + GetCurrentProvingSet uint64 + ArbitrateDeal uint64 + DePledge uint64 + GetOwner uint64 + GetWorkerAddr uint64 + GetPower uint64 + GetPeerID uint64 + GetSectorSize uint64 + UpdatePeerID uint64 + ChangeWorker uint64 + IsSlashed uint64 + IsLate uint64 + AddFaults uint64 + SlashConsensusFault uint64 } -var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} +var MAMethods = maMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18} func (sma StorageMinerActor) Exports() []interface{} { return []interface{}{ @@ -142,10 +138,8 @@ func (sma StorageMinerActor) Exports() []interface{} { //14: sma.ChangeWorker, //15: sma.IsSlashed, //16: sma.IsLate, - 17: sma.PaymentVerifyInclusion, - 18: sma.PaymentVerifySector, - 19: sma.AddFaults, - 20: sma.SlashConsensusFault, + 17: sma.AddFaults, + 18: sma.SlashConsensusFault, } } @@ -205,15 +199,17 @@ func (sma StorageMinerActor) StorageMinerConstructor(act *types.Actor, vmctx typ return nil, nil } -type CommitSectorParams struct { - SectorID uint64 - CommD []byte - CommR []byte - CommRStar []byte - Proof []byte +type OnChainSealVerifyInfo struct { + CommD []byte // TODO: update proofs code + CommR []byte + + Epoch uint64 + Proof []byte + DealIDs []uint64 + SectorNumber uint64 } -func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContext, params *CommitSectorParams) ([]byte, ActorError) { +func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContext, params *OnChainSealVerifyInfo) ([]byte, ActorError) { ctx := context.TODO() oldstate, self, err := loadState(vmctx) if err != nil { @@ -225,36 +221,46 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex return nil, err } + if vmctx.Message().From != mi.Worker { + return nil, aerrors.New(1, "not authorized to commit sector for miner") + } + // TODO: this needs to get normalized to either the ID address or the actor address maddr := vmctx.Message().To - if ok, err := ValidatePoRep(maddr, mi.SectorSize, params); err != nil { + ticket, err := vmctx.GetRandomness(params.Epoch) + if err != nil { + return nil, aerrors.Wrap(err, "failed to get randomness for commitsector") + } + + if ok, err := ValidatePoRep(maddr, mi.SectorSize, params, ticket); err != nil { return nil, err } else if !ok { - return nil, aerrors.New(1, "bad proof!") + return nil, aerrors.New(2, "bad proof!") } // make sure the miner isnt trying to submit a pre-existing sector - unique, err := SectorIsUnique(ctx, vmctx.Storage(), self.Sectors, params.SectorID) + unique, err := SectorIsUnique(ctx, vmctx.Storage(), self.Sectors, params.SectorNumber) if err != nil { return nil, err } if !unique { - return nil, aerrors.New(2, "sector already committed!") + return nil, aerrors.New(3, "sector already committed!") } // Power of the miner after adding this sector - futurePower := types.BigAdd(self.Power, mi.SectorSize) + futurePower := types.BigAdd(self.Power, types.NewInt(mi.SectorSize)) collateralRequired := CollateralForPower(futurePower) + // TODO: grab from market? if act.Balance.LessThan(collateralRequired) { - return nil, aerrors.New(3, "not enough collateral") + return nil, aerrors.New(4, "not enough collateral") } // Note: There must exist a unique index in the miner's sector set for each // sector ID. The `faults`, `recovered`, and `done` parameters of the // SubmitPoSt method express indices into this sector set. - nssroot, err := AddToSectorSet(ctx, vmctx.Storage(), self.Sectors, params.SectorID, params.CommR, params.CommD) + nssroot, err := AddToSectorSet(ctx, vmctx.Storage(), self.Sectors, params.SectorNumber, params.CommR, params.CommD) if err != nil { return nil, err } @@ -286,7 +292,15 @@ func (sma StorageMinerActor) CommitSector(act *types.Actor, vmctx types.VMContex return nil, err } - return nil, nil + activateParams, err := SerializeParams(&ActivateStorageDealsParams{ + Deals: params.DealIDs, + }) + if err != nil { + return nil, err + } + + _, err = vmctx.Send(StorageMarketAddress, SMAMethods.ActivateStorageDeals, types.NewInt(0), activateParams) + return nil, err } type SubmitPoStParams struct { @@ -346,7 +360,7 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, var seed [sectorbuilder.CommLen]byte { - randHeight := currentProvingPeriodEnd - build.PoSTChallangeTime + randHeight := currentProvingPeriodEnd - build.PoStChallangeTime - build.PoStRandomnessLookback if vmctx.BlockHeight() <= randHeight { // TODO: spec, retcode return nil, aerrors.Newf(1, "submit PoSt called outside submission window (%d < %d)", vmctx.BlockHeight(), randHeight) @@ -393,7 +407,7 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, faults := self.CurrentFaultSet.All() - if ok, lerr := sectorbuilder.VerifyPost(mi.SectorSize.Uint64(), + if ok, lerr := sectorbuilder.VerifyPost(mi.SectorSize, sectorbuilder.NewSortedSectorInfo(sectorInfos), seed, params.Proof, faults); !ok || lerr != nil { if lerr != nil { @@ -426,14 +440,14 @@ func (sma StorageMinerActor) SubmitPoSt(act *types.Actor, vmctx types.VMContext, oldPower := self.Power self.Power = types.BigMul(types.NewInt(pss.Count-uint64(len(faults))), - mi.SectorSize) + types.NewInt(mi.SectorSize)) enc, err := SerializeParams(&UpdateStorageParams{Delta: types.BigSub(self.Power, oldPower)}) if err != nil { return nil, err } - _, err = vmctx.Send(StorageMarketAddress, SPAMethods.UpdateStorage, types.NewInt(0), enc) + _, err = vmctx.Send(StoragePowerAddress, SPAMethods.UpdateStorage, types.NewInt(0), enc) if err != nil { return nil, err } @@ -511,8 +525,8 @@ func GetFromSectorSet(ctx context.Context, s types.Storage, ss cid.Cid, sectorID return true, comms[0], comms[1], nil } -func ValidatePoRep(maddr address.Address, ssize types.BigInt, params *CommitSectorParams) (bool, ActorError) { - ok, err := sectorbuilder.VerifySeal(ssize.Uint64(), params.CommR, params.CommD, params.CommRStar, maddr, params.SectorID, params.Proof) +func ValidatePoRep(maddr address.Address, ssize uint64, params *OnChainSealVerifyInfo, ticket []byte) (bool, ActorError) { + ok, err := sectorbuilder.VerifySeal(ssize, params.CommR, params.CommD, maddr, ticket, params.SectorNumber, params.Proof) if err != nil { return false, aerrors.Absorb(err, 25, "verify seal failed") } @@ -626,7 +640,7 @@ func (sma StorageMinerActor) GetSectorSize(act *types.Actor, vmctx types.VMConte return nil, err } - return mi.SectorSize.Bytes(), nil + return types.NewInt(mi.SectorSize).Bytes(), nil } type PaymentVerifyParams struct { @@ -634,84 +648,6 @@ type PaymentVerifyParams struct { Proof []byte } -type PieceInclVoucherData struct { // TODO: Update spec at https://github.com/filecoin-project/specs/blob/master/actors.md#paymentverify - CommP []byte - PieceSize types.BigInt -} - -type InclusionProof struct { - Sector uint64 // for CommD, also verifies the sector is in sector set - Proof []byte -} - -func (sma StorageMinerActor) PaymentVerifyInclusion(act *types.Actor, vmctx types.VMContext, params *PaymentVerifyParams) ([]byte, ActorError) { - // params.Extra - PieceInclVoucherData - // params.Proof - InclusionProof - - _, self, aerr := loadState(vmctx) - if aerr != nil { - return nil, aerr - } - mi, aerr := loadMinerInfo(vmctx, self) - if aerr != nil { - return nil, aerr - } - - var voucherData PieceInclVoucherData - if err := cbor.DecodeInto(params.Extra, &voucherData); err != nil { - return nil, aerrors.Absorb(err, 2, "failed to decode storage voucher data for verification") - } - var proof InclusionProof - if err := cbor.DecodeInto(params.Proof, &proof); err != nil { - return nil, aerrors.Absorb(err, 3, "failed to decode storage payment proof") - } - - ok, _, commD, aerr := GetFromSectorSet(context.TODO(), vmctx.Storage(), self.Sectors, proof.Sector) - if aerr != nil { - return nil, aerr - } - if !ok { - return nil, aerrors.New(4, "miner does not have required sector") - } - - ok, err := sectorbuilder.VerifyPieceInclusionProof(mi.SectorSize.Uint64(), voucherData.PieceSize.Uint64(), voucherData.CommP, commD, proof.Proof) - if err != nil { - return nil, aerrors.Absorb(err, 5, "verify piece inclusion proof failed") - } - if !ok { - return nil, aerrors.New(6, "piece inclusion proof was invalid") - } - - return nil, nil -} - -func (sma StorageMinerActor) PaymentVerifySector(act *types.Actor, vmctx types.VMContext, params *PaymentVerifyParams) ([]byte, ActorError) { - // params.Extra - BigInt - sector id - // params.Proof - nil - - _, self, aerr := loadState(vmctx) - if aerr != nil { - return nil, aerr - } - - // TODO: ensure no sector ID reusability within related deal lifetime - sector := types.BigFromBytes(params.Extra) - - if len(params.Proof) > 0 { - return nil, aerrors.New(1, "unexpected proof bytes") - } - - ok, _, _, aerr := GetFromSectorSet(context.TODO(), vmctx.Storage(), self.Sectors, sector.Uint64()) - if aerr != nil { - return nil, aerr - } - if !ok { - return nil, aerrors.New(2, "miner does not have required sector") - } - - return nil, nil -} - type AddFaultsParams struct { Faults types.BitField } @@ -722,7 +658,7 @@ func (sma StorageMinerActor) AddFaults(act *types.Actor, vmctx types.VMContext, return nil, aerr } - challengeHeight := self.ProvingPeriodEnd - build.PoSTChallangeTime + challengeHeight := self.ProvingPeriodEnd - build.PoStChallangeTime if vmctx.BlockHeight() < challengeHeight { // TODO: optimized bitfield methods @@ -753,7 +689,7 @@ type MinerSlashConsensusFault struct { } func (sma StorageMinerActor) SlashConsensusFault(act *types.Actor, vmctx types.VMContext, params *MinerSlashConsensusFault) ([]byte, ActorError) { - if vmctx.Message().From != StorageMarketAddress { + if vmctx.Message().From != StoragePowerAddress { return nil, aerrors.New(1, "SlashConsensusFault may only be called by the storage market actor") } diff --git a/chain/actors/actor_multisig.go b/chain/actors/actor_multisig.go index 71a6d0e09..e8c360de6 100644 --- a/chain/actors/actor_multisig.go +++ b/chain/actors/actor_multisig.go @@ -16,10 +16,29 @@ type MultiSigActorState struct { Required uint64 NextTxID uint64 + InitialBalance types.BigInt + StartingBlock uint64 + UnlockDuration uint64 + //TODO: make this map/sharray/whatever Transactions []MTransaction } +func (msas MultiSigActorState) canSpend(act *types.Actor, amnt types.BigInt, height uint64) bool { + if msas.UnlockDuration == 0 { + return true + } + + offset := height - msas.StartingBlock + if offset > msas.UnlockDuration { + return true + } + + minBalance := types.BigDiv(msas.InitialBalance, types.NewInt(msas.UnlockDuration)) + minBalance = types.BigMul(minBalance, types.NewInt(offset)) + return !minBalance.LessThan(types.BigSub(act.Balance, amnt)) +} + func (msas MultiSigActorState) isSigner(addr address.Address) bool { for _, s := range msas.Signers { if s == addr { @@ -90,8 +109,9 @@ func (msa MultiSigActor) Exports() []interface{} { } type MultiSigConstructorParams struct { - Signers []address.Address - Required uint64 + Signers []address.Address + Required uint64 + UnlockDuration uint64 } func (MultiSigActor) MultiSigConstructor(act *types.Actor, vmctx types.VMContext, @@ -100,6 +120,13 @@ func (MultiSigActor) MultiSigConstructor(act *types.Actor, vmctx types.VMContext Signers: params.Signers, Required: params.Required, } + + if params.UnlockDuration != 0 { + self.InitialBalance = vmctx.Message().Value + self.UnlockDuration = params.UnlockDuration + self.StartingBlock = vmctx.BlockHeight() + } + head, err := vmctx.Storage().Put(self) if err != nil { return nil, aerrors.Wrap(err, "could not put new head") @@ -183,6 +210,9 @@ func (msa MultiSigActor) Propose(act *types.Actor, vmctx types.VMContext, } if self.Required == 1 { + if !self.canSpend(act, tx.Value, vmctx.BlockHeight()) { + return nil, aerrors.New(100, "transaction amount exceeds available") + } _, err := vmctx.Send(tx.To, tx.Method, tx.Value, tx.Params) if aerrors.IsFatal(err) { return nil, err @@ -229,6 +259,9 @@ func (msa MultiSigActor) Approve(act *types.Actor, vmctx types.VMContext, } tx.Approved = append(tx.Approved, vmctx.Message().From) if uint64(len(tx.Approved)) >= self.Required { + if !self.canSpend(act, tx.Value, vmctx.BlockHeight()) { + return nil, aerrors.New(100, "transaction amount exceeds available") + } _, err := vmctx.Send(tx.To, tx.Method, tx.Value, tx.Params) if aerrors.IsFatal(err) { return nil, err diff --git a/chain/actors/actor_multisig_test.go b/chain/actors/actor_multisig_test.go index b705ad4a8..b55d17b13 100644 --- a/chain/actors/actor_multisig_test.go +++ b/chain/actors/actor_multisig_test.go @@ -23,7 +23,7 @@ func TestMultiSigCreate(t *testing.T) { } h := NewHarness(t, opts...) - ret, _ := h.CreateActor(t, creatorAddr, actors.MultisigActorCodeCid, + ret, _ := h.CreateActor(t, creatorAddr, actors.MultisigCodeCid, &actors.MultiSigConstructorParams{ Signers: []address.Address{creatorAddr, sig1Addr, sig2Addr}, Required: 2, @@ -49,7 +49,7 @@ func TestMultiSigOps(t *testing.T) { HarnessAddr(&sig1Addr, 100000), HarnessAddr(&sig2Addr, 100000), HarnessAddr(&outsideAddr, 100000), - HarnessActor(&multSigAddr, &creatorAddr, actors.MultisigActorCodeCid, + HarnessActor(&multSigAddr, &creatorAddr, actors.MultisigCodeCid, func() cbg.CBORMarshaler { return &actors.MultiSigConstructorParams{ Signers: []address.Address{creatorAddr, sig1Addr, sig2Addr}, diff --git a/chain/actors/actor_paych_test.go b/chain/actors/actor_paych_test.go index 3b712598c..e23acdf4a 100644 --- a/chain/actors/actor_paych_test.go +++ b/chain/actors/actor_paych_test.go @@ -18,7 +18,7 @@ func TestPaychCreate(t *testing.T) { } h := NewHarness(t, opts...) - ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelActorCodeCid, + ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelCodeCid, &actors.PCAConstructorParams{ To: targetAddr, }) @@ -47,7 +47,7 @@ func TestPaychUpdate(t *testing.T) { } h := NewHarness(t, opts...) - ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelActorCodeCid, + ret, _ := h.CreateActor(t, creatorAddr, actors.PaymentChannelCodeCid, &actors.PCAConstructorParams{ To: targetAddr, }) diff --git a/chain/actors/actor_storagemarket.go b/chain/actors/actor_storagemarket.go new file mode 100644 index 000000000..9c3fcb9aa --- /dev/null +++ b/chain/actors/actor_storagemarket.go @@ -0,0 +1,604 @@ +package actors + +import ( + "bytes" + "context" + + "github.com/filecoin-project/go-amt-ipld" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-hamt-ipld" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors/aerrors" + "github.com/filecoin-project/lotus/chain/address" + "github.com/filecoin-project/lotus/chain/types" +) + +type StorageMarketActor struct{} + +type smaMethods struct { + Constructor uint64 + WithdrawBalance uint64 + AddBalance uint64 + CheckLockedBalance uint64 + PublishStorageDeals uint64 + HandleCronAction uint64 + SettleExpiredDeals uint64 + ProcessStorageDealsPayment uint64 + SlashStorageDealCollateral uint64 + GetLastExpirationFromDealIDs uint64 + ActivateStorageDeals uint64 +} + +var SMAMethods = smaMethods{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} + +func (sma StorageMarketActor) Exports() []interface{} { + return []interface{}{ + 2: sma.WithdrawBalance, + 3: sma.AddBalance, + // 4: sma.CheckLockedBalance, + 5: sma.PublishStorageDeals, + // 6: sma.HandleCronAction, + // 7: sma.SettleExpiredDeals, + // 8: sma.ProcessStorageDealsPayment, + // 9: sma.SlashStorageDealCollateral, + // 10: sma.GetLastExpirationFromDealIDs, + 11: sma.ActivateStorageDeals, // TODO: move under PublishStorageDeals after specs team approves + } +} + +type StorageParticipantBalance struct { + Locked types.BigInt + Available types.BigInt +} + +type StorageMarketState struct { + Balances cid.Cid // hamt + Deals cid.Cid // amt + + NextDealID uint64 // TODO: spec +} + +// TODO: Drop in favour of car storage +type SerializationMode = uint64 + +const ( + SerializationUnixFSv0 = iota + // IPLD / car +) + +type StorageDealProposal struct { + PieceRef []byte // cid bytes // TODO: spec says to use cid.Cid, probably not a good idea + PieceSize uint64 + PieceSerialization SerializationMode // Needs to be here as it tells how data in the sector maps to PieceRef cid + + Client address.Address + Provider address.Address + + ProposalExpiration uint64 + Duration uint64 // TODO: spec + + StoragePricePerEpoch types.BigInt + StorageCollateral types.BigInt + + ProposerSignature *types.Signature +} + +func (sdp *StorageDealProposal) TotalStoragePrice() types.BigInt { + return types.BigMul(sdp.StoragePricePerEpoch, types.NewInt(sdp.Duration)) +} + +type SignFunc = func(context.Context, []byte) (*types.Signature, error) + +func (sdp *StorageDealProposal) Sign(ctx context.Context, sign SignFunc) error { + if sdp.ProposerSignature != nil { + return xerrors.New("signature already present in StorageDealProposal") + } + var buf bytes.Buffer + if err := sdp.MarshalCBOR(&buf); err != nil { + return err + } + sig, err := sign(ctx, buf.Bytes()) + if err != nil { + return err + } + sdp.ProposerSignature = sig + return nil +} + +func (sdp *StorageDealProposal) Verify() error { + unsigned := *sdp + unsigned.ProposerSignature = nil + var buf bytes.Buffer + if err := unsigned.MarshalCBOR(&buf); err != nil { + return err + } + + return sdp.ProposerSignature.Verify(sdp.Client, buf.Bytes()) +} + +func (d *StorageDeal) Sign(ctx context.Context, sign SignFunc) error { + var buf bytes.Buffer + if err := d.Proposal.MarshalCBOR(&buf); err != nil { + return err + } + sig, err := sign(ctx, buf.Bytes()) + if err != nil { + return err + } + d.CounterSignature = sig + return nil +} + +func (d *StorageDeal) Verify(proposerWorker address.Address) error { + var buf bytes.Buffer + if err := d.Proposal.MarshalCBOR(&buf); err != nil { + return err + } + + return d.CounterSignature.Verify(proposerWorker, buf.Bytes()) +} + +type StorageDeal struct { + Proposal StorageDealProposal + CounterSignature *types.Signature +} + +type OnChainDeal struct { + Deal StorageDeal + ActivationEpoch uint64 // 0 = inactive +} + +type WithdrawBalanceParams struct { + Balance types.BigInt +} + +func (sma StorageMarketActor) WithdrawBalance(act *types.Actor, vmctx types.VMContext, params *WithdrawBalanceParams) ([]byte, ActorError) { + // TODO: (spec) this should be 2-stage + + var self StorageMarketState + old := vmctx.Storage().GetHead() + if err := vmctx.Storage().Get(old, &self); err != nil { + return nil, err + } + + b, bnd, err := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, vmctx.Message().From) + if err != nil { + return nil, aerrors.Wrap(err, "could not get balance") + } + + balance := b[0] + + if balance.Available.LessThan(params.Balance) { + return nil, aerrors.Newf(1, "can not withdraw more funds than available: %s > %s", params.Balance, b[0].Available) + } + + balance.Available = types.BigSub(balance.Available, params.Balance) + + _, err = vmctx.Send(vmctx.Message().From, 0, params.Balance, nil) + if err != nil { + return nil, aerrors.Wrap(err, "sending funds failed") + } + + bcid, err := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{ + vmctx.Message().From: balance, + }) + if err != nil { + return nil, err + } + + self.Balances = bcid + + nroot, err := vmctx.Storage().Put(&self) + if err != nil { + return nil, err + } + + return nil, vmctx.Storage().Commit(old, nroot) +} + +func (sma StorageMarketActor) AddBalance(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) { + var self StorageMarketState + old := vmctx.Storage().GetHead() + if err := vmctx.Storage().Get(old, &self); err != nil { + return nil, err + } + + b, bnd, err := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, vmctx.Message().From) + if err != nil { + return nil, aerrors.Wrap(err, "could not get balance") + } + + balance := b[0] + + balance.Available = types.BigAdd(balance.Available, vmctx.Message().Value) + + bcid, err := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{ + vmctx.Message().From: balance, + }) + if err != nil { + return nil, err + } + + self.Balances = bcid + + nroot, err := vmctx.Storage().Put(&self) + if err != nil { + return nil, err + } + + return nil, vmctx.Storage().Commit(old, nroot) +} + +func setMarketBalances(vmctx types.VMContext, nd *hamt.Node, set map[address.Address]StorageParticipantBalance) (cid.Cid, ActorError) { + for addr, b := range set { + balance := b // to stop linter complaining + if err := nd.Set(vmctx.Context(), string(addr.Bytes()), &balance); err != nil { + return cid.Undef, aerrors.HandleExternalError(err, "setting new balance") + } + } + if err := nd.Flush(vmctx.Context()); err != nil { + return cid.Undef, aerrors.HandleExternalError(err, "flushing balance hamt") + } + + c, err := vmctx.Ipld().Put(vmctx.Context(), nd) + if err != nil { + return cid.Undef, aerrors.HandleExternalError(err, "failed to balances storage") + } + return c, nil +} + +func GetMarketBalances(ctx context.Context, store *hamt.CborIpldStore, rcid cid.Cid, addrs ...address.Address) ([]StorageParticipantBalance, *hamt.Node, ActorError) { + nd, err := hamt.LoadNode(ctx, store, rcid) + if err != nil { + return nil, nil, aerrors.HandleExternalError(err, "failed to load miner set") + } + + out := make([]StorageParticipantBalance, len(addrs)) + + for i, a := range addrs { + var balance StorageParticipantBalance + err = nd.Find(ctx, string(a.Bytes()), &balance) + switch err { + case hamt.ErrNotFound: + out[i] = StorageParticipantBalance{ + Locked: types.NewInt(0), + Available: types.NewInt(0), + } + case nil: + out[i] = balance + default: + return nil, nil, aerrors.HandleExternalError(err, "failed to do set lookup") + } + + } + + return out, nd, nil +} + +/* +func (sma StorageMarketActor) CheckLockedBalance(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) { + +} +*/ + +type PublishStorageDealsParams struct { + Deals []StorageDeal +} + +type PublishStorageDealResponse struct { + DealIDs []uint64 +} + +func (sma StorageMarketActor) PublishStorageDeals(act *types.Actor, vmctx types.VMContext, params *PublishStorageDealsParams) ([]byte, ActorError) { + var self StorageMarketState + old := vmctx.Storage().GetHead() + if err := vmctx.Storage().Get(old, &self); err != nil { + return nil, err + } + + deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals) + if err != nil { + return nil, aerrors.HandleExternalError(err, "loading deals amt") + } + + // todo: handle duplicate deals + + if len(params.Deals) == 0 { + return nil, aerrors.New(1, "no storage deals in params.Deals") + } + + out := PublishStorageDealResponse{ + DealIDs: make([]uint64, len(params.Deals)), + } + + workerBytes, aerr := vmctx.Send(params.Deals[0].Proposal.Provider, MAMethods.GetWorkerAddr, types.NewInt(0), nil) + if aerr != nil { + return nil, aerr + } + providerWorker, err := address.NewFromBytes(workerBytes) + if err != nil { + return nil, aerrors.HandleExternalError(err, "parsing provider worker address bytes") + } + + // TODO: REVIEW: Do we want to check if provider exists in the power actor? + + for i, deal := range params.Deals { + if err := self.validateDeal(vmctx, deal, providerWorker); err != nil { + return nil, err + } + + err := deals.Set(self.NextDealID, &OnChainDeal{Deal: deal}) + if err != nil { + return nil, aerrors.HandleExternalError(err, "setting deal in deal AMT") + } + out.DealIDs[i] = self.NextDealID + + self.NextDealID++ + } + + dealsCid, err := deals.Flush() + if err != nil { + return nil, aerrors.HandleExternalError(err, "saving deals AMT") + } + + self.Deals = dealsCid + + nroot, err := vmctx.Storage().Put(&self) + if err != nil { + return nil, aerrors.HandleExternalError(err, "storing state failed") + } + + aerr = vmctx.Storage().Commit(old, nroot) + if aerr != nil { + return nil, aerr + } + + var outBuf bytes.Buffer + if err := out.MarshalCBOR(&outBuf); err != nil { + return nil, aerrors.HandleExternalError(err, "serialising output") + } + + return outBuf.Bytes(), nil +} + +func (st *StorageMarketState) validateDeal(vmctx types.VMContext, deal StorageDeal, providerWorker address.Address) aerrors.ActorError { + if vmctx.BlockHeight() > deal.Proposal.ProposalExpiration { + return aerrors.New(1, "deal proposal already expired") + } + + if err := deal.Proposal.Verify(); err != nil { + return aerrors.Absorb(err, 2, "verifying proposer signature") + } + + err := deal.Verify(providerWorker) + if err != nil { + return aerrors.Absorb(err, 2, "verifying provider signature") + } + + // TODO: maybe this is actually fine + if vmctx.Message().From != providerWorker && vmctx.Message().From != deal.Proposal.Client { + return aerrors.New(4, "message not sent by deal participant") + } + + // TODO: do some caching (changes gas so needs to be in spec too) + b, bnd, aerr := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), st.Balances, deal.Proposal.Client, providerWorker) + if aerr != nil { + return aerrors.Wrap(aerr, "getting client, and provider balances") + } + clientBalance := b[0] + providerBalance := b[1] + + totalPrice := deal.Proposal.TotalStoragePrice() + + if clientBalance.Available.LessThan(totalPrice) { + return aerrors.Newf(5, "client doesn't have enough available funds to cover storage price; %d < %d", clientBalance.Available, totalPrice) + } + + clientBalance = lockFunds(clientBalance, totalPrice) + + // TODO: REVIEW: Not clear who pays for this + if providerBalance.Available.LessThan(deal.Proposal.StorageCollateral) { + return aerrors.Newf(6, "provider doesn't have enough available funds to cover StorageCollateral; %d < %d", providerBalance.Available, deal.Proposal.StorageCollateral) + } + + providerBalance = lockFunds(providerBalance, deal.Proposal.StorageCollateral) + + // TODO: piece checks (e.g. size > sectorSize)? + + bcid, aerr := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{ + deal.Proposal.Client: clientBalance, + providerWorker: providerBalance, + }) + if aerr != nil { + return aerr + } + + st.Balances = bcid + + return nil +} + +type ActivateStorageDealsParams struct { + Deals []uint64 +} + +func (sma StorageMarketActor) ActivateStorageDeals(act *types.Actor, vmctx types.VMContext, params *ActivateStorageDealsParams) ([]byte, ActorError) { + var self StorageMarketState + old := vmctx.Storage().GetHead() + if err := vmctx.Storage().Get(old, &self); err != nil { + return nil, err + } + + deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals) + if err != nil { + // TODO: kind of annoying that this can be caused by gas, otherwise could be fatal + return nil, aerrors.HandleExternalError(err, "loading deals amt") + } + + for _, deal := range params.Deals { + var dealInfo OnChainDeal + if err := deals.Get(deal, &dealInfo); err != nil { + if _, is := err.(*amt.ErrNotFound); is { + return nil, aerrors.New(3, "deal not found") + } + return nil, aerrors.HandleExternalError(err, "getting deal info failed") + } + + if vmctx.Message().From != dealInfo.Deal.Proposal.Provider { + return nil, aerrors.New(1, "ActivateStorageDeals can only be called by the deal provider") + } + + if vmctx.BlockHeight() > dealInfo.Deal.Proposal.ProposalExpiration { + return nil, aerrors.New(2, "deal cannot be activated: proposal expired") + } + + if dealInfo.ActivationEpoch > 0 { + // this probably can't happen in practice + return nil, aerrors.New(3, "deal already active") + } + + dealInfo.ActivationEpoch = vmctx.BlockHeight() + + if err := deals.Set(deal, &dealInfo); err != nil { + return nil, aerrors.HandleExternalError(err, "setting deal info in AMT failed") + } + } + + dealsCid, err := deals.Flush() + if err != nil { + return nil, aerrors.HandleExternalError(err, "saving deals AMT") + } + + self.Deals = dealsCid + + nroot, err := vmctx.Storage().Put(&self) + if err != nil { + return nil, aerrors.HandleExternalError(err, "storing state failed") + } + + aerr := vmctx.Storage().Commit(old, nroot) + if aerr != nil { + return nil, aerr + } + + return nil, nil +} + +type ProcessStorageDealsPaymentParams struct { + DealIDs []uint64 +} + +func (sma StorageMarketActor) ProcessStorageDealsPayment(act *types.Actor, vmctx types.VMContext, params *ProcessStorageDealsPaymentParams) ([]byte, ActorError) { + var self StorageMarketState + old := vmctx.Storage().GetHead() + if err := vmctx.Storage().Get(old, &self); err != nil { + return nil, err + } + + deals, err := amt.LoadAMT(types.WrapStorage(vmctx.Storage()), self.Deals) + if err != nil { + // TODO: kind of annoying that this can be caused by gas, otherwise could be fatal + return nil, aerrors.HandleExternalError(err, "loading deals amt") + } + + // TODO: Would be nice if send could assert actor type + workerBytes, aerr := vmctx.Send(vmctx.Message().From, MAMethods.GetWorkerAddr, types.NewInt(0), nil) + if aerr != nil { + return nil, aerr + } + providerWorker, err := address.NewFromBytes(workerBytes) + if err != nil { + return nil, aerrors.HandleExternalError(err, "parsing provider worker address bytes") + } + + for _, deal := range params.DealIDs { + var dealInfo OnChainDeal + if err := deals.Get(deal, &dealInfo); err != nil { + if _, is := err.(*amt.ErrNotFound); is { + return nil, aerrors.New(2, "deal not found") + } + return nil, aerrors.HandleExternalError(err, "getting deal info failed") + } + + if dealInfo.Deal.Proposal.Provider != vmctx.Message().From { + return nil, aerrors.New(3, "ProcessStorageDealsPayment can only be called by deal provider") + } + + if vmctx.BlockHeight() < dealInfo.ActivationEpoch { + // TODO: This is probably fatal + return nil, aerrors.New(4, "ActivationEpoch lower than block height") + } + + if vmctx.BlockHeight() > dealInfo.ActivationEpoch+dealInfo.Deal.Proposal.Duration { + // Deal expired, miner should drop it + // TODO: process payment for the remainder of last proving period + return nil, nil + } + + // todo: check math (written on a plane, also tired) + // TODO: division is hard, this more than likely has some off-by-one issue + toPay := types.BigMul(dealInfo.Deal.Proposal.StoragePricePerEpoch, types.NewInt(build.ProvingPeriodDuration)) + + b, bnd, aerr := GetMarketBalances(vmctx.Context(), vmctx.Ipld(), self.Balances, dealInfo.Deal.Proposal.Client, providerWorker) + if aerr != nil { + return nil, aerr + } + clientBal := b[0] + providerBal := b[1] + + clientBal.Locked, providerBal.Available = transferFunds(clientBal.Locked, providerBal.Available, toPay) + + // TODO: call set once + bcid, aerr := setMarketBalances(vmctx, bnd, map[address.Address]StorageParticipantBalance{ + dealInfo.Deal.Proposal.Client: clientBal, + providerWorker: providerBal, + }) + if aerr != nil { + return nil, aerr + } + + self.Balances = bcid + } + + nroot, err := vmctx.Storage().Put(&self) + if err != nil { + return nil, aerrors.HandleExternalError(err, "storing state failed") + } + + aerr = vmctx.Storage().Commit(old, nroot) + if aerr != nil { + return nil, aerr + } + + return nil, nil +} + +func lockFunds(p StorageParticipantBalance, amt types.BigInt) StorageParticipantBalance { + p.Available, p.Locked = transferFunds(p.Available, p.Locked, amt) + return p +} + +func transferFunds(from, to, amt types.BigInt) (types.BigInt, types.BigInt) { + // TODO: some asserts + return types.BigSub(from, amt), types.BigAdd(to, amt) +} + +/* +func (sma StorageMarketActor) HandleCronAction(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) { + +} + +func (sma StorageMarketActor) SettleExpiredDeals(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) { + +} + +func (sma StorageMarketActor) SlashStorageDealCollateral(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) { + +} + +func (sma StorageMarketActor) GetLastExpirationFromDealIDs(act *types.Actor, vmctx types.VMContext, params *struct{}) ([]byte, ActorError) { + +} +*/ diff --git a/chain/actors/actor_storagepower.go b/chain/actors/actor_storagepower.go index 21afb6dd0..ea564bc62 100644 --- a/chain/actors/actor_storagepower.go +++ b/chain/actors/actor_storagepower.go @@ -53,12 +53,12 @@ type StoragePowerState struct { type CreateStorageMinerParams struct { Owner address.Address Worker address.Address - SectorSize types.BigInt + SectorSize uint64 PeerID peer.ID } func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VMContext, params *CreateStorageMinerParams) ([]byte, ActorError) { - if !SupportedSectorSize(params.SectorSize) { + if !build.SupportedSectorSize(params.SectorSize) { return nil, aerrors.New(1, "Unsupported sector size") } @@ -87,7 +87,7 @@ func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VM return nil, err } - ret, err := vmctx.Send(InitActorAddress, IAMethods.Exec, vmctx.Message().Value, encoded) + ret, err := vmctx.Send(InitAddress, IAMethods.Exec, vmctx.Message().Value, encoded) if err != nil { return nil, err } @@ -116,13 +116,6 @@ func (spa StoragePowerActor) CreateStorageMiner(act *types.Actor, vmctx types.VM return naddr.Bytes(), nil } -func SupportedSectorSize(ssize types.BigInt) bool { - if ssize.Uint64() == build.SectorSize { - return true - } - return false -} - type ArbitrateConsensusFaultParams struct { Block1 *types.BlockHeader Block2 *types.BlockHeader diff --git a/chain/actors/actor_storagepower_test.go b/chain/actors/actor_storagepower_test.go index cc4ef921c..b11edc71c 100644 --- a/chain/actors/actor_storagepower_test.go +++ b/chain/actors/actor_storagepower_test.go @@ -37,12 +37,12 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) { // cheating the bootstrapping problem cheatStorageMarketTotal(t, h.vm, h.cs.Blockstore()) - ret, _ := h.InvokeWithValue(t, ownerAddr, StorageMarketAddress, SPAMethods.CreateStorageMiner, + ret, _ := h.InvokeWithValue(t, ownerAddr, StoragePowerAddress, SPAMethods.CreateStorageMiner, types.NewInt(500000), &CreateStorageMinerParams{ Owner: ownerAddr, Worker: workerAddr, - SectorSize: types.NewInt(build.SectorSize), + SectorSize: build.SectorSizes[0], PeerID: "fakepeerid", }) ApplyOK(t, ret) @@ -52,7 +52,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) { } { - ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.IsMiner, + ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.IsMiner, &IsMinerParam{Addr: minerAddr}) ApplyOK(t, ret) @@ -68,7 +68,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) { } { - ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.PowerLookup, + ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.PowerLookup, &PowerLookupParams{Miner: minerAddr}) ApplyOK(t, ret) power := types.BigFromBytes(ret.Return) @@ -93,7 +93,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) { signBlock(t, h.w, workerAddr, b1) signBlock(t, h.w, workerAddr, b2) - ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.ArbitrateConsensusFault, + ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.ArbitrateConsensusFault, &ArbitrateConsensusFaultParams{ Block1: b1, Block2: b2, @@ -102,13 +102,13 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) { } { - ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.PowerLookup, + ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.PowerLookup, &PowerLookupParams{Miner: minerAddr}) assert.Equal(t, ret.ExitCode, byte(1)) } { - ret, _ := h.Invoke(t, ownerAddr, StorageMarketAddress, SPAMethods.IsMiner, &IsMinerParam{minerAddr}) + ret, _ := h.Invoke(t, ownerAddr, StoragePowerAddress, SPAMethods.IsMiner, &IsMinerParam{minerAddr}) ApplyOK(t, ret) assert.Equal(t, ret.Return, cbg.CborBoolFalse) } @@ -117,7 +117,7 @@ func TestStorageMarketCreateAndSlashMiner(t *testing.T) { func cheatStorageMarketTotal(t *testing.T, vm *vm.VM, bs bstore.Blockstore) { t.Helper() - sma, err := vm.StateTree().GetActor(StorageMarketAddress) + sma, err := vm.StateTree().GetActor(StoragePowerAddress) if err != nil { t.Fatal(err) } @@ -138,7 +138,7 @@ func cheatStorageMarketTotal(t *testing.T, vm *vm.VM, bs bstore.Blockstore) { sma.Head = c - if err := vm.StateTree().SetActor(StorageMarketAddress, sma); err != nil { + if err := vm.StateTree().SetActor(StoragePowerAddress, sma); err != nil { t.Fatal(err) } } diff --git a/chain/actors/actors.go b/chain/actors/actors.go index 72d3b96d5..10181eacd 100644 --- a/chain/actors/actors.go +++ b/chain/actors/actors.go @@ -7,16 +7,18 @@ import ( mh "github.com/multiformats/go-multihash" ) -var AccountActorCodeCid cid.Cid -var StorageMarketActorCodeCid cid.Cid +var AccountCodeCid cid.Cid +var StoragePowerCodeCid cid.Cid +var StorageMarketCodeCid cid.Cid var StorageMinerCodeCid cid.Cid -var MultisigActorCodeCid cid.Cid -var InitActorCodeCid cid.Cid -var PaymentChannelActorCodeCid cid.Cid +var MultisigCodeCid cid.Cid +var InitCodeCid cid.Cid +var PaymentChannelCodeCid cid.Cid -var InitActorAddress = mustIDAddress(0) +var InitAddress = mustIDAddress(0) var NetworkAddress = mustIDAddress(1) -var StorageMarketAddress = mustIDAddress(2) +var StoragePowerAddress = mustIDAddress(2) +var StorageMarketAddress = mustIDAddress(3) // TODO: missing from spec var BurntFundsAddress = mustIDAddress(99) func mustIDAddress(i uint64) address.Address { @@ -37,10 +39,11 @@ func init() { return c } - AccountActorCodeCid = mustSum("account") - StorageMarketActorCodeCid = mustSum("smarket") - StorageMinerCodeCid = mustSum("sminer") - MultisigActorCodeCid = mustSum("multisig") - InitActorCodeCid = mustSum("init") - PaymentChannelActorCodeCid = mustSum("paych") + AccountCodeCid = mustSum("fil/1/account") // TODO: spec + StoragePowerCodeCid = mustSum("fil/1/power") + StorageMarketCodeCid = mustSum("fil/1/market") + StorageMinerCodeCid = mustSum("fil/1/miner") + MultisigCodeCid = mustSum("fil/1/multisig") + InitCodeCid = mustSum("fil/1/init") + PaymentChannelCodeCid = mustSum("fil/1/paych") } diff --git a/chain/actors/actors_test.go b/chain/actors/actors_test.go index 36902de75..9e0c1186a 100644 --- a/chain/actors/actors_test.go +++ b/chain/actors/actors_test.go @@ -80,7 +80,7 @@ func TestVMInvokeMethod(t *testing.T) { } msg := &types.Message{ - To: InitActorAddress, + To: InitAddress, From: from, Method: IAMethods.Exec, Params: enc, @@ -118,7 +118,7 @@ func TestStorageMarketActorCreateMiner(t *testing.T) { params := &StorageMinerConstructorParams{ Owner: maddr, Worker: maddr, - SectorSize: types.NewInt(build.SectorSize), + SectorSize: build.SectorSizes[0], PeerID: "fakepeerid", } var err error @@ -128,7 +128,7 @@ func TestStorageMarketActorCreateMiner(t *testing.T) { } msg := &types.Message{ - To: StorageMarketAddress, + To: StoragePowerAddress, From: from, Method: SPAMethods.CreateStorageMiner, Params: enc, diff --git a/chain/actors/cbor_gen.go b/chain/actors/cbor_gen.go index d39a81af2..5444dafb0 100644 --- a/chain/actors/cbor_gen.go +++ b/chain/actors/cbor_gen.go @@ -421,8 +421,8 @@ func (t *StorageMinerConstructorParams) MarshalCBOR(w io.Writer) error { return err } - // t.t.SectorSize (types.BigInt) - if err := t.SectorSize.MarshalCBOR(w); err != nil { + // t.t.SectorSize (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SectorSize)); err != nil { return err } @@ -469,15 +469,16 @@ func (t *StorageMinerConstructorParams) UnmarshalCBOR(r io.Reader) error { } } - // t.t.SectorSize (types.BigInt) - - { - - if err := t.SectorSize.UnmarshalCBOR(br); err != nil { - return err - } + // t.t.SectorSize (uint64) + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.SectorSize = extra // t.t.PeerID (peer.ID) { @@ -491,17 +492,12 @@ func (t *StorageMinerConstructorParams) UnmarshalCBOR(r io.Reader) error { return nil } -func (t *CommitSectorParams) MarshalCBOR(w io.Writer) error { +func (t *OnChainSealVerifyInfo) MarshalCBOR(w io.Writer) error { if t == nil { _, err := w.Write(cbg.CborNull) return err } - if _, err := w.Write([]byte{133}); err != nil { - return err - } - - // t.t.SectorID (uint64) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SectorID)); err != nil { + if _, err := w.Write([]byte{134}); err != nil { return err } @@ -521,11 +517,8 @@ func (t *CommitSectorParams) MarshalCBOR(w io.Writer) error { return err } - // t.t.CommRStar ([]uint8) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.CommRStar)))); err != nil { - return err - } - if _, err := w.Write(t.CommRStar); err != nil { + // t.t.Epoch (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Epoch)); err != nil { return err } @@ -536,10 +529,25 @@ func (t *CommitSectorParams) MarshalCBOR(w io.Writer) error { if _, err := w.Write(t.Proof); err != nil { return err } + + // t.t.DealIDs ([]uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, v); err != nil { + return err + } + } + + // t.t.SectorNumber (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SectorNumber)); err != nil { + return err + } return nil } -func (t *CommitSectorParams) UnmarshalCBOR(r io.Reader) error { +func (t *OnChainSealVerifyInfo) UnmarshalCBOR(r io.Reader) error { br := cbg.GetPeeker(r) maj, extra, err := cbg.CborReadHeader(br) @@ -550,20 +558,10 @@ func (t *CommitSectorParams) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 5 { + if extra != 6 { return fmt.Errorf("cbor input had wrong number of fields") } - // t.t.SectorID (uint64) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if maj != cbg.MajUnsignedInt { - return fmt.Errorf("wrong type for uint64 field") - } - t.SectorID = extra // t.t.CommD ([]uint8) maj, extra, err = cbg.CborReadHeader(br) @@ -598,23 +596,16 @@ func (t *CommitSectorParams) UnmarshalCBOR(r io.Reader) error { if _, err := io.ReadFull(br, t.CommR); err != nil { return err } - // t.t.CommRStar ([]uint8) + // t.t.Epoch (uint64) maj, extra, err = cbg.CborReadHeader(br) if err != nil { return err } - if extra > 8192 { - return fmt.Errorf("t.CommRStar: array too large (%d)", extra) - } - - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - t.CommRStar = make([]byte, extra) - if _, err := io.ReadFull(br, t.CommRStar); err != nil { - return err + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") } + t.Epoch = extra // t.t.Proof ([]uint8) maj, extra, err = cbg.CborReadHeader(br) @@ -632,6 +623,46 @@ func (t *CommitSectorParams) UnmarshalCBOR(r io.Reader) error { if _, err := io.ReadFull(br, t.Proof); err != nil { return err } + // t.t.DealIDs ([]uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + if extra > 0 { + t.DealIDs = make([]uint64, extra) + } + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = val + } + + // t.t.SectorNumber (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.SectorNumber = extra return nil } @@ -662,8 +693,8 @@ func (t *MinerInfo) MarshalCBOR(w io.Writer) error { return err } - // t.t.SectorSize (types.BigInt) - if err := t.SectorSize.MarshalCBOR(w); err != nil { + // t.t.SectorSize (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SectorSize)); err != nil { return err } return nil @@ -712,15 +743,16 @@ func (t *MinerInfo) UnmarshalCBOR(r io.Reader) error { t.PeerID = peer.ID(sval) } - // t.t.SectorSize (types.BigInt) - - { - - if err := t.SectorSize.UnmarshalCBOR(br); err != nil { - return err - } + // t.t.SectorSize (uint64) + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.SectorSize = extra return nil } @@ -792,143 +824,6 @@ func (t *SubmitPoStParams) UnmarshalCBOR(r io.Reader) error { return nil } -func (t *PieceInclVoucherData) MarshalCBOR(w io.Writer) error { - if t == nil { - _, err := w.Write(cbg.CborNull) - return err - } - if _, err := w.Write([]byte{130}); err != nil { - return err - } - - // t.t.CommP ([]uint8) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.CommP)))); err != nil { - return err - } - if _, err := w.Write(t.CommP); err != nil { - return err - } - - // t.t.PieceSize (types.BigInt) - if err := t.PieceSize.MarshalCBOR(w); err != nil { - return err - } - return nil -} - -func (t *PieceInclVoucherData) UnmarshalCBOR(r io.Reader) error { - br := cbg.GetPeeker(r) - - maj, extra, err := cbg.CborReadHeader(br) - 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.t.CommP ([]uint8) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if extra > 8192 { - return fmt.Errorf("t.CommP: array too large (%d)", extra) - } - - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - t.CommP = make([]byte, extra) - if _, err := io.ReadFull(br, t.CommP); err != nil { - return err - } - // t.t.PieceSize (types.BigInt) - - { - - if err := t.PieceSize.UnmarshalCBOR(br); err != nil { - return err - } - - } - return nil -} - -func (t *InclusionProof) MarshalCBOR(w io.Writer) error { - if t == nil { - _, err := w.Write(cbg.CborNull) - return err - } - if _, err := w.Write([]byte{130}); err != nil { - return err - } - - // t.t.Sector (uint64) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Sector)); err != nil { - return err - } - - // t.t.Proof ([]uint8) - if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.Proof)))); err != nil { - return err - } - if _, err := w.Write(t.Proof); err != nil { - return err - } - return nil -} - -func (t *InclusionProof) UnmarshalCBOR(r io.Reader) error { - br := cbg.GetPeeker(r) - - maj, extra, err := cbg.CborReadHeader(br) - 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.t.Sector (uint64) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if maj != cbg.MajUnsignedInt { - return fmt.Errorf("wrong type for uint64 field") - } - t.Sector = extra - // t.t.Proof ([]uint8) - - maj, extra, err = cbg.CborReadHeader(br) - if err != nil { - return err - } - if extra > 8192 { - return fmt.Errorf("t.Proof: array too large (%d)", extra) - } - - if maj != cbg.MajByteString { - return fmt.Errorf("expected byte array") - } - t.Proof = make([]byte, extra) - if _, err := io.ReadFull(br, t.Proof); err != nil { - return err - } - return nil -} - func (t *PaymentVerifyParams) MarshalCBOR(w io.Writer) error { if t == nil { _, err := w.Write(cbg.CborNull) @@ -1060,7 +955,7 @@ func (t *MultiSigActorState) MarshalCBOR(w io.Writer) error { _, err := w.Write(cbg.CborNull) return err } - if _, err := w.Write([]byte{132}); err != nil { + if _, err := w.Write([]byte{135}); err != nil { return err } @@ -1084,6 +979,21 @@ func (t *MultiSigActorState) MarshalCBOR(w io.Writer) error { return err } + // t.t.InitialBalance (types.BigInt) + if err := t.InitialBalance.MarshalCBOR(w); err != nil { + return err + } + + // t.t.StartingBlock (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.StartingBlock)); err != nil { + return err + } + + // t.t.UnlockDuration (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.UnlockDuration)); err != nil { + return err + } + // t.t.Transactions ([]actors.MTransaction) if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Transactions)))); err != nil { return err @@ -1107,7 +1017,7 @@ func (t *MultiSigActorState) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 4 { + if extra != 7 { return fmt.Errorf("cbor input had wrong number of fields") } @@ -1157,6 +1067,35 @@ func (t *MultiSigActorState) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("wrong type for uint64 field") } t.NextTxID = extra + // t.t.InitialBalance (types.BigInt) + + { + + if err := t.InitialBalance.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.StartingBlock (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.StartingBlock = extra + // t.t.UnlockDuration (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.UnlockDuration = extra // t.t.Transactions ([]actors.MTransaction) maj, extra, err = cbg.CborReadHeader(br) @@ -1191,7 +1130,7 @@ func (t *MultiSigConstructorParams) MarshalCBOR(w io.Writer) error { _, err := w.Write(cbg.CborNull) return err } - if _, err := w.Write([]byte{130}); err != nil { + if _, err := w.Write([]byte{131}); err != nil { return err } @@ -1209,6 +1148,11 @@ func (t *MultiSigConstructorParams) MarshalCBOR(w io.Writer) error { if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Required)); err != nil { return err } + + // t.t.UnlockDuration (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.UnlockDuration)); err != nil { + return err + } return nil } @@ -1223,7 +1167,7 @@ func (t *MultiSigConstructorParams) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("cbor input should be of type array") } - if extra != 2 { + if extra != 3 { return fmt.Errorf("cbor input had wrong number of fields") } @@ -1263,6 +1207,16 @@ func (t *MultiSigConstructorParams) UnmarshalCBOR(r io.Reader) error { return fmt.Errorf("wrong type for uint64 field") } t.Required = extra + // t.t.UnlockDuration (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.UnlockDuration = extra return nil } @@ -2474,8 +2428,8 @@ func (t *CreateStorageMinerParams) MarshalCBOR(w io.Writer) error { return err } - // t.t.SectorSize (types.BigInt) - if err := t.SectorSize.MarshalCBOR(w); err != nil { + // t.t.SectorSize (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SectorSize)); err != nil { return err } @@ -2522,15 +2476,16 @@ func (t *CreateStorageMinerParams) UnmarshalCBOR(r io.Reader) error { } } - // t.t.SectorSize (types.BigInt) - - { - - if err := t.SectorSize.UnmarshalCBOR(br); err != nil { - return err - } + // t.t.SectorSize (uint64) + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.SectorSize = extra // t.t.PeerID (peer.ID) { @@ -2868,3 +2823,778 @@ func (t *MinerSlashConsensusFault) UnmarshalCBOR(r io.Reader) error { } return nil } + +func (t *StorageParticipantBalance) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.t.Locked (types.BigInt) + if err := t.Locked.MarshalCBOR(w); err != nil { + return err + } + + // t.t.Available (types.BigInt) + if err := t.Available.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *StorageParticipantBalance) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + 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.t.Locked (types.BigInt) + + { + + if err := t.Locked.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.Available (types.BigInt) + + { + + if err := t.Available.UnmarshalCBOR(br); err != nil { + return err + } + + } + return nil +} + +func (t *StorageMarketState) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{131}); err != nil { + return err + } + + // t.t.Balances (cid.Cid) + + if err := cbg.WriteCid(w, t.Balances); err != nil { + return xerrors.Errorf("failed to write cid field t.Balances: %w", err) + } + + // t.t.Deals (cid.Cid) + + if err := cbg.WriteCid(w, t.Deals); err != nil { + return xerrors.Errorf("failed to write cid field t.Deals: %w", err) + } + + // t.t.NextDealID (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.NextDealID)); err != nil { + return err + } + return nil +} + +func (t *StorageMarketState) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + 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.t.Balances (cid.Cid) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Balances: %w", err) + } + + t.Balances = c + + } + // t.t.Deals (cid.Cid) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Deals: %w", err) + } + + t.Deals = c + + } + // t.t.NextDealID (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.NextDealID = extra + return nil +} + +func (t *WithdrawBalanceParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.t.Balance (types.BigInt) + if err := t.Balance.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *WithdrawBalanceParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.Balance (types.BigInt) + + { + + if err := t.Balance.UnmarshalCBOR(br); err != nil { + return err + } + + } + return nil +} + +func (t *StorageDealProposal) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{138}); err != nil { + return err + } + + // t.t.PieceRef ([]uint8) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajByteString, uint64(len(t.PieceRef)))); err != nil { + return err + } + if _, err := w.Write(t.PieceRef); err != nil { + return err + } + + // t.t.PieceSize (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.PieceSize)); err != nil { + return err + } + + // t.t.PieceSerialization (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.PieceSerialization)); err != nil { + return err + } + + // t.t.Client (address.Address) + if err := t.Client.MarshalCBOR(w); err != nil { + return err + } + + // t.t.Provider (address.Address) + if err := t.Provider.MarshalCBOR(w); err != nil { + return err + } + + // t.t.ProposalExpiration (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.ProposalExpiration)); err != nil { + return err + } + + // t.t.Duration (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Duration)); err != nil { + return err + } + + // t.t.StoragePricePerEpoch (types.BigInt) + if err := t.StoragePricePerEpoch.MarshalCBOR(w); err != nil { + return err + } + + // t.t.StorageCollateral (types.BigInt) + if err := t.StorageCollateral.MarshalCBOR(w); err != nil { + return err + } + + // t.t.ProposerSignature (types.Signature) + if err := t.ProposerSignature.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *StorageDealProposal) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 10 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.PieceRef ([]uint8) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("t.PieceRef: array too large (%d)", extra) + } + + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + t.PieceRef = make([]byte, extra) + if _, err := io.ReadFull(br, t.PieceRef); err != nil { + return err + } + // t.t.PieceSize (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.PieceSize = extra + // t.t.PieceSerialization (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.PieceSerialization = extra + // t.t.Client (address.Address) + + { + + if err := t.Client.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.Provider (address.Address) + + { + + if err := t.Provider.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.ProposalExpiration (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.ProposalExpiration = extra + // t.t.Duration (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Duration = extra + // t.t.StoragePricePerEpoch (types.BigInt) + + { + + if err := t.StoragePricePerEpoch.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.StorageCollateral (types.BigInt) + + { + + if err := t.StorageCollateral.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.ProposerSignature (types.Signature) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.ProposerSignature = new(types.Signature) + if err := t.ProposerSignature.UnmarshalCBOR(br); err != nil { + return err + } + } + + } + return nil +} + +func (t *StorageDeal) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.t.Proposal (actors.StorageDealProposal) + if err := t.Proposal.MarshalCBOR(w); err != nil { + return err + } + + // t.t.CounterSignature (types.Signature) + if err := t.CounterSignature.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *StorageDeal) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + 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.t.Proposal (actors.StorageDealProposal) + + { + + if err := t.Proposal.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.CounterSignature (types.Signature) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.CounterSignature = new(types.Signature) + if err := t.CounterSignature.UnmarshalCBOR(br); err != nil { + return err + } + } + + } + return nil +} + +func (t *PublishStorageDealsParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.t.Deals ([]actors.StorageDeal) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Deals)))); err != nil { + return err + } + for _, v := range t.Deals { + if err := v.MarshalCBOR(w); err != nil { + return err + } + } + return nil +} + +func (t *PublishStorageDealsParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.Deals ([]actors.StorageDeal) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("t.Deals: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + if extra > 0 { + t.Deals = make([]StorageDeal, extra) + } + for i := 0; i < int(extra); i++ { + + var v StorageDeal + if err := v.UnmarshalCBOR(br); err != nil { + return err + } + + t.Deals[i] = v + } + + return nil +} + +func (t *PublishStorageDealResponse) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.t.DealIDs ([]uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, v); err != nil { + return err + } + } + return nil +} + +func (t *PublishStorageDealResponse) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.DealIDs ([]uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + if extra > 0 { + t.DealIDs = make([]uint64, extra) + } + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = val + } + + return nil +} + +func (t *ActivateStorageDealsParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.t.Deals ([]uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.Deals)))); err != nil { + return err + } + for _, v := range t.Deals { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, v); err != nil { + return err + } + } + return nil +} + +func (t *ActivateStorageDealsParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.Deals ([]uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("t.Deals: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + if extra > 0 { + t.Deals = make([]uint64, extra) + } + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.Deals slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.Deals was not a uint, instead got %d", maj) + } + + t.Deals[i] = val + } + + return nil +} + +func (t *ProcessStorageDealsPaymentParams) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.t.DealIDs ([]uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajArray, uint64(len(t.DealIDs)))); err != nil { + return err + } + for _, v := range t.DealIDs { + if err := cbg.CborWriteHeader(w, cbg.MajUnsignedInt, v); err != nil { + return err + } + } + return nil +} + +func (t *ProcessStorageDealsPaymentParams) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.DealIDs ([]uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if extra > 8192 { + return fmt.Errorf("t.DealIDs: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + if extra > 0 { + t.DealIDs = make([]uint64, extra) + } + for i := 0; i < int(extra); i++ { + + maj, val, err := cbg.CborReadHeader(br) + if err != nil { + return xerrors.Errorf("failed to read uint64 for t.DealIDs slice: %w", err) + } + + if maj != cbg.MajUnsignedInt { + return xerrors.Errorf("value read for array t.DealIDs was not a uint, instead got %d", maj) + } + + t.DealIDs[i] = val + } + + return nil +} + +func (t *OnChainDeal) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.t.Deal (actors.StorageDeal) + if err := t.Deal.MarshalCBOR(w); err != nil { + return err + } + + // t.t.ActivationEpoch (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.ActivationEpoch)); err != nil { + return err + } + return nil +} + +func (t *OnChainDeal) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + 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.t.Deal (actors.StorageDeal) + + { + + if err := t.Deal.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.ActivationEpoch (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.ActivationEpoch = extra + return nil +} diff --git a/chain/actors/harness2_test.go b/chain/actors/harness2_test.go index f0fc4b3e7..0ffc02b1b 100644 --- a/chain/actors/harness2_test.go +++ b/chain/actors/harness2_test.go @@ -210,7 +210,7 @@ func (h *Harness) CreateActor(t testing.TB, from address.Address, t.Helper() return h.Apply(t, types.Message{ - To: actors.InitActorAddress, + To: actors.InitAddress, From: from, Method: actors.IAMethods.Exec, Params: DumpObject(t, diff --git a/chain/deals/cbor_gen.go b/chain/deals/cbor_gen.go new file mode 100644 index 000000000..40413170c --- /dev/null +++ b/chain/deals/cbor_gen.go @@ -0,0 +1,778 @@ +package deals + +import ( + "fmt" + "io" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/types" + "github.com/libp2p/go-libp2p-core/peer" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +/* This file was generated by github.com/whyrusleeping/cbor-gen */ + +var _ = xerrors.Errorf + +func (t *AskRequest) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.t.Miner (address.Address) + if err := t.Miner.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *AskRequest) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.Miner (address.Address) + + { + + if err := t.Miner.UnmarshalCBOR(br); err != nil { + return err + } + + } + return nil +} + +func (t *AskResponse) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.t.Ask (types.SignedStorageAsk) + if err := t.Ask.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *AskResponse) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.Ask (types.SignedStorageAsk) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Ask = new(types.SignedStorageAsk) + if err := t.Ask.UnmarshalCBOR(br); err != nil { + return err + } + } + + } + return nil +} + +func (t *Proposal) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{129}); err != nil { + return err + } + + // t.t.DealProposal (actors.StorageDealProposal) + if err := t.DealProposal.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *Proposal) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 1 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.DealProposal (actors.StorageDealProposal) + + { + + if err := t.DealProposal.UnmarshalCBOR(br); err != nil { + return err + } + + } + return nil +} + +func (t *Response) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{134}); err != nil { + return err + } + + // t.t.State (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.State)); err != nil { + return err + } + + // t.t.Message (string) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Message)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.Message)); err != nil { + return err + } + + // t.t.Proposal (cid.Cid) + + if err := cbg.WriteCid(w, t.Proposal); err != nil { + return xerrors.Errorf("failed to write cid field t.Proposal: %w", err) + } + + // t.t.StorageDeal (actors.StorageDeal) + if err := t.StorageDeal.MarshalCBOR(w); err != nil { + return err + } + + // t.t.PublishMessage (cid.Cid) + + if t.PublishMessage == nil { + if _, err := w.Write(cbg.CborNull); err != nil { + return err + } + } else { + if err := cbg.WriteCid(w, *t.PublishMessage); err != nil { + return xerrors.Errorf("failed to write cid field t.PublishMessage: %w", err) + } + } + + // t.t.CommitMessage (cid.Cid) + + if t.CommitMessage == nil { + if _, err := w.Write(cbg.CborNull); err != nil { + return err + } + } else { + if err := cbg.WriteCid(w, *t.CommitMessage); err != nil { + return xerrors.Errorf("failed to write cid field t.CommitMessage: %w", err) + } + } + + return nil +} + +func (t *Response) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 6 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.State (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.State = extra + // t.t.Message (string) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.Message = string(sval) + } + // t.t.Proposal (cid.Cid) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Proposal: %w", err) + } + + t.Proposal = c + + } + // t.t.StorageDeal (actors.StorageDeal) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.StorageDeal = new(actors.StorageDeal) + if err := t.StorageDeal.UnmarshalCBOR(br); err != nil { + return err + } + } + + } + // t.t.PublishMessage (cid.Cid) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.PublishMessage: %w", err) + } + + t.PublishMessage = &c + } + + } + // t.t.CommitMessage (cid.Cid) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.CommitMessage: %w", err) + } + + t.CommitMessage = &c + } + + } + return nil +} + +func (t *SignedResponse) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.t.Response (deals.Response) + if err := t.Response.MarshalCBOR(w); err != nil { + return err + } + + // t.t.Signature (types.Signature) + if err := t.Signature.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *SignedResponse) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + 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.t.Response (deals.Response) + + { + + if err := t.Response.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.Signature (types.Signature) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Signature = new(types.Signature) + if err := t.Signature.UnmarshalCBOR(br); err != nil { + return err + } + } + + } + return nil +} + +func (t *ClientDealProposal) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{135}); err != nil { + return err + } + + // t.t.Data (cid.Cid) + + if err := cbg.WriteCid(w, t.Data); err != nil { + return xerrors.Errorf("failed to write cid field t.Data: %w", err) + } + + // t.t.PricePerEpoch (types.BigInt) + if err := t.PricePerEpoch.MarshalCBOR(w); err != nil { + return err + } + + // t.t.ProposalExpiration (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.ProposalExpiration)); err != nil { + return err + } + + // t.t.Duration (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Duration)); err != nil { + return err + } + + // t.t.ProviderAddress (address.Address) + if err := t.ProviderAddress.MarshalCBOR(w); err != nil { + return err + } + + // t.t.Client (address.Address) + if err := t.Client.MarshalCBOR(w); err != nil { + return err + } + + // t.t.MinerID (peer.ID) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.MinerID)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.MinerID)); err != nil { + return err + } + return nil +} + +func (t *ClientDealProposal) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 7 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.Data (cid.Cid) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Data: %w", err) + } + + t.Data = c + + } + // t.t.PricePerEpoch (types.BigInt) + + { + + if err := t.PricePerEpoch.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.ProposalExpiration (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.ProposalExpiration = extra + // t.t.Duration (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Duration = extra + // t.t.ProviderAddress (address.Address) + + { + + if err := t.ProviderAddress.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.Client (address.Address) + + { + + if err := t.Client.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.MinerID (peer.ID) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.MinerID = peer.ID(sval) + } + return nil +} + +func (t *ClientDeal) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{132}); err != nil { + return err + } + + // t.t.ProposalCid (cid.Cid) + + if err := cbg.WriteCid(w, t.ProposalCid); err != nil { + return xerrors.Errorf("failed to write cid field t.ProposalCid: %w", err) + } + + // t.t.Proposal (actors.StorageDealProposal) + if err := t.Proposal.MarshalCBOR(w); err != nil { + return err + } + + // t.t.State (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.State)); err != nil { + return err + } + + // t.t.Miner (peer.ID) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Miner)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.Miner)); err != nil { + return err + } + return nil +} + +func (t *ClientDeal) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + 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.t.ProposalCid (cid.Cid) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.ProposalCid: %w", err) + } + + t.ProposalCid = c + + } + // t.t.Proposal (actors.StorageDealProposal) + + { + + if err := t.Proposal.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.State (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.State = extra + // t.t.Miner (peer.ID) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.Miner = peer.ID(sval) + } + return nil +} + +func (t *MinerDeal) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{135}); err != nil { + return err + } + + // t.t.Client (peer.ID) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajTextString, uint64(len(t.Client)))); err != nil { + return err + } + if _, err := w.Write([]byte(t.Client)); err != nil { + return err + } + + // t.t.Proposal (actors.StorageDealProposal) + if err := t.Proposal.MarshalCBOR(w); err != nil { + return err + } + + // t.t.ProposalCid (cid.Cid) + + if err := cbg.WriteCid(w, t.ProposalCid); err != nil { + return xerrors.Errorf("failed to write cid field t.ProposalCid: %w", err) + } + + // t.t.State (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.State)); err != nil { + return err + } + + // t.t.Ref (cid.Cid) + + if err := cbg.WriteCid(w, t.Ref); err != nil { + return xerrors.Errorf("failed to write cid field t.Ref: %w", err) + } + + // t.t.DealID (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.DealID)); err != nil { + return err + } + + // t.t.SectorID (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SectorID)); err != nil { + return err + } + return nil +} + +func (t *MinerDeal) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 7 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.Client (peer.ID) + + { + sval, err := cbg.ReadString(br) + if err != nil { + return err + } + + t.Client = peer.ID(sval) + } + // t.t.Proposal (actors.StorageDealProposal) + + { + + if err := t.Proposal.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.ProposalCid (cid.Cid) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.ProposalCid: %w", err) + } + + t.ProposalCid = c + + } + // t.t.State (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.State = extra + // t.t.Ref (cid.Cid) + + { + + c, err := cbg.ReadCid(br) + if err != nil { + return xerrors.Errorf("failed to read cid field t.Ref: %w", err) + } + + t.Ref = c + + } + // t.t.DealID (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.DealID = extra + // t.t.SectorID (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.SectorID = extra + return nil +} diff --git a/chain/deals/client.go b/chain/deals/client.go index bf059ab93..fa70dbe99 100644 --- a/chain/deals/client.go +++ b/chain/deals/client.go @@ -2,12 +2,11 @@ package deals import ( "context" - "math" + "github.com/filecoin-project/lotus/node/impl/full" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" - cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p-core/host" inet "github.com/libp2p/go-libp2p-core/network" @@ -18,6 +17,7 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/address" "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/wallet" "github.com/filecoin-project/lotus/lib/cborrpc" @@ -25,22 +25,11 @@ import ( "github.com/filecoin-project/lotus/retrieval/discovery" ) -func init() { - cbor.RegisterCborType(ClientDeal{}) - cbor.RegisterCborType(actors.PieceInclVoucherData{}) // TODO: USE CBORGEN! - cbor.RegisterCborType(types.SignedVoucher{}) - cbor.RegisterCborType(types.ModVerifyParams{}) - cbor.RegisterCborType(types.Signature{}) - cbor.RegisterCborType(actors.PaymentInfo{}) - cbor.RegisterCborType(api.PaymentInfo{}) - cbor.RegisterCborType(actors.InclusionProof{}) -} - var log = logging.Logger("deals") type ClientDeal struct { ProposalCid cid.Cid - Proposal StorageDealProposal + Proposal actors.StorageDealProposal State api.DealState Miner peer.ID @@ -49,15 +38,17 @@ type ClientDeal struct { type Client struct { sm *stmgr.StateManager + chain *store.ChainStore h host.Host w *wallet.Wallet dag dtypes.ClientDAG discovery *discovery.Local + mpool full.MpoolAPI deals ClientStateStore conns map[cid.Cid]inet.Stream - incoming chan ClientDeal + incoming chan *ClientDeal updated chan clientDealUpdate stop chan struct{} @@ -70,18 +61,20 @@ type clientDealUpdate struct { err error } -func NewClient(sm *stmgr.StateManager, h host.Host, w *wallet.Wallet, ds dtypes.MetadataDS, dag dtypes.ClientDAG, discovery *discovery.Local) *Client { +func NewClient(sm *stmgr.StateManager, chain *store.ChainStore, h host.Host, w *wallet.Wallet, ds dtypes.MetadataDS, dag dtypes.ClientDAG, discovery *discovery.Local, mpool full.MpoolAPI) *Client { c := &Client{ sm: sm, + chain: chain, h: h, w: w, dag: dag, discovery: discovery, + mpool: mpool, deals: ClientStateStore{StateStore{ds: namespace.Wrap(ds, datastore.NewKey("/deals/client"))}}, conns: map[cid.Cid]inet.Stream{}, - incoming: make(chan ClientDeal, 16), + incoming: make(chan *ClientDeal, 16), updated: make(chan clientDealUpdate, 16), stop: make(chan struct{}), @@ -108,7 +101,7 @@ func (c *Client) Run(ctx context.Context) { }() } -func (c *Client) onIncoming(deal ClientDeal) { +func (c *Client) onIncoming(deal *ClientDeal) { log.Info("incoming deal") if _, ok := c.conns[deal.ProposalCid]; ok { @@ -166,70 +159,94 @@ func (c *Client) onUpdated(ctx context.Context, update clientDealUpdate) { type ClientDealProposal struct { Data cid.Cid - TotalPrice types.BigInt - Duration uint64 + PricePerEpoch types.BigInt + ProposalExpiration uint64 + Duration uint64 - Payment actors.PaymentInfo - - MinerAddress address.Address - ClientAddress address.Address - MinerID peer.ID + ProviderAddress address.Address + Client address.Address + MinerID peer.ID } -func (c *Client) VerifyParams(ctx context.Context, data cid.Cid) (*actors.PieceInclVoucherData, error) { - commP, size, err := c.commP(ctx, data) +func (c *Client) Start(ctx context.Context, p ClientDealProposal) (cid.Cid, error) { + // check market funds + clientMarketBalance, err := c.sm.MarketBalance(ctx, p.Client, nil) if err != nil { - return nil, err + return cid.Undef, xerrors.Errorf("getting client market balance failed: %w", err) } - return &actors.PieceInclVoucherData{ - CommP: commP, - PieceSize: types.NewInt(uint64(size)), - }, nil -} + if clientMarketBalance.Available.LessThan(types.BigMul(p.PricePerEpoch, types.NewInt(p.Duration))) { + // TODO: move to a smarter market funds manager -func (c *Client) Start(ctx context.Context, p ClientDealProposal, vd *actors.PieceInclVoucherData) (cid.Cid, error) { - proposal := StorageDealProposal{ - PieceRef: p.Data, - SerializationMode: SerializationUnixFs, - CommP: vd.CommP[:], - Size: vd.PieceSize.Uint64(), - TotalPrice: p.TotalPrice, - Duration: p.Duration, - Payment: p.Payment, - MinerAddress: p.MinerAddress, - ClientAddress: p.ClientAddress, + smsg, err := c.mpool.MpoolPushMessage(ctx, &types.Message{ + To: actors.StorageMarketAddress, + From: p.Client, + Value: types.BigMul(p.PricePerEpoch, types.NewInt(p.Duration)), + GasPrice: types.NewInt(0), + GasLimit: types.NewInt(1000000), + Method: actors.SMAMethods.AddBalance, + }) + if err != nil { + return cid.Undef, err + } + + _, r, err := c.sm.WaitForMessage(ctx, smsg.Cid()) + if err != nil { + return cid.Undef, err + } + + if r.ExitCode != 0 { + return cid.Undef, xerrors.Errorf("adding funds to storage miner market actor failed: exit %d", r.ExitCode) + } } - s, err := c.h.NewStream(ctx, p.MinerID, ProtocolID) + dataSize, err := c.dataSize(ctx, p.Data) + + proposal := &actors.StorageDealProposal{ + PieceRef: p.Data.Bytes(), + PieceSize: uint64(dataSize), + PieceSerialization: actors.SerializationUnixFSv0, + Client: p.Client, + Provider: p.ProviderAddress, + ProposalExpiration: p.ProposalExpiration, + Duration: p.Duration, + StoragePricePerEpoch: p.PricePerEpoch, + StorageCollateral: types.NewInt(uint64(dataSize)), // TODO: real calc + } + + if err := api.SignWith(ctx, c.w.Sign, p.Client, proposal); err != nil { + return cid.Undef, xerrors.Errorf("signing deal proposal failed: %w", err) + } + + proposalNd, err := cborrpc.AsIpld(proposal) if err != nil { - return cid.Undef, err + return cid.Undef, xerrors.Errorf("getting proposal node failed: %w", err) } - if err := c.sendProposal(s, proposal, p.ClientAddress); err != nil { - return cid.Undef, err - } - - proposalNd, err := cbor.WrapObject(proposal, math.MaxUint64, -1) + s, err := c.h.NewStream(ctx, p.MinerID, DealProtocolID) if err != nil { - return cid.Undef, err + s.Reset() + return cid.Undef, xerrors.Errorf("connecting to storage provider failed: %w", err) } - deal := ClientDeal{ + if err := cborrpc.WriteCborRPC(s, proposal); err != nil { + s.Reset() + return cid.Undef, xerrors.Errorf("sending proposal to storage provider failed: %w", err) + } + + deal := &ClientDeal{ ProposalCid: proposalNd.Cid(), - Proposal: proposal, + Proposal: *proposal, State: api.DealUnknown, Miner: p.MinerID, s: s, } - // TODO: actually care about what happens with the deal after it was accepted c.incoming <- deal - // TODO: start tracking after the deal is sealed return deal.ProposalCid, c.discovery.AddPeer(p.Data, discovery.RetrievalPeer{ - Address: proposal.MinerAddress, + Address: proposal.Provider, ID: deal.Miner, }) } diff --git a/chain/deals/client_states.go b/chain/deals/client_states.go index d19270707..bb30e8440 100644 --- a/chain/deals/client_states.go +++ b/chain/deals/client_states.go @@ -2,12 +2,12 @@ package deals import ( "context" - "github.com/filecoin-project/lotus/api" "golang.org/x/xerrors" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/lib/sectorbuilder" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/stmgr" ) type clientHandlerFunc func(ctx context.Context, deal ClientDeal) error @@ -39,6 +39,39 @@ func (c *Client) new(ctx context.Context, deal ClientDeal) error { return xerrors.Errorf("deal wasn't accepted (State=%d)", resp.State) } + // TODO: spec says it's optional + pubmsg, err := c.chain.GetMessage(*resp.PublishMessage) + if err != nil { + return xerrors.Errorf("getting deal pubsish message: %w", err) + } + + pw, err := stmgr.GetMinerWorker(ctx, c.sm, nil, deal.Proposal.Provider) + if err != nil { + return xerrors.Errorf("getting miner worker failed: %w", err) + } + + if pubmsg.From != pw { + return xerrors.Errorf("deal wasn't published by storage provider: from=%s, provider=%s", pubmsg.From, deal.Proposal.Provider) + } + + if pubmsg.To != actors.StorageMarketAddress { + return xerrors.Errorf("deal publish message wasn't set to StorageMarket actor (to=%s)", pubmsg.To) + } + + if pubmsg.Method != actors.SMAMethods.PublishStorageDeals { + return xerrors.Errorf("deal publish message called incorrect method (method=%s)", pubmsg.Method) + } + + // TODO: timeout + _, ret, err := c.sm.WaitForMessage(ctx, *resp.PublishMessage) + if err != nil { + return xerrors.Errorf("waiting for deal publish message: %w", err) + } + if ret.ExitCode != 0 { + return xerrors.Errorf("deal publish failed: exit=%d", ret.ExitCode) + } + // TODO: persist dealId + log.Info("DEAL ACCEPTED!") return nil @@ -75,13 +108,19 @@ func (c *Client) staged(ctx context.Context, deal ClientDeal) error { log.Info("DEAL SEALED!") - ok, err := sectorbuilder.VerifyPieceInclusionProof(build.SectorSize, deal.Proposal.Size, deal.Proposal.CommP, resp.CommD, resp.PieceInclusionProof.ProofElements) + // TODO: want? + /*ssize, err := stmgr.GetMinerSectorSize(ctx, c.sm, nil, deal.Proposal.MinerAddress) + if err != nil { + return xerrors.Errorf("failed to get miner sector size: %w", err) + } + + ok, err := sectorbuilder.VerifyPieceInclusionProof(ssize, deal.Proposal.Size, deal.Proposal.CommP, resp.CommD, resp.PieceInclusionProof.ProofElements) if err != nil { return xerrors.Errorf("verifying piece inclusion proof in staged deal %s: %w", deal.ProposalCid, err) } if !ok { return xerrors.Errorf("verifying piece inclusion proof in staged deal %s failed", deal.ProposalCid) - } + }*/ return nil } diff --git a/chain/deals/client_utils.go b/chain/deals/client_utils.go index c192bbeb4..9c26f4268 100644 --- a/chain/deals/client_utils.go +++ b/chain/deals/client_utils.go @@ -2,17 +2,13 @@ package deals import ( "context" - "github.com/filecoin-project/lotus/lib/sectorbuilder" "runtime" "github.com/ipfs/go-cid" files "github.com/ipfs/go-ipfs-files" - cbor "github.com/ipfs/go-ipld-cbor" unixfile "github.com/ipfs/go-unixfs/file" - inet "github.com/libp2p/go-libp2p-core/network" "golang.org/x/xerrors" - "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/lib/cborrpc" ) @@ -32,68 +28,38 @@ func (c *Client) failDeal(id cid.Cid, cerr error) { log.Errorf("deal %s failed: %s", id, cerr) } -func (c *Client) commP(ctx context.Context, data cid.Cid) ([]byte, int64, error) { +func (c *Client) dataSize(ctx context.Context, data cid.Cid) (int64, error) { root, err := c.dag.Get(ctx, data) if err != nil { log.Errorf("failed to get file root for deal: %s", err) - return nil, 0, err + return 0, err } n, err := unixfile.NewUnixfsFile(ctx, c.dag, root) if err != nil { log.Errorf("cannot open unixfs file: %s", err) - return nil, 0, err + return 0, err } uf, ok := n.(files.File) if !ok { // TODO: we probably got directory, how should we handle this in unixfs mode? - return nil, 0, xerrors.New("unsupported unixfs type") + return 0, xerrors.New("unsupported unixfs type") } - size, err := uf.Size() - if err != nil { - return nil, 0, err - } - - commP, err := sectorbuilder.GeneratePieceCommitment(uf, uint64(size)) - if err != nil { - return nil, 0, err - } - - return commP[:], size, err + return uf.Size() } -func (c *Client) sendProposal(s inet.Stream, proposal StorageDealProposal, from address.Address) error { - log.Info("Sending deal proposal") - - msg, err := cbor.DumpObject(proposal) - if err != nil { - return err - } - sig, err := c.w.Sign(context.TODO(), from, msg) - if err != nil { - return err - } - - signedProposal := &SignedStorageDealProposal{ - Proposal: proposal, - Signature: sig, - } - - return cborrpc.WriteCborRPC(s, signedProposal) -} - -func (c *Client) readStorageDealResp(deal ClientDeal) (*StorageDealResponse, error) { +func (c *Client) readStorageDealResp(deal ClientDeal) (*Response, error) { s, ok := c.conns[deal.ProposalCid] if !ok { // TODO: Try to re-establish the connection using query protocol return nil, xerrors.Errorf("no connection to miner") } - var resp SignedStorageDealResponse + var resp SignedResponse if err := cborrpc.ReadCborRPC(s, &resp); err != nil { - log.Errorw("failed to read StorageDealResponse message", "error", err) + log.Errorw("failed to read Response message", "error", err) return nil, err } diff --git a/chain/deals/handler_states.go b/chain/deals/handler_states.go deleted file mode 100644 index a981497e3..000000000 --- a/chain/deals/handler_states.go +++ /dev/null @@ -1,313 +0,0 @@ -package deals - -import ( - "bytes" - "context" - - "github.com/filecoin-project/go-sectorbuilder/sealing_state" - cbor "github.com/ipfs/go-ipld-cbor" - "github.com/ipfs/go-merkledag" - unixfile "github.com/ipfs/go-unixfs/file" - "golang.org/x/xerrors" - - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/lib/sectorbuilder" - "github.com/filecoin-project/lotus/storage/sectorblocks" -) - -type minerHandlerFunc func(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) - -func (h *Handler) handle(ctx context.Context, deal MinerDeal, cb minerHandlerFunc, next api.DealState) { - go func() { - mut, err := cb(ctx, deal) - - if err == nil && next == api.DealNoUpdate { - return - } - - select { - case h.updated <- minerDealUpdate{ - newState: next, - id: deal.ProposalCid, - err: err, - mut: mut, - }: - case <-h.stop: - } - }() -} - -// ACCEPTED - -func (h *Handler) checkVoucher(ctx context.Context, deal MinerDeal, voucher *types.SignedVoucher, lane uint64, maxClose uint64, amount types.BigInt) error { - err := h.full.PaychVoucherCheckValid(ctx, deal.Proposal.Payment.PayChActor, voucher) - if err != nil { - return err - } - - if voucher.Extra == nil { - return xerrors.New("voucher.Extra not set") - } - - if voucher.Extra.Actor != deal.Proposal.MinerAddress { - return xerrors.Errorf("extra params actor didn't match miner address in proposal: '%s' != '%s'", voucher.Extra.Actor, deal.Proposal.MinerAddress) - } - - if voucher.Extra.Method != actors.MAMethods.PaymentVerifyInclusion { - return xerrors.Errorf("expected extra method %d, got %d", actors.MAMethods.PaymentVerifyInclusion, voucher.Extra.Method) - } - - var inclChallenge actors.PieceInclVoucherData - if err := cbor.DecodeInto(voucher.Extra.Data, &inclChallenge); err != nil { - return xerrors.Errorf("failed to decode storage voucher data for verification: %w", err) - } - - if inclChallenge.PieceSize.Uint64() != deal.Proposal.Size { - return xerrors.Errorf("paych challenge piece size didn't match deal proposal size: %d != %d", inclChallenge.PieceSize.Uint64(), deal.Proposal.Size) - } - - if !bytes.Equal(inclChallenge.CommP, deal.Proposal.CommP) { - return xerrors.New("paych challenge commP didn't match deal proposal") - } - - if voucher.MinCloseHeight > maxClose { - return xerrors.Errorf("MinCloseHeight too high (%d), max expected: %d", voucher.MinCloseHeight, maxClose) - } - - if voucher.TimeLock > maxClose { - return xerrors.Errorf("TimeLock too high (%d), max expected: %d", voucher.TimeLock, maxClose) - } - - if len(voucher.Merges) > 0 { - return xerrors.New("didn't expect any merges") - } - - if voucher.Amount.LessThan(amount) { - return xerrors.Errorf("not enough funds in the voucher: %s < %s; vl=%d", voucher.Amount, amount, len(deal.Proposal.Payment.Vouchers)) - } - - if voucher.Lane != lane { - return xerrors.Errorf("expected all vouchers on lane %d, found voucher on lane %d", lane, voucher.Lane) - } - - return nil -} - -func (h *Handler) consumeVouchers(ctx context.Context, deal MinerDeal) error { - curHead, err := h.full.ChainHead(ctx) - if err != nil { - return err - } - if len(deal.Proposal.Payment.Vouchers) == 0 { - return xerrors.Errorf("no payment vouchers for deal") - } - - increment := deal.Proposal.Duration / uint64(len(deal.Proposal.Payment.Vouchers)) - - startH := deal.Proposal.Payment.Vouchers[0].TimeLock - increment - if startH > curHead.Height()+build.DealVoucherSkewLimit { - return xerrors.Errorf("deal starts too far into the future: start=%d; h=%d; max=%d; inc=%d", startH, curHead.Height(), curHead.Height()+build.DealVoucherSkewLimit, increment) - } - - vspec := VoucherSpec(deal.Proposal.Duration, deal.Proposal.TotalPrice, startH, nil) - - lane := deal.Proposal.Payment.Vouchers[0].Lane - - for i, voucher := range deal.Proposal.Payment.Vouchers { - maxClose := curHead.Height() + (increment * uint64(i+1)) + build.DealVoucherSkewLimit - - if err := h.checkVoucher(ctx, deal, voucher, lane, maxClose, vspec[i].Amount); err != nil { - return xerrors.Errorf("validating payment voucher %d: %w", i, err) - } - } - - minPrice := types.BigMul(types.BigMul(h.pricePerByteBlock, types.NewInt(deal.Proposal.Size)), types.NewInt(deal.Proposal.Duration)) - if types.BigCmp(minPrice, deal.Proposal.TotalPrice) > 0 { - return xerrors.Errorf("minimum price: %s", minPrice) - } - - prevAmt := types.NewInt(0) - - for i, voucher := range deal.Proposal.Payment.Vouchers { - delta, err := h.full.PaychVoucherAdd(ctx, deal.Proposal.Payment.PayChActor, voucher, nil, types.BigSub(vspec[i].Amount, prevAmt)) - if err != nil { - return xerrors.Errorf("consuming payment voucher %d: %w", i, err) - } - prevAmt = types.BigAdd(prevAmt, delta) - } - - return nil -} - -func (h *Handler) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) { - switch deal.Proposal.SerializationMode { - //case SerializationRaw: - //case SerializationIPLD: - case SerializationUnixFs: - default: - return nil, xerrors.Errorf("deal proposal with unsupported serialization: %s", deal.Proposal.SerializationMode) - } - - if deal.Proposal.Payment.ChannelMessage != nil { - log.Info("waiting for channel message to appear on chain") - if _, err := h.full.StateWaitMsg(ctx, *deal.Proposal.Payment.ChannelMessage); err != nil { - return nil, xerrors.Errorf("waiting for paych message: %w", err) - } - } - - if err := h.consumeVouchers(ctx, deal); err != nil { - return nil, err - } - - log.Info("fetching data for a deal") - err := h.sendSignedResponse(StorageDealResponse{ - State: api.DealAccepted, - Message: "", - Proposal: deal.ProposalCid, - }) - if err != nil { - return nil, err - } - - return nil, merkledag.FetchGraph(ctx, deal.Ref, h.dag) -} - -// STAGED - -func (h *Handler) staged(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) { - err := h.sendSignedResponse(StorageDealResponse{ - State: api.DealStaged, - Proposal: deal.ProposalCid, - }) - if err != nil { - log.Warnf("Sending deal response failed: %s", err) - } - - root, err := h.dag.Get(ctx, deal.Ref) - if err != nil { - return nil, xerrors.Errorf("failed to get file root for deal: %s", err) - } - - // TODO: abstract this away into ReadSizeCloser + implement different modes - n, err := unixfile.NewUnixfsFile(ctx, h.dag, root) - if err != nil { - return nil, xerrors.Errorf("cannot open unixfs file: %s", err) - } - - uf, ok := n.(sectorblocks.UnixfsReader) - if !ok { - // we probably got directory, unsupported for now - return nil, xerrors.Errorf("unsupported unixfs file type") - } - - sectorID, err := h.secst.AddUnixfsPiece(deal.Proposal.PieceRef, uf, deal.Proposal.Duration) - if err != nil { - return nil, xerrors.Errorf("AddPiece failed: %s", err) - } - - log.Warnf("New Sector: %d", sectorID) - return func(deal *MinerDeal) { - deal.SectorID = sectorID - }, nil -} - -// SEALING - -func getInclusionProof(ref string, status sectorbuilder.SectorSealingStatus) (PieceInclusionProof, error) { - for i, p := range status.Pieces { - if p.Key == ref { - return PieceInclusionProof{ - Position: uint64(i), - ProofElements: p.InclusionProof, - }, nil - } - } - return PieceInclusionProof{}, xerrors.Errorf("pieceInclusionProof for %s in sector %d not found", ref, status.SectorID) -} - -func (h *Handler) waitSealed(ctx context.Context, deal MinerDeal) (sectorbuilder.SectorSealingStatus, error) { - status, err := h.secst.WaitSeal(ctx, deal.SectorID) - if err != nil { - return sectorbuilder.SectorSealingStatus{}, err - } - - switch status.State { - case sealing_state.Sealed: - case sealing_state.Failed: - return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sealing sector %d for deal %s (ref=%s) failed: %s", deal.SectorID, deal.ProposalCid, deal.Ref, status.SealErrorMsg) - case sealing_state.Pending: - return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sector status was 'pending' after call to WaitSeal (for sector %d)", deal.SectorID) - case sealing_state.Sealing: - return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sector status was 'wait' after call to WaitSeal (for sector %d)", deal.SectorID) - default: - return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("unknown SealStatusCode: %d", status.SectorID) - } - - return status, nil -} - -func (h *Handler) sealing(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) { - status, err := h.waitSealed(ctx, deal) - if err != nil { - return nil, err - } - - // TODO: don't hardcode unixfs - ip, err := getInclusionProof(string(sectorblocks.SerializationUnixfs0)+deal.Ref.String(), status) - if err != nil { - return nil, err - } - - proof := &actors.InclusionProof{ - Sector: deal.SectorID, - Proof: ip.ProofElements, - } - proofB, err := cbor.DumpObject(proof) - if err != nil { - return nil, err - } - - // store proofs for channels - for i, v := range deal.Proposal.Payment.Vouchers { - if v.Extra.Method == actors.MAMethods.PaymentVerifyInclusion { - // TODO: Set correct minAmount - if _, err := h.full.PaychVoucherAdd(ctx, deal.Proposal.Payment.PayChActor, v, proofB, types.NewInt(0)); err != nil { - return nil, xerrors.Errorf("storing payment voucher %d proof: %w", i, err) - } - } - } - - err = h.sendSignedResponse(StorageDealResponse{ - State: api.DealSealing, - Proposal: deal.ProposalCid, - PieceInclusionProof: ip, - CommD: status.CommD[:], - }) - if err != nil { - log.Warnf("Sending deal response failed: %s", err) - } - - return nil, nil -} - -func (h *Handler) complete(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) { - mcid, err := h.commt.WaitCommit(ctx, deal.Proposal.MinerAddress, deal.SectorID) - if err != nil { - log.Warnf("Waiting for sector commitment message: %s", err) - } - - err = h.sendSignedResponse(StorageDealResponse{ - State: api.DealComplete, - Proposal: deal.ProposalCid, - - SectorCommitMessage: &mcid, - }) - if err != nil { - log.Warnf("Sending deal response failed: %s", err) - } - - return nil, nil -} diff --git a/chain/deals/handler.go b/chain/deals/provider.go similarity index 66% rename from chain/deals/handler.go rename to chain/deals/provider.go index 02db7153c..86383c61b 100644 --- a/chain/deals/handler.go +++ b/chain/deals/provider.go @@ -2,43 +2,40 @@ package deals import ( "context" - "math" "sync" cid "github.com/ipfs/go-cid" datastore "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/namespace" - cbor "github.com/ipfs/go-ipld-cbor" inet "github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/peer" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/cborrpc" "github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/storage/commitment" "github.com/filecoin-project/lotus/storage/sectorblocks" ) -func init() { - cbor.RegisterCborType(MinerDeal{}) -} - type MinerDeal struct { Client peer.ID - Proposal StorageDealProposal + Proposal actors.StorageDealProposal ProposalCid cid.Cid State api.DealState Ref cid.Cid + DealID uint64 SectorID uint64 // Set when State >= DealStaged s inet.Stream } -type Handler struct { +type Provider struct { pricePerByteBlock types.BigInt // how much we want for storing one byte for one block minPieceSize uint64 @@ -73,7 +70,7 @@ type minerDealUpdate struct { mut func(*MinerDeal) } -func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *commitment.Tracker, dag dtypes.StagingDAG, fullNode api.FullNode) (*Handler, error) { +func NewProvider(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *commitment.Tracker, dag dtypes.StagingDAG, fullNode api.FullNode) (*Provider, error) { addr, err := ds.Get(datastore.NewKey("miner-address")) if err != nil { return nil, err @@ -83,7 +80,7 @@ func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *c return nil, err } - h := &Handler{ + h := &Provider{ secst: secst, commt: commt, dag: dag, @@ -112,7 +109,7 @@ func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *c if h.ask == nil { // TODO: we should be fine with this state, and just say it means 'not actively accepting deals' // for now... lets just set a price - if err := h.SetPrice(types.NewInt(3), 1000000); err != nil { + if err := h.SetPrice(types.NewInt(500_000_000), 1000000); err != nil { return nil, xerrors.Errorf("failed setting a default price: %w", err) } } @@ -120,40 +117,40 @@ func NewHandler(ds dtypes.MetadataDS, secst *sectorblocks.SectorBlocks, commt *c return h, nil } -func (h *Handler) Run(ctx context.Context) { +func (p *Provider) Run(ctx context.Context) { // TODO: restore state go func() { - defer log.Warn("quitting deal handler loop") - defer close(h.stopped) + defer log.Warn("quitting deal provider loop") + defer close(p.stopped) for { select { - case deal := <-h.incoming: // DealAccepted - h.onIncoming(deal) - case update := <-h.updated: // DealStaged - h.onUpdated(ctx, update) - case <-h.stop: + case deal := <-p.incoming: // DealAccepted + p.onIncoming(deal) + case update := <-p.updated: // DealStaged + p.onUpdated(ctx, update) + case <-p.stop: return } } }() } -func (h *Handler) onIncoming(deal MinerDeal) { +func (p *Provider) onIncoming(deal MinerDeal) { log.Info("incoming deal") - h.conns[deal.ProposalCid] = deal.s + p.conns[deal.ProposalCid] = deal.s - if err := h.deals.Begin(deal.ProposalCid, deal); err != nil { + if err := p.deals.Begin(deal.ProposalCid, &deal); err != nil { // This can happen when client re-sends proposal - h.failDeal(deal.ProposalCid, err) + p.failDeal(deal.ProposalCid, err) log.Errorf("deal tracking failed: %s", err) return } go func() { - h.updated <- minerDealUpdate{ + p.updated <- minerDealUpdate{ newState: api.DealAccepted, id: deal.ProposalCid, err: nil, @@ -161,15 +158,15 @@ func (h *Handler) onIncoming(deal MinerDeal) { }() } -func (h *Handler) onUpdated(ctx context.Context, update minerDealUpdate) { +func (p *Provider) onUpdated(ctx context.Context, update minerDealUpdate) { log.Infof("Deal %s updated state to %d", update.id, update.newState) if update.err != nil { - log.Errorf("deal %s failed: %s", update.id, update.err) - h.failDeal(update.id, update.err) + log.Errorf("deal %s (newSt: %d) failed: %s", update.id, update.newState, update.err) + p.failDeal(update.id, update.err) return } var deal MinerDeal - err := h.deals.MutateMiner(update.id, func(d *MinerDeal) error { + err := p.deals.MutateMiner(update.id, func(d *MinerDeal) error { d.State = update.newState if update.mut != nil { update.mut(d) @@ -178,30 +175,29 @@ func (h *Handler) onUpdated(ctx context.Context, update minerDealUpdate) { return nil }) if err != nil { - h.failDeal(update.id, err) + p.failDeal(update.id, err) return } switch update.newState { case api.DealAccepted: - h.handle(ctx, deal, h.accept, api.DealStaged) + p.handle(ctx, deal, p.accept, api.DealStaged) case api.DealStaged: - h.handle(ctx, deal, h.staged, api.DealSealing) + p.handle(ctx, deal, p.staged, api.DealSealing) case api.DealSealing: - h.handle(ctx, deal, h.sealing, api.DealComplete) + p.handle(ctx, deal, p.sealing, api.DealComplete) case api.DealComplete: - h.handle(ctx, deal, h.complete, api.DealNoUpdate) + p.handle(ctx, deal, p.complete, api.DealNoUpdate) } } -func (h *Handler) newDeal(s inet.Stream, proposal StorageDealProposal) (MinerDeal, error) { - // TODO: Review: Not signed? - proposalNd, err := cbor.WrapObject(proposal, math.MaxUint64, -1) +func (p *Provider) newDeal(s inet.Stream, proposal actors.StorageDealProposal) (MinerDeal, error) { + proposalNd, err := cborrpc.AsIpld(&proposal) if err != nil { return MinerDeal{}, err } - ref, err := cid.Parse(proposal.PieceRef) + ref, err := cid.Cast(proposal.PieceRef) if err != nil { return MinerDeal{}, err } @@ -218,27 +214,27 @@ func (h *Handler) newDeal(s inet.Stream, proposal StorageDealProposal) (MinerDea }, nil } -func (h *Handler) HandleStream(s inet.Stream) { +func (p *Provider) HandleStream(s inet.Stream) { log.Info("Handling storage deal proposal!") - proposal, err := h.readProposal(s) + proposal, err := p.readProposal(s) if err != nil { log.Error(err) s.Close() return } - deal, err := h.newDeal(s, proposal.Proposal) + deal, err := p.newDeal(s, proposal) if err != nil { log.Error(err) s.Close() return } - h.incoming <- deal + p.incoming <- deal } -func (h *Handler) Stop() { - close(h.stop) - <-h.stopped +func (p *Provider) Stop() { + close(p.stop) + <-p.stopped } diff --git a/chain/deals/asks.go b/chain/deals/provider_asks.go similarity index 57% rename from chain/deals/asks.go rename to chain/deals/provider_asks.go index df82550e8..1b1960b97 100644 --- a/chain/deals/asks.go +++ b/chain/deals/provider_asks.go @@ -1,6 +1,7 @@ package deals import ( + "bytes" "context" "time" @@ -9,49 +10,48 @@ import ( "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/lib/cborrpc" datastore "github.com/ipfs/go-datastore" - cbor "github.com/ipfs/go-ipld-cbor" inet "github.com/libp2p/go-libp2p-core/network" "golang.org/x/xerrors" ) -func (h *Handler) SetPrice(p types.BigInt, ttlsecs int64) error { - h.askLk.Lock() - defer h.askLk.Unlock() +func (p *Provider) SetPrice(price types.BigInt, ttlsecs int64) error { + p.askLk.Lock() + defer p.askLk.Unlock() var seqno uint64 - if h.ask != nil { - seqno = h.ask.Ask.SeqNo + 1 + if p.ask != nil { + seqno = p.ask.Ask.SeqNo + 1 } now := time.Now().Unix() ask := &types.StorageAsk{ - Price: p, - Timestamp: now, - Expiry: now + ttlsecs, - Miner: h.actor, + Price: price, + Timestamp: uint64(now), + Expiry: uint64(now + ttlsecs), + Miner: p.actor, SeqNo: seqno, - MinPieceSize: h.minPieceSize, + MinPieceSize: p.minPieceSize, } - ssa, err := h.signAsk(ask) + ssa, err := p.signAsk(ask) if err != nil { return err } - return h.saveAsk(ssa) + return p.saveAsk(ssa) } -func (h *Handler) getAsk(m address.Address) *types.SignedStorageAsk { - h.askLk.Lock() - defer h.askLk.Unlock() - if m != h.actor { +func (p *Provider) getAsk(m address.Address) *types.SignedStorageAsk { + p.askLk.Lock() + defer p.askLk.Unlock() + if m != p.actor { return nil } - return h.ask + return p.ask } -func (h *Handler) HandleAskStream(s inet.Stream) { +func (p *Provider) HandleAskStream(s inet.Stream) { defer s.Close() var ar AskRequest if err := cborrpc.ReadCborRPC(s, &ar); err != nil { @@ -59,7 +59,7 @@ func (h *Handler) HandleAskStream(s inet.Stream) { return } - resp := h.processAskRequest(&ar) + resp := p.processAskRequest(&ar) if err := cborrpc.WriteCborRPC(s, resp); err != nil { log.Errorf("failed to write ask response: %s", err) @@ -67,19 +67,19 @@ func (h *Handler) HandleAskStream(s inet.Stream) { } } -func (h *Handler) processAskRequest(ar *AskRequest) *AskResponse { +func (p *Provider) processAskRequest(ar *AskRequest) *AskResponse { return &AskResponse{ - Ask: h.getAsk(ar.Miner), + Ask: p.getAsk(ar.Miner), } } var bestAskKey = datastore.NewKey("latest-ask") -func (h *Handler) tryLoadAsk() error { - h.askLk.Lock() - defer h.askLk.Unlock() +func (p *Provider) tryLoadAsk() error { + p.askLk.Lock() + defer p.askLk.Unlock() - err := h.loadAsk() + err := p.loadAsk() if err != nil { if xerrors.Is(err, datastore.ErrNotFound) { log.Warn("no previous ask found, miner will not accept deals until a price is set") @@ -91,33 +91,33 @@ func (h *Handler) tryLoadAsk() error { return nil } -func (h *Handler) loadAsk() error { - askb, err := h.ds.Get(datastore.NewKey("latest-ask")) +func (p *Provider) loadAsk() error { + askb, err := p.ds.Get(datastore.NewKey("latest-ask")) if err != nil { return xerrors.Errorf("failed to load most recent ask from disk: %w", err) } var ssa types.SignedStorageAsk - if err := cbor.DecodeInto(askb, &ssa); err != nil { + if err := cborrpc.ReadCborRPC(bytes.NewReader(askb), &ssa); err != nil { return err } - h.ask = &ssa + p.ask = &ssa return nil } -func (h *Handler) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error) { - b, err := cbor.DumpObject(a) +func (p *Provider) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error) { + b, err := cborrpc.Dump(a) if err != nil { return nil, err } - worker, err := h.getWorker(h.actor) + worker, err := p.getWorker(p.actor) if err != nil { return nil, xerrors.Errorf("failed to get worker to sign ask: %w", err) } - sig, err := h.full.WalletSign(context.TODO(), worker, b) + sig, err := p.full.WalletSign(context.TODO(), worker, b) if err != nil { return nil, err } @@ -128,29 +128,29 @@ func (h *Handler) signAsk(a *types.StorageAsk) (*types.SignedStorageAsk, error) }, nil } -func (h *Handler) saveAsk(a *types.SignedStorageAsk) error { - b, err := cbor.DumpObject(a) +func (p *Provider) saveAsk(a *types.SignedStorageAsk) error { + b, err := cborrpc.Dump(a) if err != nil { return err } - if err := h.ds.Put(bestAskKey, b); err != nil { + if err := p.ds.Put(bestAskKey, b); err != nil { return err } - h.ask = a + p.ask = a return nil } func (c *Client) checkAskSignature(ask *types.SignedStorageAsk) error { tss := c.sm.ChainStore().GetHeaviestTipSet().ParentState() - w, err := stmgr.GetMinerWorker(context.TODO(), c.sm, tss, ask.Ask.Miner) + w, err := stmgr.GetMinerWorkerRaw(context.TODO(), c.sm, tss, ask.Ask.Miner) if err != nil { return xerrors.Errorf("failed to get worker for miner in ask", err) } - sigb, err := cbor.DumpObject(ask.Ask) + sigb, err := cborrpc.Dump(ask.Ask) if err != nil { return xerrors.Errorf("failed to re-serialize ask") } diff --git a/chain/deals/provider_states.go b/chain/deals/provider_states.go new file mode 100644 index 000000000..595f236da --- /dev/null +++ b/chain/deals/provider_states.go @@ -0,0 +1,309 @@ +package deals + +import ( + "bytes" + "context" + + "github.com/filecoin-project/go-sectorbuilder/sealing_state" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-merkledag" + unixfile "github.com/ipfs/go-unixfs/file" + "golang.org/x/xerrors" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/address" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/lib/sectorbuilder" + "github.com/filecoin-project/lotus/storage/sectorblocks" +) + +type providerHandlerFunc func(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) + +func (p *Provider) handle(ctx context.Context, deal MinerDeal, cb providerHandlerFunc, next api.DealState) { + go func() { + mut, err := cb(ctx, deal) + + if err == nil && next == api.DealNoUpdate { + return + } + + select { + case p.updated <- minerDealUpdate{ + newState: next, + id: deal.ProposalCid, + err: err, + mut: mut, + }: + case <-p.stop: + } + }() +} + +// ACCEPTED + +func (p *Provider) addMarketFunds(ctx context.Context, worker address.Address, deal MinerDeal) error { + log.Info("Adding market funds for storage collateral") + smsg, err := p.full.MpoolPushMessage(ctx, &types.Message{ + To: actors.StorageMarketAddress, + From: worker, + Value: deal.Proposal.StorageCollateral, + GasPrice: types.NewInt(0), + GasLimit: types.NewInt(1000000), + Method: actors.SMAMethods.AddBalance, + }) + if err != nil { + return err + } + + r, err := p.full.StateWaitMsg(ctx, smsg.Cid()) + if err != nil { + return err + } + + if r.Receipt.ExitCode != 0 { + return xerrors.Errorf("adding funds to storage miner market actor failed: exit %d", r.Receipt.ExitCode) + } + + return nil +} + +func (p *Provider) accept(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) { + switch deal.Proposal.PieceSerialization { + //case SerializationRaw: + //case SerializationIPLD: + case actors.SerializationUnixFSv0: + default: + return nil, xerrors.Errorf("deal proposal with unsupported serialization: %s", deal.Proposal.PieceSerialization) + } + + head, err := p.full.ChainHead(ctx) + if err != nil { + return nil, err + } + if head.Height() >= deal.Proposal.ProposalExpiration { + return nil, xerrors.Errorf("deal proposal already expired") + } + + // TODO: check StorageCollateral + + // TODO: + minPrice := types.BigDiv(types.BigMul(p.ask.Ask.Price, types.NewInt(deal.Proposal.PieceSize)), types.NewInt(1<<30)) + if deal.Proposal.StoragePricePerEpoch.LessThan(minPrice) { + return nil, xerrors.Errorf("storage price per epoch less than asking price: %s < %s", deal.Proposal.StoragePricePerEpoch, minPrice) + } + + if deal.Proposal.PieceSize < p.ask.Ask.MinPieceSize { + return nil, xerrors.Errorf("piece size less than minimum required size: %d < %d", deal.Proposal.PieceSize, p.ask.Ask.MinPieceSize) + } + + // check market funds + clientMarketBalance, err := p.full.StateMarketBalance(ctx, deal.Proposal.Client, nil) + if err != nil { + return nil, xerrors.Errorf("getting client market balance failed: %w", err) + } + + // This doesn't guarantee that the client won't withdraw / lock those funds + // but it's a decent first filter + if clientMarketBalance.Available.LessThan(deal.Proposal.TotalStoragePrice()) { + return nil, xerrors.New("clientMarketBalance.Available too small") + } + + waddr, err := p.full.StateMinerWorker(ctx, deal.Proposal.Provider, nil) + if err != nil { + return nil, err + } + + providerMarketBalance, err := p.full.StateMarketBalance(ctx, waddr, nil) + if err != nil { + return nil, xerrors.Errorf("getting provider market balance failed: %w", err) + } + + // TODO: this needs to be atomic + if providerMarketBalance.Available.LessThan(deal.Proposal.StorageCollateral) { + if err := p.addMarketFunds(ctx, waddr, deal); err != nil { + return nil, err + } + } + + log.Info("publishing deal") + + storageDeal := actors.StorageDeal{ + Proposal: deal.Proposal, + } + if err := api.SignWith(ctx, p.full.WalletSign, waddr, &storageDeal); err != nil { + return nil, xerrors.Errorf("signing storage deal failed: ", err) + } + + params, err := actors.SerializeParams(&actors.PublishStorageDealsParams{ + Deals: []actors.StorageDeal{storageDeal}, + }) + if err != nil { + return nil, xerrors.Errorf("serializing PublishStorageDeals params failed: ", err) + } + + // TODO: We may want this to happen after fetching data + smsg, err := p.full.MpoolPushMessage(ctx, &types.Message{ + To: actors.StorageMarketAddress, + From: waddr, + Value: types.NewInt(0), + GasPrice: types.NewInt(0), + GasLimit: types.NewInt(1000000), + Method: actors.SMAMethods.PublishStorageDeals, + Params: params, + }) + if err != nil { + return nil, err + } + r, err := p.full.StateWaitMsg(ctx, smsg.Cid()) + if err != nil { + return nil, err + } + if r.Receipt.ExitCode != 0 { + return nil, xerrors.Errorf("publishing deal failed: exit %d", r.Receipt.ExitCode) + } + var resp actors.PublishStorageDealResponse + if err := resp.UnmarshalCBOR(bytes.NewReader(r.Receipt.Return)); err != nil { + return nil, err + } + if len(resp.DealIDs) != 1 { + return nil, xerrors.Errorf("got unexpected number of DealIDs from") + } + + log.Info("fetching data for a deal") + mcid := smsg.Cid() + err = p.sendSignedResponse(&Response{ + State: api.DealAccepted, + Message: "", + Proposal: deal.ProposalCid, + PublishMessage: &mcid, + }) + if err != nil { + return nil, err + } + + return func(deal *MinerDeal) { + deal.DealID = resp.DealIDs[0] + }, merkledag.FetchGraph(ctx, deal.Ref, p.dag) +} + +// STAGED + +func (p *Provider) staged(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) { + err := p.sendSignedResponse(&Response{ + State: api.DealStaged, + Proposal: deal.ProposalCid, + }) + if err != nil { + log.Warnf("Sending deal response failed: %s", err) + } + + root, err := p.dag.Get(ctx, deal.Ref) + if err != nil { + return nil, xerrors.Errorf("failed to get file root for deal: %s", err) + } + + // TODO: abstract this away into ReadSizeCloser + implement different modes + n, err := unixfile.NewUnixfsFile(ctx, p.dag, root) + if err != nil { + return nil, xerrors.Errorf("cannot open unixfs file: %s", err) + } + + uf, ok := n.(sectorblocks.UnixfsReader) + if !ok { + // we probably got directory, unsupported for now + return nil, xerrors.Errorf("unsupported unixfs file type") + } + + // TODO: uf.Size() is user input, not trusted + // This won't be useful / here after we migrate to putting CARs into sectors + size, err := uf.Size() + if err != nil { + return nil, xerrors.Errorf("getting unixfs file size: %w", err) + } + if uint64(size) != deal.Proposal.PieceSize { + return nil, xerrors.Errorf("deal.Proposal.PieceSize didn't match unixfs file size") + } + + pcid, err := cid.Cast(deal.Proposal.PieceRef) + if err != nil { + return nil, err + } + + sectorID, err := p.secst.AddUnixfsPiece(pcid, uf, deal.DealID) + if err != nil { + return nil, xerrors.Errorf("AddPiece failed: %s", err) + } + + log.Warnf("New Sector: %d", sectorID) + return func(deal *MinerDeal) { + deal.SectorID = sectorID + }, nil +} + +// SEALING + +func (p *Provider) waitSealed(ctx context.Context, deal MinerDeal) (sectorbuilder.SectorSealingStatus, error) { + status, err := p.secst.WaitSeal(ctx, deal.SectorID) + if err != nil { + return sectorbuilder.SectorSealingStatus{}, err + } + + switch status.State { + case sealing_state.Sealed: + case sealing_state.Failed: + return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sealing sector %d for deal %s (ref=%s) failed: %s", deal.SectorID, deal.ProposalCid, deal.Ref, status.SealErrorMsg) + case sealing_state.Pending: + return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sector status was 'pending' after call to WaitSeal (for sector %d)", deal.SectorID) + case sealing_state.Sealing: + return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("sector status was 'wait' after call to WaitSeal (for sector %d)", deal.SectorID) + default: + return sectorbuilder.SectorSealingStatus{}, xerrors.Errorf("unknown SealStatusCode: %d", status.SectorID) + } + + return status, nil +} + +func (p *Provider) sealing(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) { + err := p.sendSignedResponse(&Response{ + State: api.DealSealing, + Proposal: deal.ProposalCid, + }) + if err != nil { + log.Warnf("Sending deal response failed: %s", err) + } + + if err := p.secst.SealSector(ctx, deal.SectorID); err != nil { + return nil, xerrors.Errorf("sealing sector failed: %w", err) + } + + _, err = p.waitSealed(ctx, deal) + if err != nil { + return nil, err + } + // TODO: Spec doesn't say anything about inclusion proofs anywhere + // Not sure what mechanisms prevents miner from storing data that isn't + // clients' data + + return nil, nil +} + +func (p *Provider) complete(ctx context.Context, deal MinerDeal) (func(*MinerDeal), error) { + // TODO: Add dealID to commtracker (probably before sealing) + mcid, err := p.commt.WaitCommit(ctx, deal.Proposal.Provider, deal.SectorID) + if err != nil { + log.Warnf("Waiting for sector commitment message: %s", err) + } + + err = p.sendSignedResponse(&Response{ + State: api.DealComplete, + Proposal: deal.ProposalCid, + + CommitMessage: &mcid, + }) + if err != nil { + log.Warnf("Sending deal response failed: %s", err) + } + + return nil, nil +} diff --git a/chain/deals/handler_utils.go b/chain/deals/provider_utils.go similarity index 63% rename from chain/deals/handler_utils.go rename to chain/deals/provider_utils.go index 099a07e7d..5931cefc9 100644 --- a/chain/deals/handler_utils.go +++ b/chain/deals/provider_utils.go @@ -12,13 +12,12 @@ import ( "github.com/filecoin-project/lotus/lib/cborrpc" "github.com/ipfs/go-cid" - cbor "github.com/ipfs/go-ipld-cbor" inet "github.com/libp2p/go-libp2p-core/network" "golang.org/x/xerrors" ) -func (h *Handler) failDeal(id cid.Cid, cerr error) { - if err := h.deals.End(id); err != nil { +func (p *Provider) failDeal(id cid.Cid, cerr error) { + if err := p.deals.End(id); err != nil { log.Warnf("deals.End: %s", err) } @@ -29,16 +28,16 @@ func (h *Handler) failDeal(id cid.Cid, cerr error) { log.Errorf("deal %s failed: %s", id, cerr) - err := h.sendSignedResponse(StorageDealResponse{ + err := p.sendSignedResponse(&Response{ State: api.DealFailed, Message: cerr.Error(), Proposal: id, }) - s, ok := h.conns[id] + s, ok := p.conns[id] if ok { _ = s.Reset() - delete(h.conns, id) + delete(p.conns, id) } if err != nil { @@ -46,46 +45,50 @@ func (h *Handler) failDeal(id cid.Cid, cerr error) { } } -func (h *Handler) readProposal(s inet.Stream) (proposal SignedStorageDealProposal, err error) { +func (p *Provider) readProposal(s inet.Stream) (proposal actors.StorageDealProposal, err error) { if err := cborrpc.ReadCborRPC(s, &proposal); err != nil { log.Errorw("failed to read proposal message", "error", err) - return SignedStorageDealProposal{}, err + return proposal, err + } + + if err := proposal.Verify(); err != nil { + return proposal, xerrors.Errorf("verifying StorageDealProposal: %w", err) } // TODO: Validate proposal maybe // (and signature, obviously) - if proposal.Proposal.MinerAddress != h.actor { - log.Errorf("proposal with wrong MinerAddress: %s", proposal.Proposal.MinerAddress) - return SignedStorageDealProposal{}, err + if proposal.Provider != p.actor { + log.Errorf("proposal with wrong ProviderAddress: %s", proposal.Provider) + return proposal, err } return } -func (h *Handler) sendSignedResponse(resp StorageDealResponse) error { - s, ok := h.conns[resp.Proposal] +func (p *Provider) sendSignedResponse(resp *Response) error { + s, ok := p.conns[resp.Proposal] if !ok { return xerrors.New("couldn't send response: not connected") } - msg, err := cbor.DumpObject(&resp) + msg, err := cborrpc.Dump(resp) if err != nil { return xerrors.Errorf("serializing response: %w", err) } - worker, err := h.getWorker(h.actor) + worker, err := p.getWorker(p.actor) if err != nil { return err } - sig, err := h.full.WalletSign(context.TODO(), worker, msg) + sig, err := p.full.WalletSign(context.TODO(), worker, msg) if err != nil { return xerrors.Errorf("failed to sign response message: %w", err) } - signedResponse := SignedStorageDealResponse{ - Response: resp, + signedResponse := &SignedResponse{ + Response: *resp, Signature: sig, } @@ -93,18 +96,18 @@ func (h *Handler) sendSignedResponse(resp StorageDealResponse) error { if err != nil { // Assume client disconnected s.Close() - delete(h.conns, resp.Proposal) + delete(p.conns, resp.Proposal) } return err } -func (h *Handler) getWorker(miner address.Address) (address.Address, error) { +func (p *Provider) getWorker(miner address.Address) (address.Address, error) { getworker := &types.Message{ To: miner, From: miner, Method: actors.MAMethods.GetWorkerAddr, } - r, err := h.full.StateCall(context.TODO(), getworker, nil) + r, err := p.full.StateCall(context.TODO(), getworker, nil) if err != nil { return address.Undef, xerrors.Errorf("getting worker address: %w", err) } diff --git a/chain/deals/state_store.go b/chain/deals/state_store.go index 00c5f0424..ae959146f 100644 --- a/chain/deals/state_store.go +++ b/chain/deals/state_store.go @@ -1,10 +1,11 @@ package deals import ( + "bytes" + "github.com/filecoin-project/lotus/lib/cborrpc" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore/query" - cbor "github.com/ipfs/go-ipld-cbor" "golang.org/x/xerrors" ) @@ -22,7 +23,7 @@ func (st *StateStore) Begin(i cid.Cid, state interface{}) error { return xerrors.Errorf("Already tracking state for %s", i) } - b, err := cbor.DumpObject(state) + b, err := cborrpc.Dump(state) if err != nil { return err } @@ -75,17 +76,17 @@ func (st *MinerStateStore) MutateMiner(i cid.Cid, mutator func(*MinerDeal) error func minerMutator(m func(*MinerDeal) error) func([]byte) ([]byte, error) { return func(in []byte) ([]byte, error) { - var deal MinerDeal - err := cbor.DecodeInto(in, &deal) + deal := new(MinerDeal) + err := cborrpc.ReadCborRPC(bytes.NewReader(in), deal) if err != nil { return nil, err } - if err := m(&deal); err != nil { + if err := m(deal); err != nil { return nil, err } - return cbor.DumpObject(deal) + return cborrpc.Dump(deal) } } @@ -99,17 +100,17 @@ func (st *ClientStateStore) MutateClient(i cid.Cid, mutator func(*ClientDeal) er func clientMutator(m func(*ClientDeal) error) func([]byte) ([]byte, error) { return func(in []byte) ([]byte, error) { - var deal ClientDeal - err := cbor.DecodeInto(in, &deal) + deal := new(ClientDeal) + err := cborrpc.ReadCborRPC(bytes.NewReader(in), deal) if err != nil { return nil, err } - if err := m(&deal); err != nil { + if err := m(deal); err != nil { return nil, err } - return cbor.DumpObject(deal) + return cborrpc.Dump(deal) } } @@ -129,7 +130,7 @@ func (st *ClientStateStore) ListClient() ([]ClientDeal, error) { } var deal ClientDeal - err := cbor.DecodeInto(res.Value, &deal) + err := cborrpc.ReadCborRPC(bytes.NewReader(res.Value), &deal) if err != nil { return nil, err } diff --git a/chain/deals/types.go b/chain/deals/types.go index 58970700e..27bf31a8b 100644 --- a/chain/deals/types.go +++ b/chain/deals/types.go @@ -2,83 +2,37 @@ package deals import ( "github.com/filecoin-project/lotus/api" - "github.com/ipfs/go-cid" - cbor "github.com/ipfs/go-ipld-cbor" - "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/chain/types" + "github.com/ipfs/go-cid" ) -func init() { - cbor.RegisterCborType(StorageDealProposal{}) - cbor.RegisterCborType(SignedStorageDealProposal{}) - - cbor.RegisterCborType(PieceInclusionProof{}) - - cbor.RegisterCborType(StorageDealResponse{}) - cbor.RegisterCborType(SignedStorageDealResponse{}) - - cbor.RegisterCborType(AskRequest{}) - cbor.RegisterCborType(AskResponse{}) -} - -const ProtocolID = "/fil/storage/mk/1.0.0" +const DealProtocolID = "/fil/storage/mk/1.0.0" const AskProtocolID = "/fil/storage/ask/1.0.0" -type SerializationMode string - -const ( - SerializationUnixFs = "UnixFs" - SerializationRaw = "Raw" - SerializationIPLD = "IPLD" -) - -type StorageDealProposal struct { - PieceRef cid.Cid // TODO: port to spec - SerializationMode SerializationMode - CommP []byte - - Size uint64 - TotalPrice types.BigInt - Duration uint64 - - Payment actors.PaymentInfo - - MinerAddress address.Address - ClientAddress address.Address +type Proposal struct { + DealProposal actors.StorageDealProposal } -type SignedStorageDealProposal struct { - Proposal StorageDealProposal - - Signature *types.Signature -} - -// response - -type PieceInclusionProof struct { - Position uint64 - ProofElements []byte -} - -type StorageDealResponse struct { +type Response struct { State api.DealState - // DealRejected / DealAccepted / DealFailed / DealStaged + // DealProposalRejected Message string Proposal cid.Cid - // DealSealing - PieceInclusionProof PieceInclusionProof - CommD []byte // TODO: not in spec + // DealAccepted + StorageDeal *actors.StorageDeal + PublishMessage *cid.Cid // DealComplete - SectorCommitMessage *cid.Cid + CommitMessage *cid.Cid } -type SignedStorageDealResponse struct { - Response StorageDealResponse +// TODO: Do we actually need this to be signed? +type SignedResponse struct { + Response Response Signature *types.Signature } diff --git a/chain/deals/vouchers.go b/chain/deals/vouchers.go deleted file mode 100644 index f854299b0..000000000 --- a/chain/deals/vouchers.go +++ /dev/null @@ -1,31 +0,0 @@ -package deals - -import ( - "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/chain/types" -) - -func VoucherSpec(blocksDuration uint64, price types.BigInt, start uint64, extra *types.ModVerifyParams) []api.VoucherSpec { - nVouchers := blocksDuration / build.MinDealVoucherIncrement - if nVouchers < 1 { - nVouchers = 1 - } - if nVouchers > build.MaxVouchersPerDeal { - nVouchers = build.MaxVouchersPerDeal - } - - hIncrements := blocksDuration / nVouchers - vouchers := make([]api.VoucherSpec, nVouchers) - - for i := uint64(0); i < nVouchers; i++ { - vouchers[i] = api.VoucherSpec{ - Amount: types.BigDiv(types.BigMul(price, types.NewInt(i+1)), types.NewInt(nVouchers)), - TimeLock: start + (hIncrements * (i + 1)), - MinClose: start + (hIncrements * (i + 1)), - Extra: extra, - } - } - - return vouchers -} diff --git a/chain/gen/gen.go b/chain/gen/gen.go index ef1460430..b38f2c0df 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -206,14 +206,14 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add st := pts.ParentState() - worker, err := stmgr.GetMinerWorker(ctx, cg.sm, st, m) + worker, err := stmgr.GetMinerWorkerRaw(ctx, cg.sm, st, m) if err != nil { - return nil, nil, err + return nil, nil, xerrors.Errorf("get miner worker: %w", err) } vrfout, err := ComputeVRF(ctx, cg.w.Sign, worker, lastTicket.VRFProof) if err != nil { - return nil, nil, err + return nil, nil, xerrors.Errorf("compute VRF: %w", err) } tick := &types.Ticket{ @@ -252,7 +252,7 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad msgs, err := cg.getRandomMessages() if err != nil { - return nil, err + return nil, xerrors.Errorf("get random messages: %w", err) } for len(blks) == 0 { @@ -279,6 +279,12 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad } fts := store.NewFullTipSet(blks) + fmt.Println("Made a block: ", fts.TipSet().Cids()) + if len(fts.TipSet().Cids()) > 1 { + for _, b := range blks { + fmt.Printf("block %s: %#v\n", b.Cid(), b.Header) + } + } return &MinedTipSet{ TipSet: fts, @@ -385,7 +391,7 @@ func (mca mca) StateMinerPower(ctx context.Context, maddr address.Address, ts *t } func (mca mca) StateMinerWorker(ctx context.Context, maddr address.Address, ts *types.TipSet) (address.Address, error) { - return stmgr.GetMinerWorker(ctx, mca.sm, ts.ParentState(), maddr) + return stmgr.GetMinerWorkerRaw(ctx, mca.sm, ts.ParentState(), maddr) } func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*types.Signature, error) { @@ -393,9 +399,9 @@ func (mca mca) WalletSign(ctx context.Context, a address.Address, v []byte) (*ty } func IsRoundWinner(ctx context.Context, ts *types.TipSet, ticks []*types.Ticket, miner address.Address, a MiningCheckAPI) (bool, types.ElectionProof, error) { - r, err := a.ChainGetRandomness(ctx, ts, ticks, build.RandomnessLookback) + r, err := a.ChainGetRandomness(ctx, ts, ticks, build.EcRandomnessLookback) if err != nil { - return false, nil, err + return false, nil, xerrors.Errorf("chain get randomness: %w", err) } mworker, err := a.StateMinerWorker(ctx, miner, ts) @@ -413,7 +419,7 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, ticks []*types.Ticket, return false, nil, xerrors.Errorf("failed to check power: %w", err) } - return types.PowerCmp(vrfout, types.BigMul(pow.MinerPower, types.NewInt(build.BlocksPerEpoch)), pow.TotalPower), vrfout, nil + return types.PowerCmp(vrfout, pow.MinerPower, pow.TotalPower), vrfout, nil } type SignFunc func(context.Context, address.Address, []byte) (*types.Signature, error) diff --git a/chain/gen/mining.go b/chain/gen/mining.go index 0ede4460e..5977fc66a 100644 --- a/chain/gen/mining.go +++ b/chain/gen/mining.go @@ -27,7 +27,7 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal height := parents.Height() + uint64(len(tickets)) - worker, err := stmgr.GetMinerWorker(ctx, sm, st, miner) + worker, err := stmgr.GetMinerWorkerRaw(ctx, sm, st, miner) if err != nil { return nil, xerrors.Errorf("failed to get miner worker: %w", err) } diff --git a/chain/gen/utils.go b/chain/gen/utils.go index 6a1a5ca34..303878c94 100644 --- a/chain/gen/utils.go +++ b/chain/gen/utils.go @@ -5,6 +5,14 @@ import ( "fmt" amt "github.com/filecoin-project/go-amt-ipld" + "github.com/ipfs/go-cid" + "github.com/ipfs/go-datastore" + hamt "github.com/ipfs/go-hamt-ipld" + bstore "github.com/ipfs/go-ipfs-blockstore" + peer "github.com/libp2p/go-libp2p-peer" + cbg "github.com/whyrusleeping/cbor-gen" + "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/build" actors "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/address" @@ -12,14 +20,6 @@ import ( "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" - "golang.org/x/xerrors" - - "github.com/ipfs/go-cid" - "github.com/ipfs/go-datastore" - hamt "github.com/ipfs/go-hamt-ipld" - bstore "github.com/ipfs/go-ipfs-blockstore" - peer "github.com/libp2p/go-libp2p-peer" - cbg "github.com/whyrusleeping/cbor-gen" ) type GenesisBootstrap struct { @@ -56,7 +56,7 @@ func SetupInitActor(bs bstore.Blockstore, addrs []address.Address) (*types.Actor } act := &types.Actor{ - Code: actors.InitActorCodeCid, + Code: actors.InitCodeCid, Head: statecid, } @@ -85,10 +85,19 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types return nil, xerrors.Errorf("setup init actor: %w", err) } - if err := state.SetActor(actors.InitActorAddress, initact); err != nil { + if err := state.SetActor(actors.InitAddress, initact); err != nil { return nil, xerrors.Errorf("set init actor: %w", err) } + spact, err := SetupStoragePowerActor(bs) + if err != nil { + return nil, xerrors.Errorf("setup storage market actor: %w", err) + } + + if err := state.SetActor(actors.StoragePowerAddress, spact); err != nil { + return nil, xerrors.Errorf("set storage market actor: %w", err) + } + smact, err := SetupStorageMarketActor(bs) if err != nil { return nil, xerrors.Errorf("setup storage market actor: %w", err) @@ -104,7 +113,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types } err = state.SetActor(actors.NetworkAddress, &types.Actor{ - Code: actors.AccountActorCodeCid, + Code: actors.AccountCodeCid, Balance: netAmt, Head: emptyobject, }) @@ -113,7 +122,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types } err = state.SetActor(actors.BurntFundsAddress, &types.Actor{ - Code: actors.AccountActorCodeCid, + Code: actors.AccountCodeCid, Balance: types.NewInt(0), Head: emptyobject, }) @@ -123,7 +132,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types for a, v := range actmap { err = state.SetActor(a, &types.Actor{ - Code: actors.AccountActorCodeCid, + Code: actors.AccountCodeCid, Balance: v, Head: emptyobject, }) @@ -135,7 +144,7 @@ func MakeInitialStateTree(bs bstore.Blockstore, actmap map[address.Address]types return state, nil } -func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) { +func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) { cst := hamt.CSTFromBstore(bs) nd := hamt.NewNode(cst) emptyhamt, err := cst.Put(context.TODO(), nd) @@ -154,7 +163,41 @@ func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) { } return &types.Actor{ - Code: actors.StorageMarketActorCodeCid, + Code: actors.StoragePowerCodeCid, + Head: stcid, + Nonce: 0, + Balance: types.NewInt(0), + }, nil +} + +func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) { + cst := hamt.CSTFromBstore(bs) + nd := hamt.NewNode(cst) + emptyHAMT, err := cst.Put(context.TODO(), nd) + if err != nil { + return nil, err + } + + blks := amt.WrapBlockstore(bs) + + emptyAMT, err := amt.FromArray(blks, nil) + if err != nil { + return nil, xerrors.Errorf("amt build failed: %w", err) + } + + sms := &actors.StorageMarketState{ + Balances: emptyHAMT, + Deals: emptyAMT, + NextDealID: 0, + } + + stcid, err := cst.Put(context.TODO(), sms) + if err != nil { + return nil, err + } + + return &types.Actor{ + Code: actors.StorageMarketCodeCid, Head: stcid, Nonce: 0, Balance: types.NewInt(0), @@ -196,13 +239,13 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid params := mustEnc(&actors.CreateStorageMinerParams{ Owner: owner, Worker: worker, - SectorSize: types.NewInt(build.SectorSize), + SectorSize: build.SectorSizes[0], PeerID: pid, }) // TODO: hardcoding 7000000 here is a little fragile, it changes any // time anyone changes the initial account allocations - rval, err := doExecValue(ctx, vm, actors.StorageMarketAddress, owner, types.FromFil(6500), actors.SPAMethods.CreateStorageMiner, params) + rval, err := doExecValue(ctx, vm, actors.StoragePowerAddress, owner, types.FromFil(6500), actors.SPAMethods.CreateStorageMiner, params) if err != nil { return cid.Undef, xerrors.Errorf("failed to create genesis miner: %w", err) } @@ -216,7 +259,7 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid params = mustEnc(&actors.UpdateStorageParams{Delta: types.NewInt(5000)}) - _, err = doExec(ctx, vm, actors.StorageMarketAddress, maddr, actors.SPAMethods.UpdateStorage, params) + _, err = doExec(ctx, vm, actors.StoragePowerAddress, maddr, actors.SPAMethods.UpdateStorage, params) if err != nil { return cid.Undef, xerrors.Errorf("failed to update total storage: %w", err) } @@ -329,11 +372,11 @@ func MakeGenesisBlock(bs bstore.Blockstore, balances map[address.Address]types.B log.Infof("Empty Genesis root: %s", emptyroot) genesisticket := &types.Ticket{ - VRFProof: []byte("vrf proof"), + VRFProof: []byte("vrf proof0000000vrf proof0000000"), } b := &types.BlockHeader{ - Miner: actors.InitActorAddress, + Miner: actors.InitAddress, Tickets: []*types.Ticket{genesisticket}, ElectionProof: []byte("the Genesis block"), Parents: []cid.Cid{}, diff --git a/chain/state/statetree.go b/chain/state/statetree.go index 4f1cdb36d..55a812275 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -68,7 +68,7 @@ func (st *StateTree) SetActor(addr address.Address, act *types.Actor) error { } func (st *StateTree) lookupID(addr address.Address) (address.Address, error) { - act, err := st.GetActor(actors.InitActorAddress) + act, err := st.GetActor(actors.InitAddress) if err != nil { return address.Undef, xerrors.Errorf("getting init actor: %w", err) } @@ -143,7 +143,7 @@ func (st *StateTree) Snapshot() error { func (st *StateTree) RegisterNewAddress(addr address.Address, act *types.Actor) (address.Address, error) { var out address.Address - err := st.MutateActor(actors.InitActorAddress, func(initact *types.Actor) error { + err := st.MutateActor(actors.InitAddress, func(initact *types.Actor) error { var ias actors.InitActorState if err := st.Store.Get(context.TODO(), initact.Head, &ias); err != nil { return err diff --git a/chain/state/statetree_test.go b/chain/state/statetree_test.go index 79629daeb..360f4778e 100644 --- a/chain/state/statetree_test.go +++ b/chain/state/statetree_test.go @@ -27,7 +27,7 @@ func BenchmarkStateTreeSet(b *testing.B) { err = st.SetActor(a, &types.Actor{ Balance: types.NewInt(1258812523), Code: actors.StorageMinerCodeCid, - Head: actors.AccountActorCodeCid, + Head: actors.AccountCodeCid, Nonce: uint64(i), }) if err != nil { @@ -54,7 +54,7 @@ func BenchmarkStateTreeSetFlush(b *testing.B) { err = st.SetActor(a, &types.Actor{ Balance: types.NewInt(1258812523), Code: actors.StorageMinerCodeCid, - Head: actors.AccountActorCodeCid, + Head: actors.AccountCodeCid, Nonce: uint64(i), }) if err != nil { @@ -80,7 +80,7 @@ func BenchmarkStateTree10kGetActor(b *testing.B) { err = st.SetActor(a, &types.Actor{ Balance: types.NewInt(1258812523 + uint64(i)), Code: actors.StorageMinerCodeCid, - Head: actors.AccountActorCodeCid, + Head: actors.AccountCodeCid, Nonce: uint64(i), }) if err != nil { @@ -123,7 +123,7 @@ func TestSetCache(t *testing.T) { act := &types.Actor{ Balance: types.NewInt(0), Code: actors.StorageMinerCodeCid, - Head: actors.AccountActorCodeCid, + Head: actors.AccountCodeCid, Nonce: 0, } diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 5fac172f4..16aef7631 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -462,3 +462,17 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([] return out, nil } + +func (sm *StateManager) MarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) { + var state actors.StorageMarketState + if _, err := sm.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil { + return actors.StorageParticipantBalance{}, err + } + cst := hamt.CSTFromBstore(sm.ChainStore().Blockstore()) + b, _, err := actors.GetMarketBalances(ctx, cst, state.Balances, addr) + if err != nil { + return actors.StorageParticipantBalance{}, err + } + + return b[0], nil +} diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 025a8deb7..1dff70bbd 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -2,6 +2,7 @@ package stmgr import ( "context" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/address" @@ -9,6 +10,7 @@ import ( amt "github.com/filecoin-project/go-amt-ipld" cid "github.com/ipfs/go-cid" + hamt "github.com/ipfs/go-hamt-ipld" blockstore "github.com/ipfs/go-ipfs-blockstore" cbor "github.com/ipfs/go-ipld-cbor" "github.com/libp2p/go-libp2p-core/peer" @@ -16,7 +18,7 @@ import ( "golang.org/x/xerrors" ) -func GetMinerWorker(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) { +func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr address.Address) (address.Address, error) { recp, err := sm.CallRaw(ctx, &types.Message{ To: maddr, From: maddr, @@ -80,7 +82,7 @@ func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr add } ret, err := sm.Call(ctx, &types.Message{ From: maddr, - To: actors.StorageMarketAddress, + To: actors.StoragePowerAddress, Method: actors.SPAMethods.PowerLookup, Params: enc, }, ts) @@ -95,8 +97,8 @@ func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr add } ret, err := sm.Call(ctx, &types.Message{ - From: actors.StorageMarketAddress, - To: actors.StorageMarketAddress, + From: actors.StoragePowerAddress, + To: actors.StoragePowerAddress, Method: actors.SPAMethods.GetTotalStorage, }, ts) if err != nil { @@ -118,7 +120,7 @@ func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, mad Method: actors.MAMethods.GetPeerID, }, ts) if err != nil { - return "", xerrors.Errorf("callRaw failed: %w", err) + return "", xerrors.Errorf("call failed: %w", err) } if recp.ExitCode != 0 { @@ -128,6 +130,23 @@ func GetMinerPeerID(ctx context.Context, sm *StateManager, ts *types.TipSet, mad return peer.IDFromBytes(recp.Return) } +func GetMinerWorker(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (address.Address, error) { + recp, err := sm.Call(ctx, &types.Message{ + To: maddr, + From: maddr, + Method: actors.MAMethods.GetWorkerAddr, + }, ts) + if err != nil { + return address.Undef, xerrors.Errorf("call failed: %w", err) + } + + if recp.ExitCode != 0 { + return address.Undef, xerrors.Errorf("getting miner peer ID failed (exit code %d)", recp.ExitCode) + } + + return address.NewFromBytes(recp.Return) +} + func GetMinerProvingPeriodEnd(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) { var mas actors.StorageMinerActorState _, err := sm.LoadActorState(ctx, maddr, &mas, ts) @@ -158,6 +177,22 @@ func GetMinerSectorSet(ctx context.Context, sm *StateManager, ts *types.TipSet, return LoadSectorsFromSet(ctx, sm.ChainStore().Blockstore(), mas.Sectors) } +func GetMinerSectorSize(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (uint64, error) { + var mas actors.StorageMinerActorState + _, err := sm.LoadActorState(ctx, maddr, &mas, ts) + if err != nil { + return 0, xerrors.Errorf("failed to load miner actor state: %w", err) + } + + cst := hamt.CSTFromBstore(sm.cs.Blockstore()) + var minfo actors.MinerInfo + if err := cst.Get(ctx, mas.Info, &minfo); err != nil { + return 0, xerrors.Errorf("failed to read miner info: %w", err) + } + + return minfo.SectorSize, nil +} + func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid) ([]*api.SectorInfo, error) { blks := amt.WrapBlockstore(bs) a, err := amt.LoadAMT(blks, ssc) diff --git a/chain/store/weight.go b/chain/store/weight.go index cf992554a..7c1f80ceb 100644 --- a/chain/store/weight.go +++ b/chain/store/weight.go @@ -23,8 +23,8 @@ func (cs *ChainStore) Weight(ctx context.Context, ts *types.TipSet) (types.BigIn // >>> wFunction(totalPowerAtTipset(ts)) * 2^8 <<< + (wFunction(totalPowerAtTipset(ts)) * len(ts.blocks) * wRatio_num * 2^8) / (e * wRatio_den) ret, err := cs.call(ctx, &types.Message{ - From: actors.StorageMarketAddress, - To: actors.StorageMarketAddress, + From: actors.StoragePowerAddress, + To: actors.StoragePowerAddress, Method: actors.SPAMethods.GetTotalStorage, }, ts) if err != nil { diff --git a/chain/sync.go b/chain/sync.go index def95c25e..dac2a79e5 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -398,7 +398,7 @@ func (syncer *Syncer) minerIsValid(ctx context.Context, maddr address.Address, b } ret, err := syncer.sm.Call(ctx, &types.Message{ - To: actors.StorageMarketAddress, + To: actors.StoragePowerAddress, From: maddr, Method: actors.SPAMethods.IsMiner, Params: enc, @@ -482,9 +482,9 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err return xerrors.Errorf("minerIsValid failed: %w", err) } - waddr, err := stmgr.GetMinerWorker(ctx, syncer.sm, stateroot, h.Miner) + waddr, err := stmgr.GetMinerWorkerRaw(ctx, syncer.sm, stateroot, h.Miner) if err != nil { - return xerrors.Errorf("GetMinerWorker failed: %w", err) + return xerrors.Errorf("GetMinerWorkerRaw failed: %w", err) } if err := h.CheckBlockSignature(ctx, waddr); err != nil { @@ -495,7 +495,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err return xerrors.Errorf("validating block tickets failed: %w", err) } - rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), h.Tickets, build.RandomnessLookback) + rand, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), h.Tickets, build.EcRandomnessLookback) if err != nil { return xerrors.Errorf("failed to get randomness for verifying election proof: %w", err) } diff --git a/chain/types/ask.go b/chain/types/ask.go index da0684f86..dd768feb3 100644 --- a/chain/types/ask.go +++ b/chain/types/ask.go @@ -16,10 +16,12 @@ type SignedStorageAsk struct { } type StorageAsk struct { - Price BigInt + // Price per GiB / Epoch + Price BigInt + MinPieceSize uint64 Miner address.Address - Timestamp int64 - Expiry int64 + Timestamp uint64 + Expiry uint64 SeqNo uint64 } diff --git a/chain/types/blockheader.go b/chain/types/blockheader.go index a82bf37a2..1ede605d4 100644 --- a/chain/types/blockheader.go +++ b/chain/types/blockheader.go @@ -3,15 +3,16 @@ package types import ( "bytes" "context" - "crypto/sha256" "math/big" block "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" + "github.com/minio/sha256-simd" "github.com/multiformats/go-multihash" "go.opencensus.io/trace" xerrors "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/address" ) @@ -159,23 +160,30 @@ func CidArrsEqual(a, b []cid.Cid) bool { return true } +var blocksPerEpoch = NewInt(build.BlocksPerEpoch) + func PowerCmp(eproof ElectionProof, mpow, totpow BigInt) bool { /* Need to check that - h(vrfout) / 2^256 < minerPower / totalPower + h(vrfout) / max(h) < e * minerPower / totalPower + max(h) == 2^256-1 + which in terms of integer math means: + h(vrfout) * totalPower < e * minerPower * (2^256-1) */ h := sha256.Sum256(eproof) - // 2^256 - rden := BigInt{big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil)} + lhs := BigFromBytes(h[:]).Int + lhs = lhs.Mul(lhs, totpow.Int) - top := BigMul(rden, mpow) - out := BigDiv(top, totpow) + // rhs = minerPower * 2^256 - minerPower + // rhs = minerPower << 256 - minerPower + rhs := new(big.Int).Lsh(mpow.Int, 256) + rhs = rhs.Mul(rhs, blocksPerEpoch.Int) + rhs = rhs.Sub(rhs, mpow.Int) - hp := BigFromBytes(h[:]) - return hp.LessThan(out) + return lhs.Cmp(rhs) == -1 } func (t *Ticket) Equals(ot *Ticket) bool { diff --git a/chain/types/blockheader_test.go b/chain/types/blockheader_test.go index d32e8bdce..09ca061b9 100644 --- a/chain/types/blockheader_test.go +++ b/chain/types/blockheader_test.go @@ -27,7 +27,7 @@ func testBlockHeader(t testing.TB) *BlockHeader { ElectionProof: []byte("cats won the election"), Tickets: []*Ticket{ &Ticket{ - VRFProof: []byte("vrf proof"), + VRFProof: []byte("vrf proof0000000vrf proof0000000"), }, }, Parents: []cid.Cid{c, c}, diff --git a/chain/types/cbor_gen.go b/chain/types/cbor_gen.go index bad374f1b..9cf6ec913 100644 --- a/chain/types/cbor_gen.go +++ b/chain/types/cbor_gen.go @@ -1272,3 +1272,201 @@ func (t *BlockMsg) UnmarshalCBOR(r io.Reader) error { return nil } + +func (t *SignedStorageAsk) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{130}); err != nil { + return err + } + + // t.t.Ask (types.StorageAsk) + if err := t.Ask.MarshalCBOR(w); err != nil { + return err + } + + // t.t.Signature (types.Signature) + if err := t.Signature.MarshalCBOR(w); err != nil { + return err + } + return nil +} + +func (t *SignedStorageAsk) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + 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.t.Ask (types.StorageAsk) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Ask = new(StorageAsk) + if err := t.Ask.UnmarshalCBOR(br); err != nil { + return err + } + } + + } + // t.t.Signature (types.Signature) + + { + + pb, err := br.PeekByte() + if err != nil { + return err + } + if pb == cbg.CborNull[0] { + var nbuf [1]byte + if _, err := br.Read(nbuf[:]); err != nil { + return err + } + } else { + t.Signature = new(Signature) + if err := t.Signature.UnmarshalCBOR(br); err != nil { + return err + } + } + + } + return nil +} + +func (t *StorageAsk) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + if _, err := w.Write([]byte{134}); err != nil { + return err + } + + // t.t.Price (types.BigInt) + if err := t.Price.MarshalCBOR(w); err != nil { + return err + } + + // t.t.MinPieceSize (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.MinPieceSize)); err != nil { + return err + } + + // t.t.Miner (address.Address) + if err := t.Miner.MarshalCBOR(w); err != nil { + return err + } + + // t.t.Timestamp (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Timestamp)); err != nil { + return err + } + + // t.t.Expiry (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.Expiry)); err != nil { + return err + } + + // t.t.SeqNo (uint64) + if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, t.SeqNo)); err != nil { + return err + } + return nil +} + +func (t *StorageAsk) UnmarshalCBOR(r io.Reader) error { + br := cbg.GetPeeker(r) + + maj, extra, err := cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajArray { + return fmt.Errorf("cbor input should be of type array") + } + + if extra != 6 { + return fmt.Errorf("cbor input had wrong number of fields") + } + + // t.t.Price (types.BigInt) + + { + + if err := t.Price.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.MinPieceSize (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.MinPieceSize = extra + // t.t.Miner (address.Address) + + { + + if err := t.Miner.UnmarshalCBOR(br); err != nil { + return err + } + + } + // t.t.Timestamp (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Timestamp = extra + // t.t.Expiry (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.Expiry = extra + // t.t.SeqNo (uint64) + + maj, extra, err = cbg.CborReadHeader(br) + if err != nil { + return err + } + if maj != cbg.MajUnsignedInt { + return fmt.Errorf("wrong type for uint64 field") + } + t.SeqNo = extra + return nil +} diff --git a/chain/vm/invoker.go b/chain/vm/invoker.go index 713f64d39..decc590b7 100644 --- a/chain/vm/invoker.go +++ b/chain/vm/invoker.go @@ -29,11 +29,12 @@ func newInvoker() *invoker { } // add builtInCode using: register(cid, singleton) - inv.register(actors.InitActorCodeCid, actors.InitActor{}, actors.InitActorState{}) - inv.register(actors.StorageMarketActorCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{}) + inv.register(actors.InitCodeCid, actors.InitActor{}, actors.InitActorState{}) + inv.register(actors.StoragePowerCodeCid, actors.StoragePowerActor{}, actors.StoragePowerState{}) + inv.register(actors.StorageMarketCodeCid, actors.StorageMarketActor{}, actors.StorageMarketState{}) inv.register(actors.StorageMinerCodeCid, actors.StorageMinerActor{}, actors.StorageMinerActorState{}) - inv.register(actors.MultisigActorCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{}) - inv.register(actors.PaymentChannelActorCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{}) + inv.register(actors.MultisigCodeCid, actors.MultiSigActor{}, actors.MultiSigActorState{}) + inv.register(actors.PaymentChannelCodeCid, actors.PaymentChannelActor{}, actors.PaymentChannelActorState{}) return inv } diff --git a/chain/vm/mkactor.go b/chain/vm/mkactor.go index 6b0fc4ca4..1e1885825 100644 --- a/chain/vm/mkactor.go +++ b/chain/vm/mkactor.go @@ -66,7 +66,7 @@ func NewBLSAccountActor(st *state.StateTree, addr address.Address) (*types.Actor } nact := &types.Actor{ - Code: actors.AccountActorCodeCid, + Code: actors.AccountCodeCid, Balance: types.NewInt(0), Head: c, } @@ -76,7 +76,7 @@ func NewBLSAccountActor(st *state.StateTree, addr address.Address) (*types.Actor func NewSecp256k1AccountActor(st *state.StateTree, addr address.Address) (*types.Actor, aerrors.ActorError) { nact := &types.Actor{ - Code: actors.AccountActorCodeCid, + Code: actors.AccountCodeCid, Balance: types.NewInt(0), Head: EmptyObjectCid, } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index be9bf6eb0..38831043b 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -176,7 +176,7 @@ func (vmc *VMContext) ChargeGas(amount uint64) aerrors.ActorError { } func (vmc *VMContext) StateTree() (types.StateTree, aerrors.ActorError) { - if vmc.msg.To != actors.InitActorAddress { + if vmc.msg.To != actors.InitAddress { return nil, aerrors.Escalate(fmt.Errorf("only init actor can access state tree directly"), "invalid use of StateTree") } @@ -215,7 +215,7 @@ func ResolveToKeyAddr(state types.StateTree, cst *hamt.CborIpldStore, addr addre return address.Undef, aerrors.Newf(1, "failed to find actor: %s", addr) } - if act.Code != actors.AccountActorCodeCid { + if act.Code != actors.AccountCodeCid { return address.Undef, aerrors.New(1, "address was not for an account actor") } @@ -488,6 +488,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, msg *types.Message) (*ApplyRet, return nil, xerrors.Errorf("getting block miner actor (%s) failed: %w", vm.blockMiner, err) } + // TODO: support multiple blocks in a tipset + // TODO: actually wire this up (miner is undef for now) gasReward := types.BigMul(msg.GasPrice, gasUsed) if err := Transfer(gasHolder, miner, gasReward); err != nil { return nil, xerrors.Errorf("failed to give miner gas reward: %w", err) @@ -630,6 +632,7 @@ func depositFunds(act *types.Actor, amt types.BigInt) { } var miningRewardTotal = types.FromFil(build.MiningRewardTotal) +var blocksPerEpoch = types.NewInt(build.BlocksPerEpoch) // MiningReward returns correct mining reward // coffer is amount of FIL in NetworkAddress @@ -637,5 +640,6 @@ func MiningReward(remainingReward types.BigInt) types.BigInt { ci := big.NewInt(0).Set(remainingReward.Int) res := ci.Mul(ci, build.InitialReward) res = res.Div(res, miningRewardTotal.Int) + res = res.Div(res, blocksPerEpoch.Int) return types.BigInt{res} } diff --git a/cli/client.go b/cli/client.go index e9e5814c7..7f9771a3d 100644 --- a/cli/client.go +++ b/cli/client.go @@ -101,8 +101,7 @@ var clientDealCmd = &cli.Command{ return err } - // TODO: parse bigint - price, err := strconv.ParseInt(cctx.Args().Get(2), 10, 32) + price, err := types.ParseFIL(cctx.Args().Get(2)) if err != nil { return err } @@ -112,7 +111,7 @@ var clientDealCmd = &cli.Command{ return err } - proposal, err := api.ClientStartDeal(ctx, data, miner, types.NewInt(uint64(price)), uint64(dur)) + proposal, err := api.ClientStartDeal(ctx, data, miner, types.BigInt(price), uint64(dur)) if err != nil { return err } @@ -164,7 +163,7 @@ var clientFindCmd = &cli.Command{ fmt.Printf("ERR %s@%s: %s\n", offer.Miner, offer.MinerPeerID, offer.Err) continue } - fmt.Printf("RETRIEVAL %s@%s-%sfil-%db\n", offer.Miner, offer.MinerPeerID, offer.MinPrice, offer.Size) + fmt.Printf("RETRIEVAL %s@%s-%sfil-%db\n", offer.Miner, offer.MinerPeerID, types.FIL(offer.MinPrice), offer.Size) } return nil @@ -308,19 +307,20 @@ var clientQueryAskCmd = &cli.Command{ } fmt.Printf("Ask: %s\n", maddr) - fmt.Printf("Price per Byte: %s\n", ask.Ask.Price) + fmt.Printf("Price per Byte: %s\n", types.FIL(ask.Ask.Price)) size := cctx.Int64("size") if size == 0 { return nil } - fmt.Printf("Price per Block: %s\n", types.BigMul(ask.Ask.Price, types.NewInt(uint64(size)))) + perEpoch := types.BigDiv(types.BigMul(ask.Ask.Price, types.NewInt(uint64(size))), types.NewInt(1<<30)) + fmt.Printf("Price per Block: %s\n", types.FIL(perEpoch)) duration := cctx.Int64("duration") if duration == 0 { return nil } - fmt.Printf("Total Price: %s\n", types.BigMul(types.BigMul(ask.Ask.Price, types.NewInt(uint64(size))), types.NewInt(uint64(duration)))) + fmt.Printf("Total Price: %s\n", types.FIL(types.BigMul(perEpoch, types.NewInt(uint64(duration))))) return nil }, diff --git a/cli/createminer.go b/cli/createminer.go index 551528613..4247fe48e 100644 --- a/cli/createminer.go +++ b/cli/createminer.go @@ -53,7 +53,7 @@ var createMinerCmd = &cli.Command{ createMinerArgs := actors.CreateStorageMinerParams{ Worker: worker, Owner: owner, - SectorSize: types.NewInt(ssize), + SectorSize: ssize, PeerID: pid, } @@ -69,7 +69,7 @@ var createMinerCmd = &cli.Command{ } msg := &types.Message{ - To: actors.StorageMarketAddress, + To: actors.StoragePowerAddress, From: addr, Method: actors.SPAMethods.CreateStorageMiner, Params: params, diff --git a/cli/state.go b/cli/state.go index b40611c54..6d831b249 100644 --- a/cli/state.go +++ b/cli/state.go @@ -78,7 +78,7 @@ var stateSectorsCmd = &cli.Command{ return err } - sectors, err := api.StateMinerSectors(ctx, maddr) + sectors, err := api.StateMinerSectors(ctx, maddr, nil) if err != nil { return err } diff --git a/cli/wallet.go b/cli/wallet.go index cb0cbbdd3..7ee4eab16 100644 --- a/cli/wallet.go +++ b/cli/wallet.go @@ -231,7 +231,7 @@ var walletImport = &cli.Command{ return err } - fmt.Printf("imported key %s successfully!", addr) + fmt.Printf("imported key %s successfully!\n", addr) return nil }, } diff --git a/cmd/lotus-fountain/main.go b/cmd/lotus-fountain/main.go index 1a7a87ce4..d6c6f9107 100644 --- a/cmd/lotus-fountain/main.go +++ b/cmd/lotus-fountain/main.go @@ -5,14 +5,17 @@ import ( "fmt" "net/http" "os" + "time" rice "github.com/GeertJohan/go.rice" logging "github.com/ipfs/go-log" + peer "github.com/libp2p/go-libp2p-peer" "golang.org/x/xerrors" "gopkg.in/urfave/cli.v2" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/chain/types" lcli "github.com/filecoin-project/lotus/cli" @@ -88,6 +91,22 @@ var runCmd = &cli.Command{ ctx: ctx, api: nodeApi, from: from, + limiter: NewLimiter(LimiterConfig{ + TotalRate: time.Second, + TotalBurst: 20, + IPRate: time.Minute, + IPBurst: 5, + WalletRate: 15 * time.Minute, + WalletBurst: 1, + }), + colLimiter: NewLimiter(LimiterConfig{ + TotalRate: time.Second, + TotalBurst: 20, + IPRate: 10 * time.Minute, + IPBurst: 1, + WalletRate: 1 * time.Hour, + WalletBurst: 1, + }), } http.Handle("/", http.FileServer(rice.MustFindBox("site").HTTPBox())) @@ -110,9 +129,25 @@ type handler struct { api api.FullNode from address.Address + + limiter *Limiter + colLimiter *Limiter } func (h *handler) send(w http.ResponseWriter, r *http.Request) { + // General limiter to allow throttling all messages that can make it into the mpool + if !h.limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) + return + } + + // Limit based on IP + limiter := h.limiter.GetIPLimiter(r.RemoteAddr) + if !limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) + return + } + to, err := address.NewFromString(r.FormValue("address")) if err != nil { w.WriteHeader(400) @@ -120,6 +155,13 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) { return } + // Limit based on wallet address + limiter = h.limiter.GetWalletLimiter(to.String()) + if !limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) + return + } + smsg, err := h.api.MpoolPushMessage(h.ctx, &types.Message{ Value: sendPerRequest, From: h.from, @@ -138,6 +180,132 @@ func (h *handler) send(w http.ResponseWriter, r *http.Request) { } func (h *handler) mkminer(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(400) - // todo + // General limiter owner allow throttling all messages that can make it into the mpool + if !h.colLimiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) + return + } + + // Limit based on IP + limiter := h.colLimiter.GetIPLimiter(r.RemoteAddr) + if !limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) + return + } + + owner, err := address.NewFromString(r.FormValue("address")) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + if owner.Protocol() != address.BLS { + w.WriteHeader(400) + w.Write([]byte("Miner address must use BLS")) + return + } + + log.Infof("mkactor on %s", owner) + + // Limit based on wallet address + limiter = h.colLimiter.GetWalletLimiter(owner.String()) + if !limiter.Allow() { + http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests) + return + } + collateral, err := h.api.StatePledgeCollateral(r.Context(), nil) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + smsg, err := h.api.MpoolPushMessage(h.ctx, &types.Message{ + Value: sendPerRequest, + From: h.from, + To: owner, + + GasPrice: types.NewInt(0), + GasLimit: types.NewInt(1000), + }) + if err != nil { + w.WriteHeader(400) + w.Write([]byte("pushfunds: " + err.Error())) + return + } + log.Infof("push funds to %s: %s", owner, smsg.Cid()) + + mw, err := h.api.StateWaitMsg(r.Context(), smsg.Cid()) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + if mw.Receipt.ExitCode != 0 { + w.WriteHeader(400) + w.Write([]byte(xerrors.Errorf("create storage miner failed: exit code %d", mw.Receipt.ExitCode).Error())) + return + } + + log.Infof("sendto %s ok", owner) + + params, err := actors.SerializeParams(&actors.CreateStorageMinerParams{ + Owner: owner, + Worker: owner, + SectorSize: 1 << 30, // build.SectorSizes[0], // TODO: dropdown allowing selection (1GiB for now) + PeerID: peer.ID("SETME"), + }) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + createStorageMinerMsg := &types.Message{ + To: actors.StoragePowerAddress, + From: h.from, + Value: collateral, + + Method: actors.SPAMethods.CreateStorageMiner, + Params: params, + + GasLimit: types.NewInt(10000000), + GasPrice: types.NewInt(0), + } + + signed, err := h.api.MpoolPushMessage(r.Context(), createStorageMinerMsg) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + log.Infof("smc %s", owner) + + mw, err = h.api.StateWaitMsg(r.Context(), signed.Cid()) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + if mw.Receipt.ExitCode != 0 { + w.WriteHeader(400) + w.Write([]byte(xerrors.Errorf("create storage miner failed: exit code %d", mw.Receipt.ExitCode).Error())) + return + } + + addr, err := address.NewFromBytes(mw.Receipt.Return) + if err != nil { + w.WriteHeader(400) + w.Write([]byte(err.Error())) + return + } + + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(200) + fmt.Fprintf(w, "New storage miners address is: %s\n", addr) + fmt.Fprintf(w, "Run lotus-storage-miner init --actor=%s --owner=%s", addr, owner) } diff --git a/cmd/lotus-fountain/rate_limiter.go b/cmd/lotus-fountain/rate_limiter.go new file mode 100644 index 000000000..eb7215780 --- /dev/null +++ b/cmd/lotus-fountain/rate_limiter.go @@ -0,0 +1,94 @@ +package main + +import ( + "sync" + "time" + + "golang.org/x/time/rate" +) + +type Limiter struct { + control *rate.Limiter + + ips map[string]*rate.Limiter + wallets map[string]*rate.Limiter + mu *sync.RWMutex + + config LimiterConfig +} + +type LimiterConfig struct { + TotalRate time.Duration + TotalBurst int + + IPRate time.Duration + IPBurst int + + WalletRate time.Duration + WalletBurst int +} + +func NewLimiter(c LimiterConfig) *Limiter { + return &Limiter{ + control: rate.NewLimiter(rate.Every(c.TotalRate), c.TotalBurst), + mu: &sync.RWMutex{}, + ips: make(map[string]*rate.Limiter), + wallets: make(map[string]*rate.Limiter), + + config: c, + } +} + +func (i *Limiter) Allow() bool { + return i.control.Allow() +} + +func (i *Limiter) AddIPLimiter(ip string) *rate.Limiter { + i.mu.Lock() + defer i.mu.Unlock() + + limiter := rate.NewLimiter(rate.Every(i.config.IPRate), i.config.IPBurst) + + i.ips[ip] = limiter + + return limiter +} + +func (i *Limiter) GetIPLimiter(ip string) *rate.Limiter { + i.mu.Lock() + limiter, exists := i.ips[ip] + + if !exists { + i.mu.Unlock() + return i.AddIPLimiter(ip) + } + + i.mu.Unlock() + + return limiter +} + +func (i *Limiter) AddWalletLimiter(addr string) *rate.Limiter { + i.mu.Lock() + defer i.mu.Unlock() + + limiter := rate.NewLimiter(rate.Every(i.config.WalletRate), i.config.WalletBurst) + + i.wallets[addr] = limiter + + return limiter +} + +func (i *Limiter) GetWalletLimiter(wallet string) *rate.Limiter { + i.mu.Lock() + limiter, exists := i.wallets[wallet] + + if !exists { + i.mu.Unlock() + return i.AddWalletLimiter(wallet) + } + + i.mu.Unlock() + + return limiter +} diff --git a/cmd/lotus-fountain/rate_limiter_test.go b/cmd/lotus-fountain/rate_limiter_test.go new file mode 100644 index 000000000..03590de50 --- /dev/null +++ b/cmd/lotus-fountain/rate_limiter_test.go @@ -0,0 +1,38 @@ +package main + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestRateLimit(t *testing.T) { + limiter := NewLimiter(LimiterConfig{ + TotalRate: time.Second, + TotalBurst: 20, + IPRate: time.Second, + IPBurst: 1, + WalletRate: time.Second, + WalletBurst: 1, + }) + + for i := 0; i < 20; i++ { + assert.True(t, limiter.Allow()) + } + + assert.False(t, limiter.Allow()) + + time.Sleep(time.Second) + assert.True(t, limiter.Allow()) + + assert.True(t, limiter.GetIPLimiter("127.0.0.1").Allow()) + assert.False(t, limiter.GetIPLimiter("127.0.0.1").Allow()) + time.Sleep(time.Second) + assert.True(t, limiter.GetIPLimiter("127.0.0.1").Allow()) + + assert.True(t, limiter.GetWalletLimiter("abc123").Allow()) + assert.False(t, limiter.GetWalletLimiter("abc123").Allow()) + time.Sleep(time.Second) + assert.True(t, limiter.GetWalletLimiter("abc123").Allow()) +} diff --git a/cmd/lotus-fountain/site/funds.html b/cmd/lotus-fountain/site/funds.html new file mode 100644 index 000000000..cd26032f3 --- /dev/null +++ b/cmd/lotus-fountain/site/funds.html @@ -0,0 +1,29 @@ + + + + Sending Funds - Lotus Fountain + + + +
+
+
+ [SENDING FUNDS] +
+
+
+ Enter destination address: + + +
+
+
+ +
+ + diff --git a/cmd/lotus-fountain/site/index.html b/cmd/lotus-fountain/site/index.html index 0a3d3577b..85226e4c0 100644 --- a/cmd/lotus-fountain/site/index.html +++ b/cmd/lotus-fountain/site/index.html @@ -2,19 +2,26 @@ Lotus Fountain - + -
- Enter destination address: - - -
+
+
+
+ [LOTUS DEVNET FAUCET] +
+ + +
+ +
diff --git a/cmd/lotus-fountain/site/main.css b/cmd/lotus-fountain/site/main.css new file mode 100644 index 000000000..efcd5dc26 --- /dev/null +++ b/cmd/lotus-fountain/site/main.css @@ -0,0 +1,56 @@ +body { + font-family: 'monospace'; + background: #1f1f1f; + color: #f0f0f0; + padding: 0; + margin: 0; +} + +.Index { + width: 100vw; + height: 100vh; + background: #1a1a1a; + color: #f0f0f0; + font-family: monospace; + + display: grid; + grid-template-columns: auto 40vw auto; + grid-template-rows: auto auto auto 3em; + grid-template-areas: + ". . ." + ". main ." + ". . ." + "footer footer footer"; +} +.Index-footer { + background: #2a2a2a; + grid-area: footer; +} + +.Index-footer > div { + padding-left: 0.7em; + padding-top: 0.7em; +} + +.Index-nodes { + grid-area: main; + background: #2a2a2a; +} + +.Index-node { + margin: 5px; + padding: 15px; + background: #1f1f1f; +} + +a:link { + color: #50f020; +} + +a:visited { + color: #50f020; +} + +a:hover { + color: #30a00a; +} diff --git a/cmd/lotus-fountain/site/miner.html b/cmd/lotus-fountain/site/miner.html new file mode 100644 index 000000000..8aec74eac --- /dev/null +++ b/cmd/lotus-fountain/site/miner.html @@ -0,0 +1,43 @@ + + + + Creating Storage Miner - Lotus Fountain + + + +
+
+
+ [CREATING STORAGE MINER] +
+
+
+ Enter destination address: + + +
+
+ +
+ When creating storage miner, DO NOT REFRESH THE PAGE, wait for it to load. This can take more than 5min. +
+
+ +
+ + + \ No newline at end of file diff --git a/cmd/lotus-storage-miner/init.go b/cmd/lotus-storage-miner/init.go index a0085fe81..54d488a1b 100644 --- a/cmd/lotus-storage-miner/init.go +++ b/cmd/lotus-storage-miner/init.go @@ -49,6 +49,11 @@ var initCmd = &cli.Command{ Aliases: []string{"o"}, Usage: "owner key to use", }, + &cli.Uint64Flag{ + Name: "sector-size", + Usage: "specify sector size to use", + Value: build.SectorSizes[0], + }, }, Action: func(cctx *cli.Context) error { log.Info("Initializing lotus storage miner") @@ -276,6 +281,8 @@ func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID, c return address.Undef, err } + ssize := cctx.Uint64("sector-size") + worker := owner if cctx.String("worker") != "" { worker, err = address.NewFromString(cctx.String("worker")) @@ -295,7 +302,7 @@ func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID, c params, err := actors.SerializeParams(&actors.CreateStorageMinerParams{ Owner: owner, Worker: worker, - SectorSize: types.NewInt(build.SectorSize), + SectorSize: ssize, PeerID: peerid, }) if err != nil { @@ -303,7 +310,7 @@ func createStorageMiner(ctx context.Context, api api.FullNode, peerid peer.ID, c } createStorageMinerMsg := &types.Message{ - To: actors.StorageMarketAddress, + To: actors.StoragePowerAddress, From: owner, Value: collateral, diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index deede68ad..149e8195d 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -36,7 +36,6 @@ var sectorsCmd = &cli.Command{ Subcommands: []*cli.Command{ sectorsStatusCmd, sectorsStagedListCmd, - sectorsStagedSealCmd, sectorsRefsCmd, }, } @@ -71,7 +70,8 @@ var sectorsStatusCmd = &cli.Command{ fmt.Printf("SealErrorMsg:\t%q\n", status.SealErrorMsg) fmt.Printf("CommD:\t\t%x\n", status.CommD) fmt.Printf("CommR:\t\t%x\n", status.CommR) - fmt.Printf("CommR*:\t\t%x\n", status.CommRStar) + fmt.Printf("Ticket:\t\t%x\n", status.Ticket.TicketBytes) + fmt.Printf("TicketH:\t\t%d\n", status.Ticket.BlockHeight) fmt.Printf("Proof:\t\t%x\n", status.Proof) fmt.Printf("Pieces:\t\t%v\n", status.Pieces) return nil @@ -101,21 +101,6 @@ var sectorsStagedListCmd = &cli.Command{ }, } -var sectorsStagedSealCmd = &cli.Command{ - Name: "seal-staged", // TODO: nest this under a 'staged' subcommand? idk - Usage: "Seal staged sectors", - Action: func(cctx *cli.Context) error { - nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) - if err != nil { - return err - } - defer closer() - ctx := lcli.ReqContext(cctx) - - return nodeApi.SectorsStagedSeal(ctx) - }, -} - var sectorsRefsCmd = &cli.Command{ Name: "refs", Usage: "List References to sectors", diff --git a/cmd/lotus-townhall/main.go b/cmd/lotus-townhall/main.go index 9be633147..e45b8e8e4 100644 --- a/cmd/lotus-townhall/main.go +++ b/cmd/lotus-townhall/main.go @@ -1,9 +1,14 @@ package main import ( + "bytes" "context" "encoding/json" "fmt" + "github.com/filecoin-project/lotus/build" + "github.com/ipfs/go-car" + "github.com/ipfs/go-datastore" + blockstore "github.com/ipfs/go-ipfs-blockstore" "net/http" "strings" @@ -14,11 +19,26 @@ import ( pnet "github.com/libp2p/go-libp2p-pnet" pubsub "github.com/libp2p/go-libp2p-pubsub" - "github.com/filecoin-project/lotus/lib/addrutil" "github.com/filecoin-project/lotus/node/modules/lp2p" ) -const topic = "/fil/headnotifs/bafy2bzacea77zxnepp7wuqqgpj7xcw2ywwmmcmtrbjghhv4g2dildogpv6roi" +var topic = "/fil/headnotifs/" + +func init() { + genBytes := build.MaybeGenesis() + bs := blockstore.NewBlockstore(datastore.NewMapDatastore()) + + c, err := car.LoadCar(bs, bytes.NewReader(genBytes)) + if err != nil { + panic(err) + } + if len(c.Roots) != 1 { + panic("expected genesis file to have one root") + } + + fmt.Printf("Genesis CID: %s\n", c.Roots[0]) + topic = topic + c.Roots[0].String() +} var upgrader = websocket.Upgrader{ WriteBufferSize: 1024, @@ -48,9 +68,7 @@ func main() { panic(err) } - pi, err := addrutil.ParseAddresses(ctx, []string{ - "/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWGU8C1mFsEtz4bXmHUH3kQTnQnxVy8cigwGV94qCpYJw7", - }) + pi, err := build.BuiltinBootstrap() if err != nil { panic(err) } diff --git a/extern/go-sectorbuilder b/extern/go-sectorbuilder index 32e85ba52..692725ff2 160000 --- a/extern/go-sectorbuilder +++ b/extern/go-sectorbuilder @@ -1 +1 @@ -Subproject commit 32e85ba52d9ccf3fc5715bcf53265b042020ee82 +Subproject commit 692725ff21919ce9c9df9ea87621b0c1e6a9746c diff --git a/gen/main.go b/gen/main.go index 7dfcb0dbb..127336a0b 100644 --- a/gen/main.go +++ b/gen/main.go @@ -4,9 +4,11 @@ import ( "fmt" "os" - "github.com/filecoin-project/lotus/chain/actors" - "github.com/filecoin-project/lotus/chain/types" gen "github.com/whyrusleeping/cbor-gen" + + "github.com/filecoin-project/lotus/chain/actors" + "github.com/filecoin-project/lotus/chain/deals" + "github.com/filecoin-project/lotus/chain/types" ) func main() { @@ -22,6 +24,8 @@ func main() { types.Actor{}, types.MessageReceipt{}, types.BlockMsg{}, + types.SignedStorageAsk{}, + types.StorageAsk{}, ) if err != nil { fmt.Println(err) @@ -46,11 +50,9 @@ func main() { actors.AccountActorState{}, actors.StorageMinerActorState{}, actors.StorageMinerConstructorParams{}, - actors.CommitSectorParams{}, + actors.OnChainSealVerifyInfo{}, actors.MinerInfo{}, actors.SubmitPoStParams{}, - actors.PieceInclVoucherData{}, - actors.InclusionProof{}, actors.PaymentVerifyParams{}, actors.UpdatePeerIDParams{}, actors.MultiSigActorState{}, @@ -75,6 +77,31 @@ func main() { actors.ArbitrateConsensusFaultParams{}, actors.PledgeCollateralParams{}, actors.MinerSlashConsensusFault{}, + actors.StorageParticipantBalance{}, + actors.StorageMarketState{}, + actors.WithdrawBalanceParams{}, + actors.StorageDealProposal{}, + actors.StorageDeal{}, + actors.PublishStorageDealsParams{}, + actors.PublishStorageDealResponse{}, + actors.ActivateStorageDealsParams{}, + actors.ProcessStorageDealsPaymentParams{}, + actors.OnChainDeal{}, + ) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + err = gen.WriteTupleEncodersToFile("./chain/deals/cbor_gen.go", "deals", + deals.AskRequest{}, + deals.AskResponse{}, + deals.Proposal{}, + deals.Response{}, + deals.SignedResponse{}, + deals.ClientDealProposal{}, + deals.ClientDeal{}, + deals.MinerDeal{}, ) if err != nil { fmt.Println(err) diff --git a/go.mod b/go.mod index 48098edda..b8eec445f 100644 --- a/go.mod +++ b/go.mod @@ -61,6 +61,7 @@ require ( github.com/mattn/go-runewidth v0.0.4 // indirect github.com/miekg/dns v1.1.16 // indirect github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 + github.com/minio/sha256-simd v0.1.0 github.com/mitchellh/go-homedir v1.1.0 github.com/multiformats/go-base32 v0.0.3 github.com/multiformats/go-multiaddr v0.0.4 @@ -79,10 +80,12 @@ require ( go.uber.org/dig v1.7.0 // indirect go.uber.org/fx v1.9.0 go.uber.org/goleak v0.10.0 // indirect + go.uber.org/multierr v1.1.0 go.uber.org/zap v1.10.0 go4.org v0.0.0-20190313082347-94abd6928b1d // indirect golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 // indirect golang.org/x/sys v0.0.0-20190904154756-749cb33beabd // indirect + golang.org/x/time v0.0.0-20181108054448-85acf8d2951c golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 google.golang.org/api v0.9.0 // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 diff --git a/go.sum b/go.sum index be3b0270d..3d9bc15a9 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,10 @@ github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= +github.com/OpenPeeDeeP/depguard v1.0.0/go.mod h1:7/4sitnI9YlQgTLLk734QlzXT8DuHVnAyztLplQjk+o= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/Stebalien/go-bitfield v0.0.1 h1:X3kbSSPUaJK60wV2hjOPZwmpljr6VGCqdq4cBLhbQBo= @@ -28,6 +30,8 @@ github.com/apache/thrift v0.12.0 h1:pODnxUFNcjP9UTLZGTdeh+j16A8lJbRvD3rOtrk/7bs= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 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= github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= @@ -71,6 +75,7 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/filecoin-project/go-amt-ipld v0.0.0-20190919045431-3650716fff16 h1:NzojcJU1VbS6zdLG13JMYis/cQy/MrN3rxmZRq56jKA= @@ -83,16 +88,35 @@ github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 h1:EzDjxMg43q1tA2c0MV3tNbaontnHLplHyFF github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcEagxdmQnA3dzork8= github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-critic/go-critic v0.3.5-0.20190526074819-1df300866540/go.mod h1:+sE8vrLDS2M0pZkBk0wy6+nLdKexVDrl/jBqQOTDThA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= +github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= +github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg= +github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= +github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= +github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk= +github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= +github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks= +github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.0.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -102,11 +126,29 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= +github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= +github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c/go.mod h1:unzUULGw35sjyOYjUt0jMTXqHlZPpPc6e+xfO4cd6mM= +github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= +github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= +github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/golangci-lint v1.18.0/go.mod h1:kaqo8l0OZKYPtjNmG4z4HrWLgcYNIJ9B9q3LWri9uLg= +github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547/go.mod h1:0qUabqiIQgfmlAmulqxyiGkkyF6/tOGSnY2cnPVwrzU= +github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= +github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= +github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= @@ -121,6 +163,7 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -131,6 +174,7 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -247,6 +291,8 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M 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/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -254,8 +300,13 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v0.0.0-20161130080628-0de1eaf82fa3/go.mod h1:jxZFDH7ILpTPQTk+E2s+z4CUas9lVNjIuKR4c5/zKgM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b h1:wxtKgYHEncAU00muMD06dzLiahtGM1eouRNOzVV7tdQ= github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= @@ -382,8 +433,10 @@ github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI= github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucas-clemente/quic-go v0.11.2 h1:Mop0ac3zALaBR3wGs6j8OYe/tcFvFsxTUFMkE/7yUOI= github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= +github.com/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA= @@ -392,6 +445,7 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +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/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -399,6 +453,7 @@ github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -410,9 +465,17 @@ github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+ github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.0 h1:U41/2erhAKcmSI14xh/ZTUdBPOzDOIfS93ibzUSl8KM= github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mozilla/tls-observatory v0.0.0-20180409132520-8791a200eb40/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= @@ -440,21 +503,30 @@ github.com/multiformats/go-multihash v0.0.7/go.mod h1:XuKXPp8VHcTygube3OWZC+aZrA github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ= github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nbutton23/zxcvbn-go v0.0.0-20160627004424-a22cb81b2ecd/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/nbutton23/zxcvbn-go v0.0.0-20171102151520-eafdab6b0663/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= +github.com/neelance/parallel v0.0.0-20160708114440-4de9ce63d14c/go.mod h1:eTBvSIlRgLo+CNFFQRQTwUGTZOEdvXIKeZS/xG+D2yU= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg= 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/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.9.0 h1:SZjF721BByVj8QH636/8S2DnX4n0Re3SteMmw3N+tzc= github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.6.0 h1:8XTW0fcJZEq9q+Upcyws4JSGua2MFysCL5xkaSgHc+M= github.com/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -469,16 +541,32 @@ github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/ryanuber/go-glob v0.0.0-20170128012129-256dc444b735/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM= github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/slimsag/godocmd v0.0.0-20161025000126-a1005ad29fe3/go.mod h1:AIBPxLCkKUFc2ZkjCXzs/Kk9OUhQLw/Zicdd0Rhqz2U= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= @@ -488,17 +576,27 @@ github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:s github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= +github.com/sourcegraph/ctxvfs v0.0.0-20180418081416-2b65f1b1ea81/go.mod h1:xIvvI5FiHLxhv8prbzVpaMHaaGPFPFQSuTcxC91ryOo= +github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= +github.com/sourcegraph/go-langserver v2.0.0+incompatible/go.mod h1:bBMjfpzEHd6ijPRoQ7f+knFfw+e8R+W158/MsqAy77c= +github.com/sourcegraph/jsonrpc2 v0.0.0-20190106185902-35a74f039c6a/go.mod h1:eESpbCslcLDs8j2D7IEdGVgul7xuk9odqDTaor30IUU= github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -508,12 +606,19 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= 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/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= +github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/quicktemplate v1.1.1/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830 h1:8kxMKmKzXXL4Ru1nyhvdms/JjWt+3YLpvRb/bAjO/y0= github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= @@ -571,11 +676,13 @@ golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM= golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -585,9 +692,11 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20170915142106-8351a756f30f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -601,6 +710,7 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -613,6 +723,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20171026204733-164713f0dfce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -625,6 +736,7 @@ golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -632,26 +744,38 @@ golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/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-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915090833-1cbadb444a80/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20170915040203-e531a2a1c15f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190121143147-24cd39ecf745/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190813142322-97f12d73768f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190909030654-5b82db07426d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -672,20 +796,24 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 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 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8 h1:Ggy3mWN4l3PUFPfSG0YB3n5fVYggzysUmiUQ89SnX6Y= gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8/go.mod h1:cKXr3E0k4aosgycml1b5z33BVV6hai1Kh7uDgFOkbcs= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -697,3 +825,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/lib/cborrpc/rpc.go b/lib/cborrpc/rpc.go index c02fc5298..901108457 100644 --- a/lib/cborrpc/rpc.go +++ b/lib/cborrpc/rpc.go @@ -1,10 +1,13 @@ package cborrpc import ( + "bytes" "encoding/hex" "io" + "math" cbor "github.com/ipfs/go-ipld-cbor" + ipld "github.com/ipfs/go-ipld-format" logging "github.com/ipfs/go-log" cbg "github.com/whyrusleeping/cbor-gen" ) @@ -43,3 +46,23 @@ func ReadCborRPC(r io.Reader, out interface{}) error { } return cbor.DecodeReader(r, out) } + +func Dump(obj interface{}) ([]byte, error) { + var out bytes.Buffer + if err := WriteCborRPC(&out, obj); err != nil { + return nil, err + } + return out.Bytes(), nil +} + +// TODO: this is a bit ugly, and this package is not exactly the best place +func AsIpld(obj interface{}) (ipld.Node, error) { + if m, ok := obj.(cbg.CBORMarshaler); ok { + b, err := Dump(m) + if err != nil { + return nil, err + } + return cbor.Decode(b, math.MaxUint64, -1) + } + return cbor.WrapObject(obj, math.MaxUint64, -1) +} diff --git a/lib/jsonrpc/handler.go b/lib/jsonrpc/handler.go index f08d8da20..e771b172e 100644 --- a/lib/jsonrpc/handler.go +++ b/lib/jsonrpc/handler.go @@ -212,7 +212,7 @@ func (h handlers) handle(ctx context.Context, req request, w func(func(io.Writer if handler.errOut != -1 { err := callResult[handler.errOut].Interface() if err != nil { - log.Warnf("error in RPC call to '%s': %s", req.Method, err) + log.Warnf("error in RPC call to '%s': %+v", req.Method, err) resp.Error = &respError{ Code: 1, Message: err.(error).Error(), diff --git a/lib/sectorbuilder/sectorbuilder.go b/lib/sectorbuilder/sectorbuilder.go index 242259e30..c9cad6ae5 100644 --- a/lib/sectorbuilder/sectorbuilder.go +++ b/lib/sectorbuilder/sectorbuilder.go @@ -1,7 +1,6 @@ package sectorbuilder import ( - "encoding/binary" "io" "os" "sort" @@ -25,6 +24,10 @@ type SortedSectorInfo = sectorbuilder.SortedSectorInfo type SectorInfo = sectorbuilder.SectorInfo +type SealTicket = sectorbuilder.SealTicket + +type SealedSectorMetadata = sectorbuilder.SealedSectorMetadata + const CommLen = sectorbuilder.CommitmentBytesLen type SectorBuilder struct { @@ -42,7 +45,7 @@ type SectorBuilderConfig struct { func New(cfg *SectorBuilderConfig) (*SectorBuilder, error) { proverId := addressToProverID(cfg.Miner) - sbp, err := sectorbuilder.InitSectorBuilder(cfg.SectorSize, 2, 1, 1, cfg.MetadataDir, proverId, cfg.SealedDir, cfg.StagedDir, 16) + sbp, err := sectorbuilder.InitSectorBuilder(cfg.SectorSize, 2, 1, 0, cfg.MetadataDir, proverId, cfg.SealedDir, cfg.StagedDir, 16) if err != nil { return nil, err } @@ -52,18 +55,12 @@ func New(cfg *SectorBuilderConfig) (*SectorBuilder, error) { }, nil } -func addressToProverID(a address.Address) [31]byte { - var proverId [31]byte +func addressToProverID(a address.Address) [32]byte { + var proverId [32]byte copy(proverId[:], a.Payload()) return proverId } -func sectorIDtoBytes(sid uint64) [31]byte { - var out [31]byte - binary.LittleEndian.PutUint64(out[:], sid) - return out -} - func (sb *SectorBuilder) Destroy() { sectorbuilder.DestroySectorBuilder(sb.handle) } @@ -87,8 +84,8 @@ func (sb *SectorBuilder) ReadPieceFromSealedSector(pieceKey string) ([]byte, err return sectorbuilder.ReadPieceFromSealedSector(sb.handle, pieceKey) } -func (sb *SectorBuilder) SealAllStagedSectors() error { - return sectorbuilder.SealAllStagedSectors(sb.handle) +func (sb *SectorBuilder) SealSector(sectorID uint64, ticket SealTicket) (SealedSectorMetadata, error) { + return sectorbuilder.SealSector(sb.handle, sectorID, ticket) } func (sb *SectorBuilder) SealStatus(sector uint64) (SectorSealingStatus, error) { @@ -121,14 +118,14 @@ func (sb *SectorBuilder) GeneratePoSt(sectorInfo SortedSectorInfo, challengeSeed var UserBytesForSectorSize = sectorbuilder.GetMaxUserBytesPerStagedSector -func VerifySeal(sectorSize uint64, commR, commD, commRStar []byte, proverID address.Address, sectorID uint64, proof []byte) (bool, error) { - var commRa, commDa, commRStara [32]byte +func VerifySeal(sectorSize uint64, commR, commD []byte, proverID address.Address, ticket []byte, sectorID uint64, proof []byte) (bool, error) { + var commRa, commDa, ticketa [32]byte copy(commRa[:], commR) copy(commDa[:], commD) - copy(commRStara[:], commRStar) + copy(ticketa[:], ticket) proverIDa := addressToProverID(proverID) - return sectorbuilder.VerifySeal(sectorSize, commRa, commDa, commRStara, proverIDa, sectorID, proof) + return sectorbuilder.VerifySeal(sectorSize, commRa, commDa, proverIDa, ticketa, sectorID, proof) } func VerifyPieceInclusionProof(sectorSize uint64, pieceSize uint64, commP []byte, commD []byte, proof []byte) (bool, error) { diff --git a/lib/sectorbuilder/sectorbuilder_test.go b/lib/sectorbuilder/sectorbuilder_test.go index 19119ce09..b40a0b9cd 100644 --- a/lib/sectorbuilder/sectorbuilder_test.go +++ b/lib/sectorbuilder/sectorbuilder_test.go @@ -1,50 +1,81 @@ package sectorbuilder_test import ( + "context" "io" "io/ioutil" "math/rand" + "path/filepath" "testing" + "github.com/ipfs/go-datastore" + + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/lib/sectorbuilder" "github.com/filecoin-project/lotus/storage/sector" ) +const sectorSize = 1024 + func TestSealAndVerify(t *testing.T) { t.Skip("this is slow") + build.SectorSizes = []uint64{sectorSize} + + if err := build.GetParams(true); err != nil { + t.Fatal(err) + } + dir, err := ioutil.TempDir("", "sbtest") if err != nil { t.Fatal(err) } - addr, err := address.NewFromString("t1tct3nfaw2q543xtybxcyw4deyxmfwkjk43u4t5y") + addr, err := address.NewFromString("t3vfxagwiegrywptkbmyohqqbfzd7xzbryjydmxso4hfhgsnv6apddyihltsbiikjf3lm7x2myiaxhuc77capq") if err != nil { t.Fatal(err) } + metadata := filepath.Join(dir, "meta") + sealed := filepath.Join(dir, "sealed") + staging := filepath.Join(dir, "staging") + sb, err := sectorbuilder.New(§orbuilder.SectorBuilderConfig{ - SectorSize: 1024, - SealedDir: dir, - StagedDir: dir, - MetadataDir: dir, + SectorSize: sectorSize, + SealedDir: sealed, + StagedDir: staging, + MetadataDir: metadata, Miner: addr, }) if err != nil { t.Fatal(err) } - r := io.LimitReader(rand.New(rand.NewSource(42)), 1016) + // TODO: Consider fixing + store := sector.NewStore(sb, datastore.NewMapDatastore(), func(ctx context.Context) (*sectorbuilder.SealTicket, error) { + return §orbuilder.SealTicket{ + BlockHeight: 5, + TicketBytes: [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2}, + }, nil + }) - if _, err := sb.AddPiece("foo", 1016, r); err != nil { + store.Service() + + dlen := sectorbuilder.UserBytesForSectorSize(sectorSize) + + r := io.LimitReader(rand.New(rand.NewSource(42)), int64(dlen)) + sid, err := store.AddPiece("foo", dlen, r) + if err != nil { + t.Fatal(err) + } + + if err := store.SealSector(context.TODO(), sid); err != nil { t.Fatal(err) } - store := sector.NewStore(sb) - store.Service() ssinfo := <-store.Incoming() - ok, err := sectorbuilder.VerifySeal(1024, ssinfo.CommR[:], ssinfo.CommD[:], ssinfo.CommRStar[:], addr, ssinfo.SectorID, ssinfo.Proof) + ok, err := sectorbuilder.VerifySeal(sectorSize, ssinfo.CommR[:], ssinfo.CommD[:], addr, ssinfo.Ticket.TicketBytes[:], ssinfo.SectorID, ssinfo.Proof) if err != nil { t.Fatal(err) } diff --git a/lotuspond/front/package-lock.json b/lotuspond/front/package-lock.json index 907aea84d..8df204f2e 100644 --- a/lotuspond/front/package-lock.json +++ b/lotuspond/front/package-lock.json @@ -3457,6 +3457,11 @@ } } }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, "clean-css": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", @@ -10663,6 +10668,15 @@ "workbox-webpack-plugin": "4.2.0" } }, + "react-tooltip": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.11.1.tgz", + "integrity": "sha512-YCMVlEC2KuHIzOQhPplTK5jmBBwoL+PYJJdJKXj7M/h7oevupd/QSVq6z5U7/ehIGXyHsAqvwpdxexDfyQ0o3A==", + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0" + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", diff --git a/lotuspond/front/package.json b/lotuspond/front/package.json index a5f397612..c9e6ac769 100644 --- a/lotuspond/front/package.json +++ b/lotuspond/front/package.json @@ -13,6 +13,7 @@ "react-dom": "^16.8.6", "react-router-dom": "^5.0.1", "react-scripts": "3.0.1", + "react-tooltip": "^3.11.1", "rpc-websockets": "^4.5.1", "styled-components": "^3.3.3", "xterm": "^3.14.5", diff --git a/lotuspond/front/src/Address.js b/lotuspond/front/src/Address.js index 6069bd29a..db6870e9a 100644 --- a/lotuspond/front/src/Address.js +++ b/lotuspond/front/src/Address.js @@ -1,10 +1,15 @@ import React from 'react' import CID from 'cids' -import * as multihash from "multihashes"; -import State from "./State"; -import methods from "./chain/methods"; +import ReactTooltip from 'react-tooltip' +import * as multihash from "multihashes" +import State from "./State" +import methods from "./chain/methods" +import Fil from "./Fil"; function truncAddr(addr, len) { + if (!addr) { + return "" + } if (addr.length > len) { return {addr.substr(0, len - 3) + '..'} } @@ -62,7 +67,7 @@ class Address extends React.Component { } openState() { - this.props.mountWindow((onClose) => ) + this.props.mountWindow((onClose) => ) } async actorInfo(actor) { @@ -117,12 +122,12 @@ class Address extends React.Component { nonce =  Nc:{this.state.nonce}{nonce} } - let balance = : {this.state.balance}  + let balance = : {{this.state.balance} if(this.props.nobalance) { balance = } if(this.props.short) { - actInfo = + actInfo = {actInfo}: {this.state.balance} balance = } @@ -136,7 +141,7 @@ class Address extends React.Component { minerInfo =  Power: {this.state.minerInfo.MinerPower} ({this.state.minerInfo.MinerPower/this.state.minerInfo.TotalPower*100}%) } - return {addr}{balance}{actInfo}{nonce}{add20k}{transfer}{minerInfo} + return {addr}{balance}{actInfo}{nonce}{add20k}{transfer}{minerInfo} } } diff --git a/lotuspond/front/src/Block.js b/lotuspond/front/src/Block.js index 422520034..44104d483 100644 --- a/lotuspond/front/src/Block.js +++ b/lotuspond/front/src/Block.js @@ -64,14 +64,21 @@ class Block extends React.Component {
Miner: {
}
Messages: {head.Messages['/']} {/*TODO: link to message explorer */}
Parent Receipts: {head.ParentMessageReceipts['/']}
-
Parent State Root: {head.ParentStateRoot['/']}
+
+ Parent State Root: {head.ParentStateRoot['/']} +  
+  
+  
+  
+  
+
----
{messages}
) } - return ( + return ( {content} ) } diff --git a/lotuspond/front/src/BlockLink.js b/lotuspond/front/src/BlockLink.js index 1faac124c..bfdbd5ea9 100644 --- a/lotuspond/front/src/BlockLink.js +++ b/lotuspond/front/src/BlockLink.js @@ -12,7 +12,7 @@ export class BlockLinks extends React.Component { block = this.props.blocks[k] } - return + return }) } } diff --git a/lotuspond/front/src/ChainExplorer.js b/lotuspond/front/src/ChainExplorer.js index aec6697bc..8957cb3d0 100644 --- a/lotuspond/front/src/ChainExplorer.js +++ b/lotuspond/front/src/ChainExplorer.js @@ -71,10 +71,10 @@ class ChainExplorer extends React.Component { return } if(!base.Blocks) { - console.log("base for H is nll blk", h, base) + console.log("base for H is nil blk", h, base) return } - let cids = base.Blocks.map(b => b.Parents) + let cids = base.Blocks.map(b => (b.Parents || [])) .reduce((acc, val) => { let out = {...acc} val.forEach(c => out[c['/']] = 8) @@ -85,6 +85,10 @@ class ChainExplorer extends React.Component { const blocks = await Promise.all(cids.map(cid => this.props.client.call('Filecoin.ChainGetBlock', [cid]))) + if (!blocks[0]) { + return + } + cache[h] = { Height: blocks[0].Height, Cids: cids, @@ -165,7 +169,7 @@ class ChainExplorer extends React.Component { return
@{h} {info}
})} - return ( + return ( {content} ) } diff --git a/lotuspond/front/src/Client.js b/lotuspond/front/src/Client.js index 56aa82ffe..37606223b 100644 --- a/lotuspond/front/src/Client.js +++ b/lotuspond/front/src/Client.js @@ -1,18 +1,17 @@ import React from 'react'; import Address from "./Address"; import Window from "./Window"; +import Fil from "./Fil"; const dealStates = [ "Unknown", "Rejected", "Accepted", - "Started", - "Failed", "Staged", "Sealing", + "Failed", "Complete", "Error", - "Expired" ] @@ -21,31 +20,43 @@ class Client extends React.Component { super(props) this.state = { + miners: ["t0101"], + ask: {Price: "500000000"}, + kbs: 1, blocks: 12, total: 36000, miner: "t0101", - deals: [] + deals: [], + + blockDelay: 10, } } - componentDidMount() { + async componentDidMount() { + let ver = await this.props.client.call('Filecoin.Version', []) + this.setState({blockDelay: ver.BlockDelay}) + this.getDeals() setInterval(this.getDeals, 1325) } getDeals = async () => { + let miners = await this.props.client.call('Filecoin.StateListMiners', [null]) let deals = await this.props.client.call('Filecoin.ClientListDeals', []) - this.setState({deals}) + miners.sort() + this.setState({deals, miners}) } update = (name) => (e) => this.setState({ [name]: e.target.value }); makeDeal = async () => { + let perBlk = this.state.ask.Price * this.state.kbs * 1000 / (1 << 30) + let file = await this.props.pondClient.call('Pond.CreateRandomFile', [this.state.kbs * 1000]) // 1024 won't fit in 1k blocks :( let cid = await this.props.client.call('Filecoin.ClientImport', [file]) - let dealcid = await this.props.client.call('Filecoin.ClientStartDeal', [cid, this.state.miner, `${Math.round(this.state.total / this.state.blocks)}`, Number(this.state.blocks)]) + let dealcid = await this.props.client.call('Filecoin.ClientStartDeal', [cid, this.state.miner, `${Math.round(perBlk)}`, Number(this.state.blocks)]) console.log("deal cid: ", dealcid) } @@ -67,23 +78,29 @@ class Client extends React.Component { } render() { - let ppb = Math.round(this.state.total / this.state.blocks * 100) / 100 - let ppmbb = Math.round(ppb / (this.state.kbs / 1000) * 100) / 100 + let perBlk = this.state.ask.Price * this.state.kbs * 1000 + let total = perBlk * this.state.blocks + let days = (this.state.blocks * this.state.blockDelay) / 60 / 60 / 24 let dealMaker = let deals = this.state.deals.map((deal, i) =>
    -
  • {i}. Proposal: {deal.ProposalCid['/'].substr(0, 18)}...
    : {dealStates[deal.State]} +
  • {i}. Proposal: {deal.ProposalCid['/'].substr(0, 18)}...
    : {dealStates[deal.State]} {dealStates[deal.State] === 'Complete' ?  [Retrieve] : }
    • Data: {deal.PieceRef['/']}, {deal.Size}B; Duration: {deal.Duration}Blocks
    • @@ -94,7 +111,7 @@ class Client extends React.Component {
) - return + return
{dealMaker}
{deals}
diff --git a/lotuspond/front/src/Consensus.js b/lotuspond/front/src/Consensus.js index 86b1362a4..14b4dd6e2 100644 --- a/lotuspond/front/src/Consensus.js +++ b/lotuspond/front/src/Consensus.js @@ -5,7 +5,7 @@ import Window from "./Window"; function styleForHDiff(max, act) { switch (max - act) { case 0: - return {background: '#00aa00'} + return {background: '#004400'} case 1: return {background: '#aaaa00'} default: diff --git a/lotuspond/front/src/Fil.js b/lotuspond/front/src/Fil.js new file mode 100644 index 000000000..85b26e9ec --- /dev/null +++ b/lotuspond/front/src/Fil.js @@ -0,0 +1,22 @@ +import React from "react"; + +function filStr(raw) { + if(typeof raw !== 'string') { + raw = String(raw) + } + if(raw.length < 19) { + raw = '0'.repeat(19 - raw.length).concat(raw) + } + + let out = raw.substring(0, raw.length - 18).concat('.', raw.substring(raw.length - 18, raw.length)).replace(/\.0+$|0+$/g, ''); + return out ? out : '0' +} + + +class Fil extends React.Component { + render() { + return filStr(this.props.children) + } +} + +export default Fil \ No newline at end of file diff --git a/lotuspond/front/src/State.js b/lotuspond/front/src/State.js index 70ddbc549..93252505d 100644 --- a/lotuspond/front/src/State.js +++ b/lotuspond/front/src/State.js @@ -1,7 +1,19 @@ import React from 'react' import Window from "./Window"; +import CID from "cids"; +import * as multihash from "multihashes"; +import code from "./chain/code"; +import Address from "./Address"; +import Fil from "./Fil"; class State extends React.Component { + byCode = { + [code.init]: InitState, + [code.power]: PowerState, + [code.market]: MarketState, + [code.miner]: MinerState, + } + constructor(props) { super(props) @@ -9,22 +21,179 @@ class State extends React.Component { } async componentDidMount() { - const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props + const tipset = this.props.tipset || await this.props.client.call("Filecoin.ChainHead", []) const actstate = await this.props.client.call('Filecoin.StateReadState', [this.props.actor, tipset]) - this.setState(actstate) + + const c = new CID(this.props.actor.Code['/']) + const mh = multihash.decode(c.multihash) + let code = mh.digest.toString() + + this.setState({...actstate, code: code}) } render() { - const content =
-
Balance: {this.state.Balance}
-
---
-
{Object.keys(this.state.State).map(k =>
{k}: {JSON.stringify(this.state.State[k])}
)}
-
+ let state + if(this.byCode[this.state.code]) { + const Stelem = this.byCode[this.state.code] + state = + } else { + state =
{Object.keys(this.state.State).map(k =>
{k}: {JSON.stringify(this.state.State[k])}
)}
+ } - return + const content =
+
Balance: {this.state.Balance}
+
---
+ {state} +
+ return {content} } } +class InitState extends React.Component { + constructor(props) { + super(props) + + this.state = {actors: []} + } + + async componentDidMount() { + const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props + const actors = await this.props.client.call("Filecoin.StateListActors", [tipset]) + this.setState({actors: actors}) + } + + render() { + return this.state.actors.sort((a, b) => (Number(a.substr(1)) > Number(b.substr(1)))) + .map(addr =>
) + } +} + +class PowerState extends React.Component { + constructor(props) { + super(props) + + this.state = {actors: []} + } + + async componentDidMount() { + const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props + const actors = await this.props.client.call("Filecoin.StateListMiners", [tipset]) + this.setState({actors: actors}) + } + + render() { + return this.state.actors.sort((a, b) => (Number(a.substr(1)) > Number(b.substr(1)))) + .map(addr =>
) + } +} + +class MarketState extends React.Component { + constructor(props) { + super(props) + this.state = {participants: {}, deals: []} + } + + async componentDidMount() { + const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props + const participants = await this.props.client.call("Filecoin.StateMarketParticipants", [tipset]) + const deals = await this.props.client.call("Filecoin.StateMarketDeals", [tipset]) + this.setState({participants, deals}) + } + + render() { + return
+
+
Participants:
+ + + {Object.keys(this.state.participants).map(p => + + + + )} +
AddressAvailableLocked
{this.state.participants[p].Available}{this.state.participants[p].Locked}
+
+
+
---
+
Deals:
+ + + {Object.keys(this.state.deals).map(d => + + + + + + + + )} +
idActiveClientProviderSizePriceDuration
{d}{this.state.deals[d].ActivationEpoch || "No"}
{this.state.deals[d].Deal.Proposal.PieceSize}B{this.state.deals[d].Deal.Proposal.StoragePricePerEpoch*this.state.deals[d].Deal.Proposal.Duration}{this.state.deals[d].Deal.Proposal.Duration}
+
+
+ } +} + +class MinerState extends React.Component { + constructor(props) { + super(props) + this.state = {state: {}, sectorSize: -1, worker: "", networkPower: 0, sectors: {}} + } + + async componentDidMount() { + const tipset = await this.props.client.call("Filecoin.ChainHead", []) // TODO: from props + + const state = await this.props.client.call('Filecoin.StateReadState', [this.props.actor, tipset]) + const sectorSize = await this.props.client.call("Filecoin.StateMinerSectorSize", [this.props.addr, tipset]) + const worker = await this.props.client.call("Filecoin.StateMinerWorker", [this.props.addr, tipset]) + + const tpow = await this.props.client.call("Filecoin.StateMinerPower", [this.props.addr, tipset]) + const networkPower = tpow.TotalPower + + let sectors = {} + + const sset = await this.props.client.call("Filecoin.StateMinerSectors", [this.props.addr, tipset]) || [] + const pset = await this.props.client.call("Filecoin.StateMinerProvingSet", [this.props.addr, tipset]) || [] + + sset.forEach(s => sectors[s.SectorID] = {...s, sectorSet: true}) + pset.forEach(s => sectors[s.SectorID] = {...(sectors[s.SectorID] || s), provingSet: true}) + + this.setState({state, sectorSize, worker, networkPower, sectors}) + } + + render() { + if (!this.state.worker) { + return (...) + } + + let state = this.state.state.State + + return
+
Worker:
+
Sector Size: {this.state.sectorSize/1024} KiB
+
Power: {state.Power} ({state.Power/this.state.networkPower*100}%)
+
Proving Period End: {state.ProvingPeriodEnd}
+
+
----
+
Sectors:
+ + + + + + {Object.keys(this.state.sectors).map(sid => + + + + + + )} + +
IDCommDCommRSectorSetProving
{sid}{this.state.sectors[sid].CommD}{this.state.sectors[sid].CommR}{this.state.sectors[sid].sectorSet ? 'X' : ' '}{this.state.sectors[sid].provingSet ? 'X' : ' '}
+
+
+ } +} + export default State \ No newline at end of file diff --git a/lotuspond/front/src/StorageNode.js b/lotuspond/front/src/StorageNode.js index ef52452f9..741932db9 100644 --- a/lotuspond/front/src/StorageNode.js +++ b/lotuspond/front/src/StorageNode.js @@ -13,6 +13,8 @@ let sealCodes = [ "Failed", "Sealing", "Sealed", + "Paused", + "ReadyForSealing", ] class StorageNode extends React.Component { @@ -122,7 +124,7 @@ class StorageNode extends React.Component {
{this.state.statusCounts.map((c, i) => {sealCodes[i]}: {c} | )}
{this.state.staged ? this.state.staged.map((s, i) => ( -
{s.SectorID} {sealCodes[s.State]}
+
{s.SectorID} {sealCodes[s.State] || `unk ${s.State}`}
)) :
}
diff --git a/lotuspond/front/src/chain/code.js b/lotuspond/front/src/chain/code.js new file mode 100644 index 000000000..c8ffc0b03 --- /dev/null +++ b/lotuspond/front/src/chain/code.js @@ -0,0 +1,9 @@ +export default { + account: "fil/1/account", + power: "fil/1/power", + market: "fil/1/market", + miner: "fil/1/miner", + multisig: "fil/1/multisig", + init: "fil/1/init", + paych: "fil/1/paych", +} diff --git a/lotuspond/front/src/chain/methods.js b/lotuspond/front/src/chain/methods.js index 3cce9098d..b9e153ef7 100644 --- a/lotuspond/front/src/chain/methods.js +++ b/lotuspond/front/src/chain/methods.js @@ -1,10 +1,12 @@ +import code from "./code"; + export default { - "account": [ + [code.account]: [ "Send", "Constructor", "GetAddress", ], - "smarket": [ + [code.power]: [ "Send", "Constructor", "CreateStorageMiner", @@ -15,7 +17,21 @@ export default { "IsMiner", "StorageCollateralForSize" ], - "sminer": [ + [code.market]: [ + "Send", + "Constructor", + "WithdrawBalance", + "AddBalance", + "CheckLockedBalance", + "PublishStorageDeals", + "HandleCronAction", + "SettleExpiredDeals", + "ProcessStorageDealsPayment", + "SlashStorageDealCollateral", + "GetLastExpirationFromDealIDs", + "ActivateStorageDeals", + ], + [code.miner]: [ "Send", "Constructor", "CommitSector", @@ -36,7 +52,7 @@ export default { "PaymentVerifyInclusion", "PaymentVerifySector", ], - "multisig": [ + [code.multisig]: [ "Send", "Constructor", "Propose", @@ -48,13 +64,13 @@ export default { "SwapSigner", "ChangeRequirement", ], - "init": [ + [code.init]: [ "Send", "Constructor", "Exec", "GetIdForAddress" ], - "paych": [ + [code.paych]: [ "Send", "Constructor", "UpdateChannelState", diff --git a/lotuspond/front/src/index.css b/lotuspond/front/src/index.css index 4a1df4db7..82ecd1213 100644 --- a/lotuspond/front/src/index.css +++ b/lotuspond/front/src/index.css @@ -11,3 +11,8 @@ code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } + +input[type=text] { + -webkit-appearance: none; + appearance: none; +} diff --git a/node/builder.go b/node/builder.go index f0bc09348..c316139ee 100644 --- a/node/builder.go +++ b/node/builder.go @@ -235,12 +235,13 @@ func Online() Option { Override(new(*sector.Store), sector.NewStore), Override(new(*sectorblocks.SectorBlocks), sectorblocks.NewSectorBlocks), Override(new(*commitment.Tracker), commitment.NewTracker), + Override(new(sector.TicketFn), modules.SealTicketGen), Override(new(*storage.Miner), modules.StorageMiner), Override(new(dtypes.StagingDAG), modules.StagingDAG), Override(new(*retrieval.Miner), retrieval.NewMiner), - Override(new(*deals.Handler), deals.NewHandler), + Override(new(*deals.Provider), deals.NewProvider), Override(HandleRetrievalKey, modules.HandleRetrieval), Override(HandleDealsKey, modules.HandleDeals), Override(RunSectorServiceKey, modules.RunSectorService), diff --git a/node/impl/client/client.go b/node/impl/client/client.go index 6269fb932..a785bef44 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -5,6 +5,7 @@ import ( "errors" "golang.org/x/xerrors" "io" + "math" "os" "github.com/ipfs/go-blockservice" @@ -13,7 +14,6 @@ import ( chunker "github.com/ipfs/go-ipfs-chunker" offline "github.com/ipfs/go-ipfs-exchange-offline" files "github.com/ipfs/go-ipfs-files" - cbor "github.com/ipfs/go-ipld-cbor" ipld "github.com/ipfs/go-ipld-format" "github.com/ipfs/go-merkledag" "github.com/ipfs/go-unixfs/importer/balanced" @@ -53,7 +53,7 @@ type API struct { Filestore dtypes.ClientFilestore `optional:"true"` } -func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, price types.BigInt, blocksDuration uint64) (*cid.Cid, error) { +func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.Address, epochPrice types.BigInt, blocksDuration uint64) (*cid.Cid, error) { // TODO: make this a param self, err := a.WalletDefaultAddress(ctx) if err != nil { @@ -76,50 +76,17 @@ func (a *API) ClientStartDeal(ctx context.Context, data cid.Cid, miner address.A return nil, err } - vd, err := a.DealClient.VerifyParams(ctx, data) - if err != nil { - return nil, err - } - - voucherData, err := cbor.DumpObject(vd) - if err != nil { - return nil, err - } - - // setup payments - total := types.BigMul(price, types.NewInt(blocksDuration)) - - // TODO: at least ping the miner before creating paych / locking the money - extra := &types.ModVerifyParams{ - Actor: miner, - Method: actors.MAMethods.PaymentVerifyInclusion, - Data: voucherData, - } - - head := a.Chain.GetHeaviestTipSet() - vouchers := deals.VoucherSpec(blocksDuration, total, head.Height(), extra) - - payment, err := a.PaychNewPayment(ctx, self, miner, vouchers) - if err != nil { - return nil, err - } - proposal := deals.ClientDealProposal{ - Data: data, - TotalPrice: total, - Duration: blocksDuration, - Payment: actors.PaymentInfo{ - PayChActor: payment.Channel, - Payer: self, - ChannelMessage: payment.ChannelMessage, - Vouchers: payment.Vouchers, - }, - MinerAddress: miner, - ClientAddress: self, - MinerID: pid, + Data: data, + PricePerEpoch: epochPrice, + ProposalExpiration: math.MaxUint64, // TODO: set something reasonable + Duration: blocksDuration, + ProviderAddress: miner, + Client: self, + MinerID: pid, } - c, err := a.DealClient.Start(ctx, proposal, vd) + c, err := a.DealClient.Start(ctx, proposal) // TODO: send updated voucher with PaymentVerifySector for cheaper validation (validate the sector the miner sent us first!) return &c, err } @@ -135,14 +102,13 @@ func (a *API) ClientListDeals(ctx context.Context) ([]api.DealInfo, error) { out[k] = api.DealInfo{ ProposalCid: v.ProposalCid, State: v.State, - Miner: v.Proposal.MinerAddress, + Provider: v.Proposal.Provider, PieceRef: v.Proposal.PieceRef, - CommP: v.Proposal.CommP, - Size: v.Proposal.Size, + Size: v.Proposal.PieceSize, - TotalPrice: v.Proposal.TotalPrice, - Duration: v.Proposal.Duration, + PricePerEpoch: v.Proposal.StoragePricePerEpoch, + Duration: v.Proposal.Duration, } } diff --git a/node/impl/common.go b/node/impl/common.go index 74f614ee3..f8037ca1d 100644 --- a/node/impl/common.go +++ b/node/impl/common.go @@ -87,6 +87,8 @@ func (a *CommonAPI) Version(context.Context) (api.Version, error) { return api.Version{ Version: build.Version, APIVersion: build.APIVersion, + + BlockDelay: build.BlockDelay, }, nil } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 135317ca9..68a134246 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -1,11 +1,15 @@ package full import ( + "bytes" "context" + "github.com/filecoin-project/go-amt-ipld" + "strconv" cid "github.com/ipfs/go-cid" "github.com/ipfs/go-hamt-ipld" "github.com/libp2p/go-libp2p-core/peer" + cbg "github.com/whyrusleeping/cbor-gen" "go.uber.org/fx" "golang.org/x/xerrors" @@ -33,8 +37,8 @@ type StateAPI struct { Chain *store.ChainStore } -func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address) ([]*api.SectorInfo, error) { - return stmgr.GetMinerSectorSet(ctx, a.StateManager, nil, addr) +func (a *StateAPI) StateMinerSectors(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.SectorInfo, error) { + return stmgr.GetMinerSectorSet(ctx, a.StateManager, ts, addr) } func (a *StateAPI) StateMinerProvingSet(ctx context.Context, addr address.Address, ts *types.TipSet) ([]*api.SectorInfo, error) { @@ -54,25 +58,7 @@ func (a *StateAPI) StateMinerPower(ctx context.Context, maddr address.Address, t } func (a *StateAPI) StateMinerWorker(ctx context.Context, m address.Address, ts *types.TipSet) (address.Address, error) { - ret, err := a.StateManager.Call(ctx, &types.Message{ - From: m, - To: m, - Method: actors.MAMethods.GetWorkerAddr, - }, ts) - if err != nil { - return address.Undef, xerrors.Errorf("failed to get miner worker addr: %w", err) - } - - if ret.ExitCode != 0 { - return address.Undef, xerrors.Errorf("failed to get miner worker addr (exit code %d)", ret.ExitCode) - } - - w, err := address.NewFromBytes(ret.Return) - if err != nil { - return address.Undef, xerrors.Errorf("GetWorkerAddr returned malformed address: %w", err) - } - - return w, nil + return stmgr.GetMinerWorker(ctx, a.StateManager, ts, m) } func (a *StateAPI) StateMinerPeerID(ctx context.Context, m address.Address, ts *types.TipSet) (peer.ID, error) { @@ -83,6 +69,10 @@ func (a *StateAPI) StateMinerProvingPeriodEnd(ctx context.Context, actor address return stmgr.GetMinerProvingPeriodEnd(ctx, a.StateManager, ts, actor) } +func (a *StateAPI) StateMinerSectorSize(ctx context.Context, actor address.Address, ts *types.TipSet) (uint64, error) { + return stmgr.GetMinerSectorSize(ctx, a.StateManager, ts, actor) +} + func (a *StateAPI) StatePledgeCollateral(ctx context.Context, ts *types.TipSet) (types.BigInt, error) { param, err := actors.SerializeParams(&actors.PledgeCollateralParams{Size: types.NewInt(0)}) if err != nil { @@ -90,8 +80,8 @@ func (a *StateAPI) StatePledgeCollateral(ctx context.Context, ts *types.TipSet) } ret, aerr := a.StateManager.Call(ctx, &types.Message{ - From: actors.StorageMarketAddress, - To: actors.StorageMarketAddress, + From: actors.StoragePowerAddress, + To: actors.StoragePowerAddress, Method: actors.SPAMethods.PledgeCollateralForSize, Params: param, @@ -210,7 +200,7 @@ func (a *StateAPI) StateWaitMsg(ctx context.Context, msg cid.Cid) (*api.MsgWait, func (a *StateAPI) StateListMiners(ctx context.Context, ts *types.TipSet) ([]address.Address, error) { var state actors.StoragePowerState - if _, err := a.StateManager.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil { + if _, err := a.StateManager.LoadActorState(ctx, actors.StoragePowerAddress, &state, ts); err != nil { return nil, err } @@ -226,3 +216,66 @@ func (a *StateAPI) StateListMiners(ctx context.Context, ts *types.TipSet) ([]add func (a *StateAPI) StateListActors(ctx context.Context, ts *types.TipSet) ([]address.Address, error) { return a.StateManager.ListAllActors(ctx, ts) } + +func (a *StateAPI) StateMarketBalance(ctx context.Context, addr address.Address, ts *types.TipSet) (actors.StorageParticipantBalance, error) { + return a.StateManager.MarketBalance(ctx, addr, ts) +} + +func (a *StateAPI) StateMarketParticipants(ctx context.Context, ts *types.TipSet) (map[string]actors.StorageParticipantBalance, error) { + out := map[string]actors.StorageParticipantBalance{} + + var state actors.StorageMarketState + if _, err := a.StateManager.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil { + return nil, err + } + cst := hamt.CSTFromBstore(a.StateManager.ChainStore().Blockstore()) + nd, err := hamt.LoadNode(ctx, cst, state.Balances) + if err != nil { + return nil, err + } + + err = nd.ForEach(ctx, func(k string, val interface{}) error { + cv := val.(*cbg.Deferred) + a, err := address.NewFromBytes([]byte(k)) + if err != nil { + return err + } + var b actors.StorageParticipantBalance + if err := b.UnmarshalCBOR(bytes.NewReader(cv.Raw)); err != nil { + return err + } + out[a.String()] = b + return nil + }) + if err != nil { + return nil, err + } + return out, nil +} + +func (a *StateAPI) StateMarketDeals(ctx context.Context, ts *types.TipSet) (map[string]actors.OnChainDeal, error) { + out := map[string]actors.OnChainDeal{} + + var state actors.StorageMarketState + if _, err := a.StateManager.LoadActorState(ctx, actors.StorageMarketAddress, &state, ts); err != nil { + return nil, err + } + + blks := amt.WrapBlockstore(a.StateManager.ChainStore().Blockstore()) + da, err := amt.LoadAMT(blks, state.Deals) + if err != nil { + return nil, err + } + + if err := da.ForEach(func(i uint64, v *cbg.Deferred) error { + var d actors.OnChainDeal + if err := d.UnmarshalCBOR(bytes.NewReader(v.Raw)); err != nil { + return err + } + out[strconv.FormatInt(int64(i), 10)] = d + return nil + }); err != nil { + return nil, err + } + return out, nil +} diff --git a/node/impl/storminer.go b/node/impl/storminer.go index 3ced1e3e2..e70480651 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -7,12 +7,13 @@ import ( "math/rand" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/lib/sectorbuilder" "github.com/filecoin-project/lotus/storage" "github.com/filecoin-project/lotus/storage/sector" "github.com/filecoin-project/lotus/storage/sectorblocks" + + "golang.org/x/xerrors" ) type StorageMinerAPI struct { @@ -31,14 +32,23 @@ func (sm *StorageMinerAPI) ActorAddress(context.Context) (address.Address, error } func (sm *StorageMinerAPI) StoreGarbageData(ctx context.Context) (uint64, error) { - size := sectorbuilder.UserBytesForSectorSize(build.SectorSize) + ssize, err := sm.Miner.SectorSize(ctx) + if err != nil { + return 0, xerrors.Errorf("failed to get miner sector size: %w", err) + } + size := sectorbuilder.UserBytesForSectorSize(ssize) + // TODO: create a deal name := fmt.Sprintf("fake-file-%d", rand.Intn(100000000)) sectorId, err := sm.Sectors.AddPiece(name, size, io.LimitReader(rand.New(rand.NewSource(42)), int64(size))) if err != nil { return 0, err } + if err := sm.Sectors.SealSector(ctx, sectorId); err != nil { + return sectorId, err + } + return sectorId, err } @@ -51,11 +61,6 @@ func (sm *StorageMinerAPI) SectorsList(context.Context) ([]uint64, error) { return sm.SectorBuilder.GetAllStagedSectors() } -// Seal all staged sectors -func (sm *StorageMinerAPI) SectorsStagedSeal(context.Context) error { - return sm.SectorBuilder.SealAllStagedSectors() -} - func (sm *StorageMinerAPI) SectorsRefs(context.Context) (map[string][]api.SealedRef, error) { // json can't handle cids as map keys out := map[string][]api.SealedRef{} diff --git a/node/modules/storageminer.go b/node/modules/storageminer.go index 009ba57b2..4f9df1c42 100644 --- a/node/modules/storageminer.go +++ b/node/modules/storageminer.go @@ -14,6 +14,7 @@ import ( "github.com/libp2p/go-libp2p-core/routing" "github.com/mitchellh/go-homedir" "go.uber.org/fx" + "golang.org/x/xerrors" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" @@ -38,13 +39,18 @@ func minerAddrFromDS(ds dtypes.MetadataDS) (address.Address, error) { return address.NewFromBytes(maddrb) } -func SectorBuilderConfig(storagePath string) func(dtypes.MetadataDS) (*sectorbuilder.SectorBuilderConfig, error) { - return func(ds dtypes.MetadataDS) (*sectorbuilder.SectorBuilderConfig, error) { +func SectorBuilderConfig(storagePath string) func(dtypes.MetadataDS, api.FullNode) (*sectorbuilder.SectorBuilderConfig, error) { + return func(ds dtypes.MetadataDS, api api.FullNode) (*sectorbuilder.SectorBuilderConfig, error) { minerAddr, err := minerAddrFromDS(ds) if err != nil { return nil, err } + ssize, err := api.StateMinerSectorSize(context.TODO(), minerAddr, nil) + if err != nil { + return nil, err + } + sp, err := homedir.Expand(storagePath) if err != nil { return nil, err @@ -56,7 +62,7 @@ func SectorBuilderConfig(storagePath string) func(dtypes.MetadataDS) (*sectorbui sb := §orbuilder.SectorBuilderConfig{ Miner: minerAddr, - SectorSize: build.SectorSize, + SectorSize: ssize, MetadataDir: metadata, SealedDir: sealed, StagedDir: staging, @@ -98,13 +104,13 @@ func HandleRetrieval(host host.Host, lc fx.Lifecycle, m *retrieval.Miner) { }) } -func HandleDeals(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, h *deals.Handler) { +func HandleDeals(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, h *deals.Provider) { ctx := helpers.LifecycleCtx(mctx, lc) lc.Append(fx.Hook{ OnStart: func(context.Context) error { h.Run(ctx) - host.SetStreamHandler(deals.ProtocolID, h.HandleStream) + host.SetStreamHandler(deals.DealProtocolID, h.HandleStream) host.SetStreamHandler(deals.AskProtocolID, h.HandleAskStream) return nil }, @@ -157,3 +163,27 @@ func RegisterMiner(lc fx.Lifecycle, ds dtypes.MetadataDS, api api.FullNode) erro }) return nil } + +func SealTicketGen(api api.FullNode) sector.TicketFn { + return func(ctx context.Context) (*sectorbuilder.SealTicket, error) { + ts, err := api.ChainHead(ctx) + if err != nil { + return nil, xerrors.Errorf("getting head ts for SealTicket failed: %w", err) + } + + r, err := api.ChainGetRandomness(ctx, ts, nil, build.SealRandomnessLookback) + if err != nil { + return nil, xerrors.Errorf("getting randomness for SealTicket failed: %w", err) + } + + var tkt [sectorbuilder.CommLen]byte + if n := copy(tkt[:], r); n != sectorbuilder.CommLen { + return nil, xerrors.Errorf("unexpected randomness len: %d (expected %d)", n, sectorbuilder.CommLen) + } + + return §orbuilder.SealTicket{ + BlockHeight: ts.Height() - build.SealRandomnessLookback, + TicketBytes: tkt, + }, nil + } +} diff --git a/paych/simple.go b/paych/simple.go index d8a3f4163..99c578d05 100644 --- a/paych/simple.go +++ b/paych/simple.go @@ -19,14 +19,14 @@ func (pm *Manager) createPaych(ctx context.Context, from, to address.Address, am enc, aerr := actors.SerializeParams(&actors.ExecParams{ Params: params, - Code: actors.PaymentChannelActorCodeCid, + Code: actors.PaymentChannelCodeCid, }) if aerr != nil { return address.Undef, cid.Undef, aerr } msg := &types.Message{ - To: actors.InitActorAddress, + To: actors.InitAddress, From: from, Value: amt, Method: actors.IAMethods.Exec, diff --git a/scripts/deploy-devnet.sh b/scripts/deploy-devnet.sh index f0c2f6809..ac5b800d1 100755 --- a/scripts/deploy-devnet.sh +++ b/scripts/deploy-devnet.sh @@ -7,6 +7,13 @@ BOOTSTRAPPERS=( root@147.75.80.17 ) ############ +read -p "You are about to deploy new DevNet, killing bootstrap nodes. Proceed? (y/n)? " r +case "$r" in + y|Y ) echo "Proceding";; + n|N ) exit 0;; + * ) exit 1;; +esac + log() { echo -e "\e[33m$1\e[39m" } @@ -74,7 +81,7 @@ ssh $GENESIS_HOST 'systemctl start lotus-storage-miner' log 'Getting genesis addr info' -ssh $GENESIS_HOST './lotus net listen' | grep -v '/10' | grep -v '/127' > build/bootstrap/root.pi +ssh $GENESIS_HOST 'lotus net listen' | grep -v '/10' | grep -v '/127' > build/bootstrap/root.pi log '> Creating bootstrap binaries' make @@ -106,5 +113,5 @@ do log 'Extracting addr info' - ssh "$host" './lotus net listen' | grep -v '/10' | grep -v '/127' >> build/bootstrap/bootstrappers.pi + ssh "$host" 'lotus net listen' | grep -v '/10' | grep -v '/127' >> build/bootstrap/bootstrappers.pi done diff --git a/storage/commitment/tracker.go b/storage/commitment/tracker.go index ea7cb1515..aa50c705e 100644 --- a/storage/commitment/tracker.go +++ b/storage/commitment/tracker.go @@ -25,7 +25,7 @@ func init() { var commitmentDsPrefix = datastore.NewKey("/commitments") type Tracker struct { - commitDs datastore.Datastore + commitments datastore.Datastore lk sync.Mutex @@ -34,35 +34,36 @@ type Tracker struct { func NewTracker(ds dtypes.MetadataDS) *Tracker { return &Tracker{ - commitDs: namespace.Wrap(ds, commitmentDsPrefix), - waits: map[datastore.Key]chan struct{}{}, + commitments: namespace.Wrap(ds, commitmentDsPrefix), + waits: map[datastore.Key]chan struct{}{}, } } type commitment struct { - Msg cid.Cid + DealIDs []uint64 + Msg cid.Cid } func commitmentKey(miner address.Address, sectorId uint64) datastore.Key { return commitmentDsPrefix.ChildString(miner.String()).ChildString(fmt.Sprintf("%d", sectorId)) } -func (ct *Tracker) TrackCommitSectorMsg(miner address.Address, sectorId uint64, mcid cid.Cid) error { +func (ct *Tracker) TrackCommitSectorMsg(miner address.Address, sectorId uint64, commitMsg cid.Cid) error { key := commitmentKey(miner, sectorId) ct.lk.Lock() defer ct.lk.Unlock() - tracking, err := ct.commitDs.Get(key) + tracking, err := ct.commitments.Get(key) switch err { case datastore.ErrNotFound: - comm := &commitment{Msg: mcid} + comm := &commitment{Msg: commitMsg} commB, err := cbor.DumpObject(comm) if err != nil { return err } - if err := ct.commitDs.Put(key, commB); err != nil { + if err := ct.commitments.Put(key, commB); err != nil { return err } @@ -78,11 +79,11 @@ func (ct *Tracker) TrackCommitSectorMsg(miner address.Address, sectorId uint64, return err } - if !comm.Msg.Equals(mcid) { - return xerrors.Errorf("commitment tracking for miner %s, sector %d: already tracking %s, got another commitment message: %s", miner, sectorId, comm.Msg, mcid) + if !comm.Msg.Equals(commitMsg) { + return xerrors.Errorf("commitment tracking for miner %s, sector %d: already tracking %s, got another commitment message: %s", miner, sectorId, comm.Msg, commitMsg) } - log.Warnf("commitment.TrackCommitSectorMsg called more than once for miner %s, sector %d, message %s", miner, sectorId, mcid) + log.Warnf("commitment.TrackCommitSectorMsg called more than once for miner %s, sector %d, message %s", miner, sectorId, commitMsg) return nil default: return err @@ -94,7 +95,7 @@ func (ct *Tracker) WaitCommit(ctx context.Context, miner address.Address, sector ct.lk.Lock() - tracking, err := ct.commitDs.Get(key) + tracking, err := ct.commitments.Get(key) if err != datastore.ErrNotFound { ct.lk.Unlock() @@ -120,7 +121,7 @@ func (ct *Tracker) WaitCommit(ctx context.Context, miner address.Address, sector select { case <-wait: - tracking, err := ct.commitDs.Get(key) + tracking, err := ct.commitments.Get(key) if err != nil { return cid.Undef, xerrors.Errorf("failed to get commitment after waiting: %w", err) } diff --git a/storage/miner.go b/storage/miner.go index 35d726d0c..0ab1ce009 100644 --- a/storage/miner.go +++ b/storage/miner.go @@ -9,9 +9,9 @@ import ( logging "github.com/ipfs/go-log" "github.com/libp2p/go-libp2p-core/host" "github.com/pkg/errors" + "golang.org/x/xerrors" "github.com/filecoin-project/lotus/api" - "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/address" "github.com/filecoin-project/lotus/chain/events" @@ -54,6 +54,7 @@ type storageMinerApi interface { StateMinerWorker(context.Context, address.Address, *types.TipSet) (address.Address, error) StateMinerProvingPeriodEnd(context.Context, address.Address, *types.TipSet) (uint64, error) StateMinerProvingSet(context.Context, address.Address, *types.TipSet) ([]*api.SectorInfo, error) + StateMinerSectorSize(context.Context, address.Address, *types.TipSet) (uint64, error) StateWaitMsg(context.Context, cid.Cid) (*api.MsgWait, error) MpoolPushMessage(context.Context, *types.Message) (*types.SignedMessage, error) @@ -121,7 +122,12 @@ func (m *Miner) handlePostingSealedSectors(ctx context.Context) { func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSealingStatus) error { log.Info("committing sector") - ok, err := sectorbuilder.VerifySeal(build.SectorSize, sinfo.CommR[:], sinfo.CommD[:], sinfo.CommRStar[:], m.maddr, sinfo.SectorID, sinfo.Proof) + ssize, err := m.SectorSize(ctx) + if err != nil { + return xerrors.Errorf("failed to check out own sector size: %w", err) + } + + ok, err := sectorbuilder.VerifySeal(ssize, sinfo.CommR[:], sinfo.CommD[:], m.maddr, sinfo.Ticket.TicketBytes[:], sinfo.SectorID, sinfo.Proof) if err != nil { log.Error("failed to verify seal we just created: ", err) } @@ -129,12 +135,19 @@ func (m *Miner) commitSector(ctx context.Context, sinfo sectorbuilder.SectorSeal log.Error("seal we just created failed verification") } - params := &actors.CommitSectorParams{ - SectorID: sinfo.SectorID, - CommD: sinfo.CommD[:], - CommR: sinfo.CommR[:], - CommRStar: sinfo.CommRStar[:], - Proof: sinfo.Proof, + deals, err := m.secst.DealsForCommit(sinfo.SectorID) + if err != nil { + return xerrors.Errorf("getting sector deals failed: %w", err) + } + + params := &actors.OnChainSealVerifyInfo{ + CommD: sinfo.CommD[:], + CommR: sinfo.CommR[:], + Proof: sinfo.Proof, + Epoch: sinfo.Ticket.BlockHeight, + + DealIDs: deals, + SectorNumber: sinfo.SectorID, } enc, aerr := actors.SerializeParams(params) if aerr != nil { @@ -192,3 +205,8 @@ func (m *Miner) runPreflightChecks(ctx context.Context) error { log.Infof("starting up miner %s, worker addr %s", m.maddr, m.worker) return nil } + +func (m *Miner) SectorSize(ctx context.Context) (uint64, error) { + // TODO: cache this + return m.api.StateMinerSectorSize(ctx, m.maddr, nil) +} diff --git a/storage/post.go b/storage/post.go index d34069894..ee024acbb 100644 --- a/storage/post.go +++ b/storage/post.go @@ -44,12 +44,12 @@ func (m *Miner) beginPosting(ctx context.Context) { m.schedLk.Unlock() - log.Infof("Scheduling post at height %d", ppe-build.PoSTChallangeTime) + log.Infof("Scheduling post at height %d", ppe-build.PoStChallangeTime) err = m.events.ChainAt(m.computePost(m.schedPost), func(ts *types.TipSet) error { // Revert // TODO: Cancel post log.Errorf("TODO: Cancel PoSt, re-run") return nil - }, PoStConfidence, ppe-build.PoSTChallangeTime) + }, PoStConfidence, ppe-build.PoStChallangeTime) if err != nil { // TODO: This is BAD, figure something out log.Errorf("scheduling PoSt failed: %s", err) @@ -82,13 +82,13 @@ func (m *Miner) scheduleNextPost(ppe uint64) { m.schedPost = ppe m.schedLk.Unlock() - log.Infow("scheduling PoSt", "post-height", ppe-build.PoSTChallangeTime, + log.Infow("scheduling PoSt", "post-height", ppe-build.PoStChallangeTime, "height", ts.Height(), "ppe", ppe, "proving-period", provingPeriod) err = m.events.ChainAt(m.computePost(ppe), func(ts *types.TipSet) error { // Revert // TODO: Cancel post log.Errorf("TODO: Cancel PoSt, re-run") return nil - }, PoStConfidence, ppe-build.PoSTChallangeTime) + }, PoStConfidence, ppe-build.PoStChallangeTime) if err != nil { // TODO: This is BAD, figure something out log.Errorf("scheduling PoSt failed: %+v", err) @@ -113,13 +113,13 @@ func (m *Miner) computePost(ppe uint64) func(ts *types.TipSet, curH uint64) erro return xerrors.Errorf("failed to get proving set for miner: %w", err) } - r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(int64(ts.Height())-int64(ppe)+int64(build.PoSTChallangeTime))) // TODO: review: check math + r, err := m.api.ChainGetRandomness(ctx, ts, nil, int(int64(ts.Height())-int64(ppe)+int64(build.PoStChallangeTime)+int64(build.PoStRandomnessLookback))) // TODO: review: check math if err != nil { return xerrors.Errorf("failed to get chain randomness for post (ts=%d; ppe=%d): %w", ts.Height(), ppe, err) } log.Infow("running PoSt", "delayed-by", - int64(ts.Height())-(int64(ppe)-int64(build.PoSTChallangeTime)), + int64(ts.Height())-(int64(ppe)-int64(build.PoStChallangeTime)), "chain-random", r, "ppe", ppe, "height", ts.Height()) tsStart := time.Now() diff --git a/storage/sector/store.go b/storage/sector/store.go index 19ca85363..5a4b6a9a3 100644 --- a/storage/sector/store.go +++ b/storage/sector/store.go @@ -2,24 +2,47 @@ package sector import ( "context" - "github.com/filecoin-project/go-sectorbuilder/sealing_state" - "golang.org/x/xerrors" + "fmt" "io" "sync" "time" + "github.com/filecoin-project/go-sectorbuilder/sealing_state" + "github.com/ipfs/go-datastore" + "github.com/ipfs/go-datastore/namespace" + cbor "github.com/ipfs/go-ipld-cbor" + logging "github.com/ipfs/go-log" + "golang.org/x/xerrors" + "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/lib/sectorbuilder" - - logging "github.com/ipfs/go-log" + "github.com/filecoin-project/lotus/node/modules/dtypes" ) +func init() { + cbor.RegisterCborType(dealMapping{}) +} + var log = logging.Logger("sectorstore") +var sectorDealsPrefix = datastore.NewKey("/sectordeals") + +type dealMapping struct { + DealIDs []uint64 + Committed bool +} + +type TicketFn func(context.Context) (*sectorbuilder.SealTicket, error) + // TODO: eventually handle sector storage here instead of in rust-sectorbuilder type Store struct { - lk sync.Mutex - sb *sectorbuilder.SectorBuilder + waitingLk sync.Mutex + + sb *sectorbuilder.SectorBuilder + tktFn TicketFn + + dealsLk sync.Mutex + deals datastore.Datastore waiting map[uint64]chan struct{} incoming []chan sectorbuilder.SectorSealingStatus @@ -28,9 +51,11 @@ type Store struct { closeCh chan struct{} } -func NewStore(sb *sectorbuilder.SectorBuilder) *Store { +func NewStore(sb *sectorbuilder.SectorBuilder, ds dtypes.MetadataDS, tktFn TicketFn) *Store { return &Store{ sb: sb, + tktFn: tktFn, + deals: namespace.Wrap(ds, sectorDealsPrefix), waiting: map[uint64]chan struct{}{}, closeCh: make(chan struct{}), } @@ -44,13 +69,13 @@ func (s *Store) poll() { log.Debug("polling for sealed sectors...") // get a list of sectors to poll - s.lk.Lock() + s.waitingLk.Lock() toPoll := make([]uint64, 0, len(s.waiting)) for id := range s.waiting { toPoll = append(toPoll, id) } - s.lk.Unlock() + s.waitingLk.Unlock() var done []sectorbuilder.SectorSealingStatus @@ -68,7 +93,7 @@ func (s *Store) poll() { } // send updates - s.lk.Lock() + s.waitingLk.Lock() for _, sector := range done { watch, ok := s.waiting[sector.SectorID] if ok { @@ -79,7 +104,7 @@ func (s *Store) poll() { c <- sector // TODO: ctx! } } - s.lk.Unlock() + s.waitingLk.Unlock() } func (s *Store) service() { @@ -90,35 +115,112 @@ func (s *Store) service() { case <-poll: s.poll() case <-s.closeCh: - s.lk.Lock() + s.waitingLk.Lock() for _, c := range s.incoming { close(c) } - s.lk.Unlock() + s.waitingLk.Unlock() return } } } -func (s *Store) AddPiece(ref string, size uint64, r io.Reader) (sectorID uint64, err error) { +func (s *Store) AddPiece(ref string, size uint64, r io.Reader, dealIDs ...uint64) (sectorID uint64, err error) { sectorID, err = s.sb.AddPiece(ref, size, r) - if err != nil { return 0, err } - s.lk.Lock() + s.waitingLk.Lock() _, exists := s.waiting[sectorID] if !exists { // pieces can share sectors s.waiting[sectorID] = make(chan struct{}) } - s.lk.Unlock() + s.waitingLk.Unlock() + + s.dealsLk.Lock() + defer s.dealsLk.Unlock() + + k := datastore.NewKey(fmt.Sprint(sectorID)) + e, err := s.deals.Get(k) + var deals dealMapping + switch err { + case nil: + if err := cbor.DecodeInto(e, &deals); err != nil { + return 0, err + } + if deals.Committed { + return 0, xerrors.Errorf("sector %d already committed", sectorID) + } + fallthrough + case datastore.ErrNotFound: + deals.DealIDs = append(deals.DealIDs, dealIDs...) + d, err := cbor.DumpObject(&deals) + if err != nil { + return 0, err + } + if err := s.deals.Put(k, d); err != nil { + return 0, err + } + default: + return 0, err + } return sectorID, nil } +func (s *Store) DealsForCommit(sectorID uint64) ([]uint64, error) { + s.dealsLk.Lock() + defer s.dealsLk.Unlock() + + k := datastore.NewKey(fmt.Sprint(sectorID)) + e, err := s.deals.Get(k) + + switch err { + case nil: + var deals dealMapping + if err := cbor.DecodeInto(e, &deals); err != nil { + return nil, err + } + if deals.Committed { + log.Errorf("getting deal IDs for sector %d: sector already marked as committed", sectorID) + } + + deals.Committed = true + d, err := cbor.DumpObject(&deals) + if err != nil { + return nil, err + } + if err := s.deals.Put(k, d); err != nil { + return nil, err + } + + return deals.DealIDs, nil + case datastore.ErrNotFound: + log.Errorf("getting deal IDs for sector %d failed: %s", err) + return []uint64{}, nil + default: + return nil, err + } +} + +func (s *Store) SealSector(ctx context.Context, sectorID uint64) error { + tkt, err := s.tktFn(ctx) + if err != nil { + return err + } + + // TODO: That's not async, is it? + // - If not then we probably can drop this wait-for-seal hack below + _, err = s.sb.SealSector(sectorID, *tkt) + if err != nil { + return err + } + return nil +} + func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) { - s.lk.Lock() + s.waitingLk.Lock() var at = -1 for i, ch := range s.incoming { if ch == c { @@ -126,7 +228,7 @@ func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) { } } if at == -1 { - s.lk.Unlock() + s.waitingLk.Unlock() return } if len(s.incoming) > 1 { @@ -135,21 +237,21 @@ func (s *Store) CloseIncoming(c <-chan sectorbuilder.SectorSealingStatus) { s.incoming[last] = nil } s.incoming = s.incoming[:len(s.incoming)-1] - s.lk.Unlock() + s.waitingLk.Unlock() } func (s *Store) Incoming() <-chan sectorbuilder.SectorSealingStatus { ch := make(chan sectorbuilder.SectorSealingStatus, 8) - s.lk.Lock() + s.waitingLk.Lock() s.incoming = append(s.incoming, ch) - s.lk.Unlock() + s.waitingLk.Unlock() return ch } func (s *Store) WaitSeal(ctx context.Context, sector uint64) (sectorbuilder.SectorSealingStatus, error) { - s.lk.Lock() + s.waitingLk.Lock() watch, ok := s.waiting[sector] - s.lk.Unlock() + s.waitingLk.Unlock() if ok { select { case <-watch: diff --git a/storage/sectorblocks/blocks.go b/storage/sectorblocks/blocks.go index 413cd9d3c..28b864e7a 100644 --- a/storage/sectorblocks/blocks.go +++ b/storage/sectorblocks/blocks.go @@ -153,7 +153,7 @@ func (r *refStorer) Read(p []byte) (n int, err error) { } } -func (st *SectorBlocks) AddUnixfsPiece(ref cid.Cid, r UnixfsReader, keepAtLeast uint64) (sectorID uint64, err error) { +func (st *SectorBlocks) AddUnixfsPiece(ref cid.Cid, r UnixfsReader, dealID uint64) (sectorID uint64, err error) { size, err := r.Size() if err != nil { return 0, err @@ -166,7 +166,7 @@ func (st *SectorBlocks) AddUnixfsPiece(ref cid.Cid, r UnixfsReader, keepAtLeast intermediate: st.intermediate, } - return st.Store.AddPiece(refst.pieceRef, uint64(size), refst) + return st.Store.AddPiece(refst.pieceRef, uint64(size), refst, dealID) } func (st *SectorBlocks) List() (map[cid.Cid][]api.SealedRef, error) {