Merge pull request #479 from filecoin-project/devnet/6

Devnet 6
This commit is contained in:
Łukasz Magiera 2019-10-29 14:42:16 +01:00 committed by GitHub
commit 340e9177b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
101 changed files with 5042 additions and 1488 deletions

View File

@ -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:

View File

@ -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)

View File

@ -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 {

View File

@ -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)
}

View File

@ -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
)

28
api/utils.go Normal file
View File

@ -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
}

View File

@ -1 +1 @@
/ip4/147.75.80.17/tcp/1347/p2p/12D3KooWQ3NBPgTbXFRGnmpZUpYBSPJtwJfxuAFHBuWJ8LumCYf2
/ip4/147.75.80.17/tcp/1347/p2p/12D3KooWPTYfTi7B1mQpbyRaCT65Trf7zW9npmihcF1xPfZogrzh

View File

@ -1 +1 @@
/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWGU8C1mFsEtz4bXmHUH3kQTnQnxVy8cigwGV94qCpYJw7
/ip4/147.75.80.29/tcp/1347/p2p/12D3KooWEwGkxuG4BSvWUU8Sf69rxUYjWHAMT2qFVBhzGJZAXc6v

Binary file not shown.

View File

@ -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 {

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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)
}

View File

@ -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")
}

View File

@ -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

View File

@ -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},

View File

@ -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,
})

View File

@ -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<addr, StorageParticipantBalance>
Deals cid.Cid // amt<StorageDeal>
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) {
}
*/

View File

@ -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

View File

@ -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)
}
}

View File

@ -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")
}

View File

@ -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,

File diff suppressed because it is too large Load Diff

View File

@ -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,

778
chain/deals/cbor_gen.go Normal file
View File

@ -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
}

View File

@ -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,
})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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{},

View File

@ -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

View File

@ -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,
}

View File

@ -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
}

View File

@ -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)

View File

@ -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 {

View File

@ -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)
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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},

View File

@ -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
}

View File

@ -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
}

View File

@ -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,
}

View File

@ -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}
}

View File

@ -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
},

View File

@ -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,

View File

@ -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
}

View File

@ -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
},
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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())
}

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>Sending Funds - Lotus Fountain</title>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div class="Index">
<div class="Index-nodes">
<div class="Index-node">
[SENDING FUNDS]
</div>
<div class="Index-node">
<form action='/send' method='get'>
<span>Enter destination address:</span>
<input type='text' name='address' style="width: 300px">
<button type='submit'>Send Funds</button>
</form>
</div>
</div>
<div class="Index-footer">
<div>
<a href="index.html">[Back]</a>
<span style="float: right">Not dispensing real Filecoin tokens</span>
</div>
</div>
</div>
</body>
</html>

View File

@ -2,19 +2,26 @@
<html>
<head>
<title>Lotus Fountain</title>
<style>
body {
font-family: 'monospace';
background: #1f1f1f;
color: #f0f0f0;
}
</style>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<form action='/send' method='get'>
<span>Enter destination address:</span>
<input type='text' name='address' style="width: 300px">
<button type='submit'>Send</button>
</form>
<div class="Index">
<div class="Index-nodes">
<div class="Index-node">
[LOTUS DEVNET FAUCET]
</div>
<div class="Index-node">
<a href="funds.html">[Send Funds]</a>
</div>
<div class="Index-node">
<a href="miner.html">[Create Miner]</a>
</div>
</div>
<div class="Index-footer">
<div>
<span style="float: right">Not dispensing real Filecoin tokens</span>
</div>
</div>
</div>
</body>
</html>

View File

@ -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;
}

View File

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<title>Creating Storage Miner - Lotus Fountain</title>
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div class="Index">
<div class="Index-nodes">
<div class="Index-node">
[CREATING STORAGE MINER]
</div>
<div class="Index-node" id="formnd">
<form id="f" action='/mkminer' method='get'>
<span>Enter destination address:</span>
<input type='text' name='address' style="width: 300px">
<button type='submit'>Create Miner</button>
</form>
</div>
<div id="plswait" style="display: none" class="Index-node">
<b>Waiting for transaction on chain..</b>
</div>
<div class="Index-node">
<span>When creating storage miner, DO NOT REFRESH THE PAGE, wait for it to load. This can take more than 5min.</span>
</div>
</div>
<div class="Index-footer">
<div>
<a href="index.html">[Back]</a>
<span style="float: right">Not dispensing real Filecoin tokens</span>
</div>
</div>
</div>
<script>
let f = document.getElementById('f')
f.onsubmit = ev => {
document.getElementById('plswait').style.display = 'block'
document.getElementById('formnd').style.display = 'none'
}
</script>
</body>
</html>

View File

@ -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,

View File

@ -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",

View File

@ -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)
}

@ -1 +1 @@
Subproject commit 32e85ba52d9ccf3fc5715bcf53265b042020ee82
Subproject commit 692725ff21919ce9c9df9ea87621b0c1e6a9746c

View File

@ -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)

3
go.mod
View File

@ -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

132
go.sum
View File

@ -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=

View File

@ -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)
}

View File

@ -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(),

View File

@ -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) {

View File

@ -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(&sectorbuilder.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 &sectorbuilder.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)
}

View File

@ -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",

View File

@ -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",

View File

@ -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 "<!nil>"
}
if (addr.length > len) {
return <abbr title={addr}>{addr.substr(0, len - 3) + '..'}</abbr>
}
@ -62,7 +67,7 @@ class Address extends React.Component {
}
openState() {
this.props.mountWindow((onClose) => <State addr={this.props.addr} actor={this.state.actor} client={this.props.client} onClose={onClose}/>)
this.props.mountWindow((onClose) => <State addr={this.props.addr} actor={this.state.actor} client={this.props.client} onClose={onClose} mountWindow={this.props.mountWindow}/>)
}
async actorInfo(actor) {
@ -117,12 +122,12 @@ class Address extends React.Component {
nonce = <span>&nbsp;<abbr title={"Next nonce"}>Nc:{this.state.nonce}</abbr>{nonce}</span>
}
let balance = <span>:&nbsp;{this.state.balance}&nbsp;</span>
let balance = <span>:&nbsp;{<Fil>{this.state.balance}</Fil>}&nbsp;</span>
if(this.props.nobalance) {
balance = <span/>
}
if(this.props.short) {
actInfo = <span/>
actInfo = <ReactTooltip id={this.props.addr} place="top" type="dark" effect="solid">{actInfo}: {<Fil>this.state.balance</Fil>}</ReactTooltip>
balance = <span/>
}
@ -136,7 +141,7 @@ class Address extends React.Component {
minerInfo = <span>&nbsp;Power: {this.state.minerInfo.MinerPower} ({this.state.minerInfo.MinerPower/this.state.minerInfo.TotalPower*100}%)</span>
}
return <span>{addr}{balance}{actInfo}{nonce}{add20k}{transfer}{minerInfo}</span>
return <span data-tip data-for={this.props.addr}>{addr}{balance}{actInfo}{nonce}{add20k}{transfer}{minerInfo}</span>
}
}

View File

@ -64,14 +64,21 @@ class Block extends React.Component {
<div>Miner: {<Address client={this.props.conn} addr={head.Miner} mountWindow={this.props.mountWindow}/>}</div>
<div>Messages: {head.Messages['/']} {/*TODO: link to message explorer */}</div>
<div>Parent Receipts: {head.ParentMessageReceipts['/']}</div>
<div>Parent State Root:&nbsp;{head.ParentStateRoot['/']}</div>
<div>
<span>Parent State Root:&nbsp;{head.ParentStateRoot['/']}</span>
<span>&nbsp;<Address client={this.props.conn} short={true} addr="t00" mountWindow={this.props.mountWindow}/></span>
<span>&nbsp;<Address client={this.props.conn} short={true} addr="t01" mountWindow={this.props.mountWindow}/></span>
<span>&nbsp;<Address client={this.props.conn} short={true} addr="t02" mountWindow={this.props.mountWindow}/></span>
<span>&nbsp;<Address client={this.props.conn} short={true} addr="t03" mountWindow={this.props.mountWindow}/></span>
<span>&nbsp;<Address client={this.props.conn} short={true} addr="t099" mountWindow={this.props.mountWindow}/></span>
</div>
<div>----</div>
<div>{messages}</div>
</div>
)
}
return (<Window className="CristalScroll" initialSize={{width: 950, height: 400}} onClose={this.props.onClose} title={`Block ${this.props.cid['/']}`}>
return (<Window className="CristalScroll" initialSize={{width: 1050, height: 400}} onClose={this.props.onClose} title={`Block ${this.props.cid['/']}`}>
{content}
</Window>)
}

View File

@ -12,7 +12,7 @@ export class BlockLinks extends React.Component {
block = this.props.blocks[k]
}
return <BlockLink key={c + '-' + k} block={block} conn={this.props.conn} cid={c} mountWindow={this.props.mountWindow}/>
return <span><BlockLink key={c + '-' + k} block={block} conn={this.props.conn} cid={c} mountWindow={this.props.mountWindow}/> </span>
})
}
}

View File

@ -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 <div key={row} className={className}>@{h} {info}</div>
})}</div>
return (<Window onClose={this.props.onClose} title={`Chain Explorer ${this.state.follow ? '(Following)' : ''}`}>
return (<Window initialSize={{width: 800}} onClose={this.props.onClose} title={`Chain Explorer ${this.state.follow ? '(Following)' : ''}`}>
{content}
</Window>)
}

View File

@ -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 = <div hidden={!this.props.pondClient}>
<span>Make Deal: </span>
<select><option>t0101</option></select>
<abbr title="Data length">L:</abbr> <input placeholder="KBs" defaultValue={1} onChange={this.update("kbs")}/>
<abbr title="Deal duration">Dur:</abbr><input placeholder="blocks" defaultValue={12} onChange={this.update("blocks")}/>
Total: <input placeholder="total price" defaultValue={36000} onChange={this.update("total")}/>
<span><abbr title="Price per block">PpB:</abbr> {ppb} </span>
<span><abbr title="Price per block-MiB">PpMbB:</abbr> {ppmbb} </span>
<div>
<span>Make Deal: </span>
<select>{this.state.miners.map(m => <option key={m} value={m}>{m}</option>)}</select>
<span> Ask: <b><Fil>{this.state.ask.Price}</Fil></b> Fil/Byte/Block</span>
</div>
<div>
Data Size: <input type="text" placeholder="KBs" defaultValue={1} onChange={this.update("kbs")} style={{width: "5em"}}/>KB;
Duration:<input type="text" placeholder="blocks" defaultValue={12} onChange={this.update("blocks")} style={{width: "5em"}}/>Blocks
</div>
<div>
Total: <Fil>{total}</Fil>; {days} Days
</div>
<button onClick={this.makeDeal}>Deal!</button>
</div>
let deals = this.state.deals.map((deal, i) => <div key={i}>
<ul>
<li>{i}. Proposal: {deal.ProposalCid['/'].substr(0, 18)}... <Address nobalance={true} client={this.props.client} addr={deal.Miner} mountWindow={this.props.mountWindow}/>: <b>{dealStates[deal.State]}</b>
<li>{i}. Proposal: {deal.ProposalCid['/'].substr(0, 18)}... <Address nobalance={true} client={this.props.client} addr={deal.Provider} mountWindow={this.props.mountWindow}/>: <b>{dealStates[deal.State]}</b>
{dealStates[deal.State] === 'Complete' ? <span>&nbsp;<a href="#" onClick={this.retrieve(deal)}>[Retrieve]</a></span> : <span/> }
<ul>
<li>Data: {deal.PieceRef['/']}, <b>{deal.Size}</b>B; Duration: <b>{deal.Duration}</b>Blocks</li>
@ -94,7 +111,7 @@ class Client extends React.Component {
</div>)
return <Window title={"Client - Node " + this.props.node.ID} onClose={this.props.onClose}>
return <Window title={"Client - Node " + this.props.node.ID} onClose={this.props.onClose} initialSize={{width: 600, height: 400}}>
<div className="Client">
<div>{dealMaker}</div>
<div>{deals}</div>

View File

@ -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:

View File

@ -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

View File

@ -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 = <div className="State">
<div>Balance: {this.state.Balance}</div>
<div>---</div>
<div>{Object.keys(this.state.State).map(k => <div key={k}>{k}: <span>{JSON.stringify(this.state.State[k])}</span></div>)}</div>
</div>
let state
if(this.byCode[this.state.code]) {
const Stelem = this.byCode[this.state.code]
state = <Stelem addr={this.props.addr} actor={this.props.actor} client={this.props.client} mountWindow={this.props.mountWindow} tipset={this.props.tipset}/>
} else {
state = <div>{Object.keys(this.state.State).map(k => <div key={k}>{k}: <span>{JSON.stringify(this.state.State[k])}</span></div>)}</div>
}
return <Window onClose={this.props.onClose} title={`Actor ${this.props.addr} @{this.props.ts.Height}`}>
const content = <div className="State">
<div>Balance: <Fil>{this.state.Balance}</Fil></div>
<div>---</div>
{state}
</div>
return <Window initialSize={{width: 850, height: 400}} onClose={this.props.onClose} title={`Actor ${this.props.addr} ${this.props.tipset && this.props.tipset.Height || ''} ${this.state.code}`}>
{content}
</Window>
}
}
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 => <div key={addr}><Address addr={addr} client={this.props.client} mountWindow={this.props.mountWindow}/></div>)
}
}
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 => <div key={addr}><Address miner={true} addr={addr} client={this.props.client} mountWindow={this.props.mountWindow}/></div>)
}
}
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 <div>
<div>
<div>Participants:</div>
<table>
<tr><td>Address</td><td>Available</td><td>Locked</td></tr>
{Object.keys(this.state.participants).map(p => <tr>
<td><Address addr={p} client={this.props.client} mountWindow={this.props.mountWindow}/></td>
<td>{this.state.participants[p].Available}</td>
<td>{this.state.participants[p].Locked}</td>
</tr>)}
</table>
</div>
<div>
<div>---</div>
<div>Deals:</div>
<table>
<tr><td>id</td><td>Active</td><td>Client</td><td>Provider</td><td>Size</td><td>Price</td><td>Duration</td></tr>
{Object.keys(this.state.deals).map(d => <tr>
<td>{d}</td>
<td>{this.state.deals[d].ActivationEpoch || "No"}</td>
<td><Address short={true} addr={this.state.deals[d].Deal.Proposal.Client} client={this.props.client} mountWindow={this.props.mountWindow}/></td>
<td><Address short={true} addr={this.state.deals[d].Deal.Proposal.Provider} client={this.props.client} mountWindow={this.props.mountWindow}/></td>
<td>{this.state.deals[d].Deal.Proposal.PieceSize}B</td>
<td>{this.state.deals[d].Deal.Proposal.StoragePricePerEpoch*this.state.deals[d].Deal.Proposal.Duration}</td>
<td>{this.state.deals[d].Deal.Proposal.Duration}</td>
</tr>)}
</table>
</div>
</div>
}
}
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 <span>(...)</span>
}
let state = this.state.state.State
return <div>
<div>Worker: <Address addr={this.state.worker} client={this.props.client} mountWindow={this.props.mountWindow}/></div>
<div>Sector Size: <b>{this.state.sectorSize/1024}</b> KiB</div>
<div>Power: <b>{state.Power}</b> (<b>{state.Power/this.state.networkPower*100}</b>%)</div>
<div>Proving Period End: <b>{state.ProvingPeriodEnd}</b></div>
<div>
<div>----</div>
<div>Sectors:</div>
<table style={{overflowY: "scroll"}}>
<thead>
<tr><td>ID</td><td>CommD</td><td>CommR</td><td>SectorSet</td><td>Proving</td></tr>
</thead>
<tbody>
{Object.keys(this.state.sectors).map(sid => <tr key={sid} style={{whiteSpace: 'nowrap'}}>
<td>{sid}</td>
<td>{this.state.sectors[sid].CommD}</td>
<td>{this.state.sectors[sid].CommR}</td>
<td>{this.state.sectors[sid].sectorSet ? 'X' : ' '}</td>
<td>{this.state.sectors[sid].provingSet ? 'X' : ' '}</td>
</tr>)}
</tbody>
</table>
</div>
</div>
}
}
export default State

View File

@ -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 {
<div>{this.state.statusCounts.map((c, i) => <span key={i}>{sealCodes[i]}: {c} | </span>)}</div>
<div>
{this.state.staged ? this.state.staged.map((s, i) => (
<div key={i}>{s.SectorID} {sealCodes[s.State]}</div>
<div key={i}>{s.SectorID} {sealCodes[s.State] || `unk ${s.State}`}</div>
)) : <div/>}
</div>

View File

@ -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",
}

View File

@ -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",

View File

@ -11,3 +11,8 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
input[type=text] {
-webkit-appearance: none;
appearance: none;
}

View File

@ -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),

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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{}

View File

@ -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 := &sectorbuilder.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 &sectorbuilder.SealTicket{
BlockHeight: ts.Height() - build.SealRandomnessLookback,
TicketBytes: tkt,
}, nil
}
}

View File

@ -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,

View File

@ -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

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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()

View File

@ -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:

Some files were not shown because too many files have changed in this diff Show More