diff --git a/README.md b/README.md index a15276ee2..d8550748d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ All work is tracked via issues. An attempt at keeping an up-to-date view on rema The main branches under development at the moment are: * [`master`](https://github.com/filecoin-project/lotus): current testnet. * [`next`](https://github.com/filecoin-project/lotus/tree/next): working branch with chain-breaking changes. -* [`interopnet`](https://github.com/filecoin-project/lotus/tree/interopnet): devnet running one of `next` commits. +* [`ntwk-calibration`](https://github.com/filecoin-project/lotus/tree/ntwk-calibration): devnet running one of `next` commits. ## License diff --git a/api/api_full.go b/api/api_full.go index 081fce0d3..6965ee818 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -367,7 +367,8 @@ type FullNode interface { PaychGet(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*ChannelInfo, error) PaychList(context.Context) ([]address.Address, error) PaychStatus(context.Context, address.Address) (*PaychStatus, error) - PaychClose(context.Context, address.Address) (cid.Cid, error) + PaychSettle(context.Context, address.Address) (cid.Cid, error) + PaychCollect(context.Context, address.Address) (cid.Cid, error) PaychAllocateLane(ctx context.Context, ch address.Address) (uint64, error) PaychNewPayment(ctx context.Context, from, to address.Address, vouchers []VoucherSpec) (*PaymentInfo, error) PaychVoucherCheckValid(context.Context, address.Address, *paych.SignedVoucher) error @@ -506,6 +507,7 @@ type QueryOffer struct { Size uint64 MinPrice types.BigInt + UnsealPrice types.BigInt PaymentInterval uint64 PaymentIntervalIncrease uint64 Miner address.Address @@ -518,6 +520,7 @@ func (o *QueryOffer) Order(client address.Address) RetrievalOrder { Piece: o.Piece, Size: o.Size, Total: o.MinPrice, + UnsealPrice: o.UnsealPrice, PaymentInterval: o.PaymentInterval, PaymentIntervalIncrease: o.PaymentIntervalIncrease, Client: client, @@ -544,6 +547,7 @@ type RetrievalOrder struct { Size uint64 // TODO: support offset Total types.BigInt + UnsealPrice types.BigInt PaymentInterval uint64 PaymentIntervalIncrease uint64 Client address.Address diff --git a/api/api_storage.go b/api/api_storage.go index 321380157..7e6d81b21 100644 --- a/api/api_storage.go +++ b/api/api_storage.go @@ -61,6 +61,7 @@ type StorageMiner interface { // WorkerConnect tells the node to connect to workers RPC WorkerConnect(context.Context, string) error WorkerStats(context.Context) (map[uint64]storiface.WorkerStats, error) + WorkerJobs(context.Context) (map[uint64][]storiface.WorkerJob, error) stores.SectorIndex diff --git a/api/apistruct/struct.go b/api/apistruct/struct.go index 665024858..6b41fa9dd 100644 --- a/api/apistruct/struct.go +++ b/api/apistruct/struct.go @@ -180,7 +180,8 @@ type FullNodeStruct struct { PaychGet func(ctx context.Context, from, to address.Address, ensureFunds types.BigInt) (*api.ChannelInfo, error) `perm:"sign"` PaychList func(context.Context) ([]address.Address, error) `perm:"read"` PaychStatus func(context.Context, address.Address) (*api.PaychStatus, error) `perm:"read"` - PaychClose func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` + PaychSettle func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` + PaychCollect func(context.Context, address.Address) (cid.Cid, error) `perm:"sign"` PaychAllocateLane func(context.Context, address.Address) (uint64, error) `perm:"sign"` PaychNewPayment func(ctx context.Context, from, to address.Address, vouchers []api.VoucherSpec) (*api.PaymentInfo, error) `perm:"sign"` PaychVoucherCheck func(context.Context, *paych.SignedVoucher) error `perm:"read"` @@ -228,6 +229,7 @@ type StorageMinerStruct struct { WorkerConnect func(context.Context, string) error `perm:"admin"` // TODO: worker perm WorkerStats func(context.Context) (map[uint64]storiface.WorkerStats, error) `perm:"admin"` + WorkerJobs func(context.Context) (map[uint64][]storiface.WorkerJob, error) `perm:"admin"` StorageList func(context.Context) (map[stores.ID][]stores.Decl, error) `perm:"admin"` StorageLocal func(context.Context) (map[stores.ID]string, error) `perm:"admin"` @@ -804,8 +806,12 @@ func (c *FullNodeStruct) PaychVoucherList(ctx context.Context, pch address.Addre return c.Internal.PaychVoucherList(ctx, pch) } -func (c *FullNodeStruct) PaychClose(ctx context.Context, a address.Address) (cid.Cid, error) { - return c.Internal.PaychClose(ctx, a) +func (c *FullNodeStruct) PaychSettle(ctx context.Context, a address.Address) (cid.Cid, error) { + return c.Internal.PaychSettle(ctx, a) +} + +func (c *FullNodeStruct) PaychCollect(ctx context.Context, a address.Address) (cid.Cid, error) { + return c.Internal.PaychCollect(ctx, a) } func (c *FullNodeStruct) PaychAllocateLane(ctx context.Context, ch address.Address) (uint64, error) { @@ -892,6 +898,10 @@ func (c *StorageMinerStruct) WorkerStats(ctx context.Context) (map[uint64]storif return c.Internal.WorkerStats(ctx) } +func (c *StorageMinerStruct) WorkerJobs(ctx context.Context) (map[uint64][]storiface.WorkerJob, error) { + return c.Internal.WorkerJobs(ctx) +} + func (c *StorageMinerStruct) StorageAttach(ctx context.Context, si stores.StorageInfo, st fsutil.FsStat) error { return c.Internal.StorageAttach(ctx, si, st) } diff --git a/api/test/paych.go b/api/test/paych.go new file mode 100644 index 000000000..da0a803e5 --- /dev/null +++ b/api/test/paych.go @@ -0,0 +1,286 @@ +package test + +import ( + "bytes" + "context" + "fmt" + "os" + "sync/atomic" + "testing" + "time" + + "github.com/filecoin-project/lotus/api" + "github.com/ipfs/go-cid" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/events/state" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/wallet" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + initactor "github.com/filecoin-project/specs-actors/actors/builtin/init" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" +) + +func TestPaymentChannels(t *testing.T, b APIBuilder, blocktime time.Duration) { + _ = os.Setenv("BELLMAN_NO_GPU", "1") + + ctx := context.Background() + n, sn := b(t, 2, oneMiner) + + paymentCreator := n[0] + paymentReceiver := n[1] + miner := sn[0] + + // get everyone connected + addrs, err := paymentCreator.NetAddrsListen(ctx) + if err != nil { + t.Fatal(err) + } + + if err := paymentReceiver.NetConnect(ctx, addrs); err != nil { + t.Fatal(err) + } + + if err := miner.NetConnect(ctx, addrs); err != nil { + t.Fatal(err) + } + + // start mining blocks + bm := newBlockMiner(ctx, t, miner, blocktime) + bm.mineBlocks() + + // send some funds to register the receiver + receiverAddr, err := paymentReceiver.WalletNew(ctx, wallet.ActSigType("secp256k1")) + if err != nil { + t.Fatal(err) + } + + sendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e10)) + + // setup the payment channel + createrAddr, err := paymentCreator.WalletDefaultAddress(ctx) + if err != nil { + t.Fatal(err) + } + + channelAmt := int64(100000) + channelInfo, err := paymentCreator.PaychGet(ctx, createrAddr, receiverAddr, abi.NewTokenAmount(channelAmt)) + if err != nil { + t.Fatal(err) + } + + res := waitForMessage(ctx, t, paymentCreator, channelInfo.ChannelMessage, time.Second, "channel create") + var params initactor.ExecReturn + err = params.UnmarshalCBOR(bytes.NewReader(res.Receipt.Return)) + if err != nil { + t.Fatal(err) + } + channel := params.RobustAddress + + // allocate three lanes + var lanes []uint64 + for i := 0; i < 3; i++ { + lane, err := paymentCreator.PaychAllocateLane(ctx, channel) + if err != nil { + t.Fatal(err) + } + lanes = append(lanes, lane) + } + + // Make two vouchers each for each lane, then save on the other side + // Note that the voucher with a value of 2000 has a higher nonce, so it + // supersedes the voucher with a value of 1000 + for _, lane := range lanes { + vouch1, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(1000), lane) + if err != nil { + t.Fatal(err) + } + vouch2, err := paymentCreator.PaychVoucherCreate(ctx, channel, abi.NewTokenAmount(2000), lane) + if err != nil { + t.Fatal(err) + } + delta1, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch1, nil, abi.NewTokenAmount(1000)) + if err != nil { + t.Fatal(err) + } + if !delta1.Equals(abi.NewTokenAmount(1000)) { + t.Fatal("voucher didn't have the right amount") + } + delta2, err := paymentReceiver.PaychVoucherAdd(ctx, channel, vouch2, nil, abi.NewTokenAmount(1000)) + if err != nil { + t.Fatal(err) + } + if !delta2.Equals(abi.NewTokenAmount(1000)) { + t.Fatal("voucher didn't have the right amount") + } + } + + // settle the payment channel + settleMsgCid, err := paymentCreator.PaychSettle(ctx, channel) + if err != nil { + t.Fatal(err) + } + + res = waitForMessage(ctx, t, paymentCreator, settleMsgCid, time.Second*10, "settle") + if res.Receipt.ExitCode != 0 { + t.Fatal("Unable to settle payment channel") + } + + creatorPreCollectBalance, err := paymentCreator.WalletBalance(ctx, createrAddr) + if err != nil { + t.Fatal(err) + } + + // wait for the receiver to submit their vouchers + ev := events.NewEvents(ctx, paymentCreator) + preds := state.NewStatePredicates(paymentCreator) + finished := make(chan struct{}) + err = ev.StateChanged(func(ts *types.TipSet) (done bool, more bool, err error) { + act, err := paymentCreator.StateReadState(ctx, channel, ts.Key()) + if err != nil { + return false, false, err + } + state := act.State.(paych.State) + if state.ToSend.GreaterThanEqual(abi.NewTokenAmount(6000)) { + return true, false, nil + } + return false, true, nil + }, func(oldTs, newTs *types.TipSet, states events.StateChange, curH abi.ChainEpoch) (more bool, err error) { + toSendChange := states.(*state.PayChToSendChange) + if toSendChange.NewToSend.GreaterThanEqual(abi.NewTokenAmount(6000)) { + close(finished) + return false, nil + } + return true, nil + }, func(ctx context.Context, ts *types.TipSet) error { + return nil + }, int(build.MessageConfidence)+1, build.SealRandomnessLookbackLimit, func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) { + return preds.OnPaymentChannelActorChanged(channel, preds.OnToSendAmountChanges())(ctx, oldTs.Key(), newTs.Key()) + }) + + select { + case <-finished: + case <-time.After(time.Second): + t.Fatal("Timed out waiting for receiver to submit vouchers") + } + + // collect funds (from receiver, though either party can do it) + collectMsg, err := paymentReceiver.PaychCollect(ctx, channel) + if err != nil { + t.Fatal(err) + } + res, err = paymentReceiver.StateWaitMsg(ctx, collectMsg, 1) + if err != nil { + t.Fatal(err) + } + if res.Receipt.ExitCode != 0 { + t.Fatal("unable to collect on payment channel") + } + + // Finally, check the balance for the creator + currentCreatorBalance, err := paymentCreator.WalletBalance(ctx, createrAddr) + if err != nil { + t.Fatal(err) + } + + // The highest nonce voucher that the creator sent on each lane is 2000 + totalVouchers := int64(len(lanes) * 2000) + // When receiver submits the tokens to the chain, creator should get a + // refund on the remaining balance, which is + // channel amount - total voucher value + expectedRefund := channelAmt - totalVouchers + delta := big.Sub(currentCreatorBalance, creatorPreCollectBalance) + if !delta.Equals(abi.NewTokenAmount(expectedRefund)) { + t.Fatalf("did not send correct funds from creator: expected %d, got %d", expectedRefund, delta) + } + + // shut down mining + bm.stop() +} + +func waitForMessage(ctx context.Context, t *testing.T, paymentCreator TestNode, msgCid cid.Cid, duration time.Duration, desc string) *api.MsgLookup { + ctx, cancel := context.WithTimeout(ctx, duration) + defer cancel() + + fmt.Println("Waiting for", desc) + res, err := paymentCreator.StateWaitMsg(ctx, msgCid, 1) + if err != nil { + fmt.Println("Error waiting for", desc, err) + t.Fatal(err) + } + if res.Receipt.ExitCode != 0 { + t.Fatalf("did not successfully send %s", desc) + } + fmt.Println("Confirmed", desc) + return res +} + +type blockMiner struct { + ctx context.Context + t *testing.T + miner TestStorageNode + blocktime time.Duration + mine int64 + done chan struct{} +} + +func newBlockMiner(ctx context.Context, t *testing.T, miner TestStorageNode, blocktime time.Duration) *blockMiner { + return &blockMiner{ + ctx: ctx, + t: t, + miner: miner, + blocktime: blocktime, + mine: int64(1), + done: make(chan struct{}), + } +} + +func (bm *blockMiner) mineBlocks() { + time.Sleep(time.Second) + go func() { + defer close(bm.done) + for atomic.LoadInt64(&bm.mine) == 1 { + time.Sleep(bm.blocktime) + if err := bm.miner.MineOne(bm.ctx, func(bool, error) {}); err != nil { + bm.t.Error(err) + } + } + }() +} + +func (bm *blockMiner) stop() { + atomic.AddInt64(&bm.mine, -1) + fmt.Println("shutting down mining") + <-bm.done +} + +func sendFunds(ctx context.Context, t *testing.T, sender TestNode, addr address.Address, amount abi.TokenAmount) { + + senderAddr, err := sender.WalletDefaultAddress(ctx) + if err != nil { + t.Fatal(err) + } + + msg := &types.Message{ + From: senderAddr, + To: addr, + Value: amount, + GasLimit: 0, + GasPrice: abi.NewTokenAmount(0), + } + + sm, err := sender.MpoolPushMessage(ctx, msg) + if err != nil { + t.Fatal(err) + } + res, err := sender.StateWaitMsg(ctx, sm.Cid(), 1) + if err != nil { + t.Fatal(err) + } + if res.Receipt.ExitCode != 0 { + t.Fatal("did not successfully send money") + } +} diff --git a/api/test/window_post.go b/api/test/window_post.go index 03cc9535d..074ba2fbb 100644 --- a/api/test/window_post.go +++ b/api/test/window_post.go @@ -175,7 +175,65 @@ func TestWindowPost(t *testing.T, b APIBuilder, blocktime time.Duration, nSector require.Equal(t, p.MinerPower, p.TotalPower) require.Equal(t, p.MinerPower.RawBytePower, types.NewInt(uint64(ssz)*uint64(nSectors+GenesisPreseals))) - // TODO: Inject faults here + // Drop 2 sectors from deadline 2 partition 0 (full partition / deadline) + { + parts, err := client.StateMinerPartitions(ctx, maddr, 2, types.EmptyTSK) + require.NoError(t, err) + require.Greater(t, len(parts), 0) + + n, err := parts[0].Sectors.Count() + require.NoError(t, err) + require.Equal(t, uint64(2), n) + + // Drop the partition + err = parts[0].Sectors.ForEach(func(sid uint64) error { + return miner.SectorRemove(ctx, abi.SectorNumber(sid)) + }) + require.NoError(t, err) + } + + // Drop 1 sectors from deadline 3 partition 0 + { + parts, err := client.StateMinerPartitions(ctx, maddr, 3, types.EmptyTSK) + require.NoError(t, err) + require.Greater(t, len(parts), 0) + + n, err := parts[0].Sectors.Count() + require.NoError(t, err) + require.Equal(t, uint64(2), n) + + // Drop the sector + s, err := parts[0].Sectors.First() + require.NoError(t, err) + + err = miner.SectorRemove(ctx, abi.SectorNumber(s)) + require.NoError(t, err) + } + + di, err = client.StateMinerProvingDeadline(ctx, maddr, types.EmptyTSK) + require.NoError(t, err) + + for { + head, err := client.ChainHead(ctx) + require.NoError(t, err) + + if head.Height() > di.PeriodStart+(miner2.WPoStProvingPeriod)+2 { + break + } + + if head.Height()%100 == 0 { + fmt.Printf("@%d\n", head.Height()) + } + build.Clock.Sleep(blocktime) + } + + p, err = client.StateMinerPower(ctx, maddr, types.EmptyTSK) + require.NoError(t, err) + + require.Equal(t, p.MinerPower, p.TotalPower) + + sectors := p.MinerPower.RawBytePower.Uint64() / uint64(ssz) + require.Equal(t, nSectors+GenesisPreseals - 3, int(sectors)) // -3 just removed sectors mine = false <-done diff --git a/build/bootstrap.go b/build/bootstrap.go index 6343a0172..80c1529ff 100644 --- a/build/bootstrap.go +++ b/build/bootstrap.go @@ -38,12 +38,3 @@ func BuiltinBootstrap() ([]peer.AddrInfo, error) { }) return out, err } - -func DrandBootstrap() ([]peer.AddrInfo, error) { - addrs := []string{ - "/dnsaddr/pl-eu.testnet.drand.sh/", - "/dnsaddr/pl-us.testnet.drand.sh/", - "/dnsaddr/pl-sin.testnet.drand.sh/", - } - return addrutil.ParseAddresses(context.TODO(), addrs) -} diff --git a/build/drand.go b/build/drand.go new file mode 100644 index 000000000..e24b802d6 --- /dev/null +++ b/build/drand.go @@ -0,0 +1,58 @@ +package build + +import "github.com/filecoin-project/lotus/node/modules/dtypes" + +var DrandNetwork = DrandTestnet + +func DrandConfig() dtypes.DrandConfig { + return DrandConfigs[DrandNetwork] +} + +type DrandEnum int + +const ( + DrandMainnet DrandEnum = iota + 1 + DrandTestnet + DrandDevnet + DrandLocalnet +) + +var DrandConfigs = map[DrandEnum]dtypes.DrandConfig{ + DrandMainnet: { + Servers: []string{ + "https://api.drand.sh", + "https://api2.drand.sh", + "https://api3.drand.sh", + }, + Relays: []string{ + "/dnsaddr/api.drand.sh/", + "/dnsaddr/api2.drand.sh/", + "/dnsaddr/api3.drand.sh/", + }, + ChainInfoJSON: `{"public_key":"868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31","period":30,"genesis_time":1595431050,"hash":"8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce","groupHash":"176f93498eac9ca337150b46d21dd58673ea4e3581185f869672e59fa4cb390a"}`, + }, + DrandTestnet: { + Servers: []string{ + "https://pl-eu.testnet.drand.sh", + "https://pl-us.testnet.drand.sh", + "https://pl-sin.testnet.drand.sh", + }, + Relays: []string{ + "/dnsaddr/pl-eu.testnet.drand.sh/", + "/dnsaddr/pl-us.testnet.drand.sh/", + "/dnsaddr/pl-sin.testnet.drand.sh/", + }, + ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"84b2234fb34e835dccd048255d7ad3194b81af7d978c3bf157e3469592ae4e02","groupHash":"4dd408e5fdff9323c76a9b6f087ba8fdc5a6da907bd9217d9d10f2287d081957"}`, + }, + DrandDevnet: { + Servers: []string{ + "https://dev1.drand.sh", + "https://dev2.drand.sh", + }, + Relays: []string{ + "/dnsaddr/dev1.drand.sh/", + "/dnsaddr/dev2.drand.sh/", + }, + ChainInfoJSON: `{"public_key":"8cda589f88914aa728fd183f383980b35789ce81b274e5daee1f338b77d02566ef4d3fb0098af1f844f10f9c803c1827","period":25,"genesis_time":1595348225,"hash":"e73b7dc3c4f6a236378220c0dd6aa110eb16eed26c11259606e07ee122838d4f","groupHash":"567d4785122a5a3e75a9bc9911d7ea807dd85ff76b78dc4ff06b075712898607"}`, + }, +} diff --git a/build/params_shared_vals.go b/build/params_shared_vals.go index bba5aa6eb..4ecb31054 100644 --- a/build/params_shared_vals.go +++ b/build/params_shared_vals.go @@ -8,8 +8,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" - - "github.com/filecoin-project/lotus/node/modules/dtypes" ) // ///// @@ -92,12 +90,3 @@ const VerifSigCacheSize = 32000 // TODO: If this is gonna stay, it should move to specs-actors const BlockMessageLimit = 512 const BlockGasLimit = 7_500_000_000 - -var DrandConfig = dtypes.DrandConfig{ - Servers: []string{ - "https://pl-eu.testnet.drand.sh", - "https://pl-us.testnet.drand.sh", - "https://pl-sin.testnet.drand.sh", - }, - ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"84b2234fb34e835dccd048255d7ad3194b81af7d978c3bf157e3469592ae4e02","groupHash":"4dd408e5fdff9323c76a9b6f087ba8fdc5a6da907bd9217d9d10f2287d081957"}`, -} diff --git a/build/params_testground.go b/build/params_testground.go index 1b81ebae3..ab7c16436 100644 --- a/build/params_testground.go +++ b/build/params_testground.go @@ -10,8 +10,6 @@ package build import ( "math/big" - "github.com/filecoin-project/lotus/node/modules/dtypes" - "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/miner" @@ -61,13 +59,4 @@ var ( v = v.Mul(v, big.NewInt(int64(FilecoinPrecision))) return v }() - - DrandConfig = dtypes.DrandConfig{ - Servers: []string{ - "https://pl-eu.testnet.drand.sh", - "https://pl-us.testnet.drand.sh", - "https://pl-sin.testnet.drand.sh", - }, - ChainInfoJSON: `{"public_key":"922a2e93828ff83345bae533f5172669a26c02dc76d6bf59c80892e12ab1455c229211886f35bb56af6d5bea981024df","period":25,"genesis_time":1590445175,"hash":"138a324aa6540f93d0dad002aa89454b1bec2b6e948682cde6bd4db40f4b7c9b"}`, - } ) diff --git a/chain/beacon/drand/drand_test.go b/chain/beacon/drand/drand_test.go index d7d9c4d18..8d7c1b2cc 100644 --- a/chain/beacon/drand/drand_test.go +++ b/chain/beacon/drand/drand_test.go @@ -12,7 +12,7 @@ import ( ) func TestPrintGroupInfo(t *testing.T) { - server := build.DrandConfig.Servers[0] + server := build.DrandConfig().Servers[0] c, err := hclient.New(server, nil, nil) assert.NoError(t, err) cg := c.(interface { diff --git a/chain/events/state/predicates.go b/chain/events/state/predicates.go index ce1bb6dd8..59f18753d 100644 --- a/chain/events/state/predicates.go +++ b/chain/events/state/predicates.go @@ -3,6 +3,7 @@ package state import ( "bytes" "context" + "github.com/filecoin-project/go-address" "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" @@ -12,6 +13,7 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api/apibstore" @@ -493,3 +495,40 @@ func (sp *StatePredicates) OnMinerPreCommitChange() DiffMinerActorStateFunc { return true, precommitChanges, nil } } + +// DiffPaymentChannelStateFunc is function that compares two states for the payment channel +type DiffPaymentChannelStateFunc func(ctx context.Context, oldState *paych.State, newState *paych.State) (changed bool, user UserData, err error) + +// OnPaymentChannelActorChanged calls diffPaymentChannelState when the state changes for the the payment channel actor +func (sp *StatePredicates) OnPaymentChannelActorChanged(paychAddr address.Address, diffPaymentChannelState DiffPaymentChannelStateFunc) DiffTipSetKeyFunc { + return sp.OnActorStateChanged(paychAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) { + var oldState paych.State + if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil { + return false, nil, err + } + var newState paych.State + if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil { + return false, nil, err + } + return diffPaymentChannelState(ctx, &oldState, &newState) + }) +} + +// PayChToSendChange is a difference in the amount to send on a payment channel when the money is collected +type PayChToSendChange struct { + OldToSend abi.TokenAmount + NewToSend abi.TokenAmount +} + +// OnToSendAmountChanges monitors changes on the total amount to send from one party to the other on a payment channel +func (sp *StatePredicates) OnToSendAmountChanges() DiffPaymentChannelStateFunc { + return func(ctx context.Context, oldState *paych.State, newState *paych.State) (changed bool, user UserData, err error) { + if oldState.ToSend.Equals(newState.ToSend) { + return false, nil, nil + } + return true, &PayChToSendChange{ + OldToSend: oldState.ToSend, + NewToSend: newState.ToSend, + }, nil + } +} diff --git a/chain/events/state/predicates_test.go b/chain/events/state/predicates_test.go index e549a71be..4592cce57 100644 --- a/chain/events/state/predicates_test.go +++ b/chain/events/state/predicates_test.go @@ -10,12 +10,10 @@ import ( "github.com/ipfs/go-cid" ds "github.com/ipfs/go-datastore" ds_sync "github.com/ipfs/go-datastore/sync" - "github.com/ipfs/go-hamt-ipld" bstore "github.com/ipfs/go-ipfs-blockstore" cbornode "github.com/ipfs/go-ipld-cbor" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-amt-ipld/v2" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/market" @@ -69,7 +67,7 @@ func (m mockAPI) setActor(tsk types.TipSetKey, act *types.Actor) { func TestMarketPredicates(t *testing.T) { ctx := context.Background() bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore())) - store := cbornode.NewCborStore(bs) + store := adt.WrapStore(ctx, cbornode.NewCborStore(bs)) oldDeal1 := &market.DealState{ SectorStartEpoch: 1, @@ -284,7 +282,7 @@ func TestMarketPredicates(t *testing.T) { func TestMinerSectorChange(t *testing.T) { ctx := context.Background() bs := bstore.NewBlockstore(ds_sync.MutexWrap(ds.NewMapDatastore())) - store := cbornode.NewCborStore(bs) + store := adt.WrapStore(ctx, cbornode.NewCborStore(bs)) nextID := uint64(0) nextIDAddrF := func() address.Address { @@ -376,7 +374,7 @@ func mockTipset(minerAddr address.Address, timestamp uint64) (*types.TipSet, err }}) } -func createMarketState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState, props map[abi.DealID]*market.DealProposal) cid.Cid { +func createMarketState(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market.DealState, props map[abi.DealID]*market.DealProposal) cid.Cid { dealRootCid := createDealAMT(ctx, t, store, deals) propRootCid := createProposalAMT(ctx, t, store, props) @@ -389,37 +387,37 @@ func createMarketState(ctx context.Context, t *testing.T, store *cbornode.BasicI return stateC } -func createEmptyMarketState(t *testing.T, store *cbornode.BasicIpldStore) *market.State { - emptyArrayCid, err := amt.NewAMT(store).Flush(context.TODO()) +func createEmptyMarketState(t *testing.T, store adt.Store) *market.State { + emptyArrayCid, err := adt.MakeEmptyArray(store).Root() require.NoError(t, err) - emptyMap, err := store.Put(context.TODO(), hamt.NewNode(store, hamt.UseTreeBitWidth(5))) + emptyMap, err := adt.MakeEmptyMap(store).Root() require.NoError(t, err) return market.ConstructState(emptyArrayCid, emptyMap, emptyMap) } -func createDealAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, deals map[abi.DealID]*market.DealState) cid.Cid { - root := amt.NewAMT(store) +func createDealAMT(ctx context.Context, t *testing.T, store adt.Store, deals map[abi.DealID]*market.DealState) cid.Cid { + root := adt.MakeEmptyArray(store) for dealID, dealState := range deals { - err := root.Set(ctx, uint64(dealID), dealState) + err := root.Set(uint64(dealID), dealState) require.NoError(t, err) } - rootCid, err := root.Flush(ctx) + rootCid, err := root.Root() require.NoError(t, err) return rootCid } -func createProposalAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, props map[abi.DealID]*market.DealProposal) cid.Cid { - root := amt.NewAMT(store) +func createProposalAMT(ctx context.Context, t *testing.T, store adt.Store, props map[abi.DealID]*market.DealProposal) cid.Cid { + root := adt.MakeEmptyArray(store) for dealID, prop := range props { - err := root.Set(ctx, uint64(dealID), prop) + err := root.Set(uint64(dealID), prop) require.NoError(t, err) } - rootCid, err := root.Flush(ctx) + rootCid, err := root.Root() require.NoError(t, err) return rootCid } -func createMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, owner, worker address.Address, sectors []miner.SectorOnChainInfo) cid.Cid { +func createMinerState(ctx context.Context, t *testing.T, store adt.Store, owner, worker address.Address, sectors []miner.SectorOnChainInfo) cid.Cid { rootCid := createSectorsAMT(ctx, t, store, sectors) state := createEmptyMinerState(ctx, t, store, owner, worker) @@ -430,10 +428,10 @@ func createMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIp return stateC } -func createEmptyMinerState(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, owner, worker address.Address) *miner.State { - emptyArrayCid, err := amt.NewAMT(store).Flush(context.TODO()) +func createEmptyMinerState(ctx context.Context, t *testing.T, store adt.Store, owner, worker address.Address) *miner.State { + emptyArrayCid, err := adt.MakeEmptyArray(store).Root() require.NoError(t, err) - emptyMap, err := store.Put(context.TODO(), hamt.NewNode(store, hamt.UseTreeBitWidth(5))) + emptyMap, err := adt.MakeEmptyMap(store).Root() require.NoError(t, err) emptyDeadline, err := store.Put(context.TODO(), &miner.Deadline{ @@ -457,14 +455,14 @@ func createEmptyMinerState(ctx context.Context, t *testing.T, store *cbornode.Ba } -func createSectorsAMT(ctx context.Context, t *testing.T, store *cbornode.BasicIpldStore, sectors []miner.SectorOnChainInfo) cid.Cid { - root := amt.NewAMT(store) +func createSectorsAMT(ctx context.Context, t *testing.T, store adt.Store, sectors []miner.SectorOnChainInfo) cid.Cid { + root := adt.MakeEmptyArray(store) for _, sector := range sectors { sector := sector - err := root.Set(ctx, uint64(sector.SectorNumber), §or) + err := root.Set(uint64(sector.SectorNumber), §or) require.NoError(t, err) } - rootCid, err := root.Flush(ctx) + rootCid, err := root.Root() require.NoError(t, err) return rootCid } diff --git a/chain/gen/gen.go b/chain/gen/gen.go index 4d535b5f4..898dda7b8 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -378,6 +378,10 @@ func (cg *ChainGen) NextTipSet() (*MinedTipSet, error) { return mts, nil } +func (cg *ChainGen) SetWinningPoStProver(m address.Address, wpp WinningPoStProver) { + cg.eppProvs[m] = wpp +} + func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Address) (*MinedTipSet, error) { var blks []*types.FullBlock diff --git a/chain/gen/genesis/genesis.go b/chain/gen/genesis/genesis.go index 9bcbce03a..0c22761eb 100644 --- a/chain/gen/genesis/genesis.go +++ b/chain/gen/genesis/genesis.go @@ -4,15 +4,6 @@ import ( "context" "encoding/json" - "github.com/filecoin-project/go-amt-ipld/v2" - "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/abi/big" - "github.com/filecoin-project/specs-actors/actors/builtin" - "github.com/filecoin-project/specs-actors/actors/builtin/account" - "github.com/filecoin-project/specs-actors/actors/builtin/multisig" - "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" "github.com/ipfs/go-datastore" bstore "github.com/ipfs/go-ipfs-blockstore" @@ -22,11 +13,21 @@ import ( "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/abi/big" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/account" + "github.com/filecoin-project/specs-actors/actors/builtin/multisig" + "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/util/adt" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/genesis" + "github.com/filecoin-project/lotus/lib/sigs" ) const AccountStart = 100 @@ -224,6 +225,43 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge return nil, err } + // Setup the first verifier as ID-address 81 + // TODO: remove this + skBytes, err := sigs.Generate(crypto.SigTypeBLS) + if err != nil { + return nil, xerrors.Errorf("creating random verifier secret key: %w", err) + } + + verifierPk, err := sigs.ToPublic(crypto.SigTypeBLS, skBytes) + if err != nil { + return nil, xerrors.Errorf("creating random verifier public key: %w", err) + } + + verifierAd, err := address.NewBLSAddress(verifierPk) + if err != nil { + return nil, xerrors.Errorf("creating random verifier address: %w", err) + } + + verifierId, err := address.NewIDAddress(81) + if err != nil { + return nil, err + } + + verifierState, err := cst.Put(ctx, &account.State{Address: verifierAd}) + if err != nil { + return nil, err + } + + err = state.SetActor(verifierId, &types.Actor{ + Code: builtin.AccountActorCodeID, + Balance: types.NewInt(0), + Head: verifierState, + }) + + if err != nil { + return nil, xerrors.Errorf("setting account from actmap: %w", err) + } + return state, nil } @@ -254,14 +292,14 @@ func createAccount(ctx context.Context, bs bstore.Blockstore, cst cbor.IpldStore if err != nil { return xerrors.Errorf("failed to create empty map: %v", err) } - + st, err := cst.Put(ctx, &multisig.State{ - Signers: ainfo.Signers, + Signers: ainfo.Signers, NumApprovalsThreshold: uint64(ainfo.Threshold), - StartEpoch: abi.ChainEpoch(ainfo.VestingStart), - UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration), - PendingTxns: pending, - InitialBalance: info.Balance, + StartEpoch: abi.ChainEpoch(ainfo.VestingStart), + UnlockDuration: abi.ChainEpoch(ainfo.VestingDuration), + PendingTxns: pending, + InitialBalance: info.Balance, }) if err != nil { return err @@ -290,17 +328,22 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci } } - verifier, err := address.NewIDAddress(80) + verifregRoot, err := address.NewIDAddress(80) if err != nil { return cid.Undef, err } - vm, err := vm.NewVM(stateroot, 0, &fakeRand{}, cs.Blockstore(), &fakedSigSyscalls{cs.VMSys()}) + verifier, err := address.NewIDAddress(81) + if err != nil { + return cid.Undef, err + } + + vm, err := vm.NewVM(stateroot, 0, &fakeRand{}, cs.Blockstore(), mkFakedSigSyscalls(cs.VMSys())) if err != nil { return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) } - _, err = doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, verifier, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifier, mustEnc(&verifreg.AddVerifierParams{ + _, err = doExecValue(ctx, vm, builtin.VerifiedRegistryActorAddr, verifregRoot, types.NewInt(0), builtin.MethodsVerifiedRegistry.AddVerifier, mustEnc(&verifreg.AddVerifierParams{ Address: verifier, Allowance: abi.NewStoragePower(int64(sum)), // eh, close enough @@ -327,7 +370,7 @@ func VerifyPreSealedData(ctx context.Context, cs *store.ChainStore, stateroot ci return st, nil } -func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Syscalls, template genesis.Template) (*GenesisBootstrap, error) { +func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys vm.SyscallBuilder, template genesis.Template) (*GenesisBootstrap, error) { st, err := MakeInitialStateTree(ctx, bs, template) if err != nil { return nil, xerrors.Errorf("make initial state tree failed: %w", err) @@ -352,9 +395,8 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Sys return nil, xerrors.Errorf("setup miners failed: %w", err) } - cst := cbor.NewCborStore(bs) - - emptyroot, err := amt.FromArray(ctx, cst, nil) + store := adt.WrapStore(ctx, cbor.NewCborStore(bs)) + emptyroot, err := adt.MakeEmptyArray(store).Root() if err != nil { return nil, xerrors.Errorf("amt build failed: %w", err) } diff --git a/chain/gen/genesis/miners.go b/chain/gen/genesis/miners.go index be2dbbefe..a0f0ee4b1 100644 --- a/chain/gen/genesis/miners.go +++ b/chain/gen/genesis/miners.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "github.com/filecoin-project/lotus/chain/state" "math/rand" "github.com/ipfs/go-cid" @@ -46,8 +47,16 @@ func (fss *fakedSigSyscalls) VerifySignature(signature crypto.Signature, signer return nil } +func mkFakedSigSyscalls(base vm.SyscallBuilder) vm.SyscallBuilder { + return func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls { + return &fakedSigSyscalls{ + base(ctx, cstate, cst), + } + } +} + func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid, miners []genesis.Miner) (cid.Cid, error) { - vm, err := vm.NewVM(sroot, 0, &fakeRand{}, cs.Blockstore(), &fakedSigSyscalls{cs.VMSys()}) + vm, err := vm.NewVM(sroot, 0, &fakeRand{}, cs.Blockstore(), mkFakedSigSyscalls(cs.VMSys())) if err != nil { return cid.Undef, xerrors.Errorf("failed to create NewVM: %w", err) } diff --git a/chain/gen/genesis/t01_init.go b/chain/gen/genesis/t01_init.go index 62f892c47..44d55b1d4 100644 --- a/chain/gen/genesis/t01_init.go +++ b/chain/gen/genesis/t01_init.go @@ -6,11 +6,12 @@ import ( "fmt" "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/util/adt" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" - "github.com/ipfs/go-hamt-ipld" bstore "github.com/ipfs/go-ipfs-blockstore" cbor "github.com/ipfs/go-ipld-cbor" + cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/chain/types" @@ -26,8 +27,8 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi ias.NextID = MinerStart ias.NetworkName = netname - cst := cbor.NewCborStore(bs) - amap := hamt.NewNode(cst, hamt.UseTreeBitWidth(5)) // TODO: use spec adt map + store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs)) + amap := adt.MakeEmptyMap(store) for i, a := range initialActors { if a.Type == genesis.TMultisig { @@ -43,9 +44,10 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi return nil, xerrors.Errorf("unmarshaling account meta: %w", err) } - fmt.Printf("init set %s t0%d\n", ainfo.Owner, AccountStart+uint64(i)) + fmt.Printf("init set %s t0%d\n", ainfo.Owner, AccountStart+int64(i)) - if err := amap.Set(context.TODO(), string(ainfo.Owner.Bytes()), AccountStart+uint64(i)); err != nil { + value := cbg.CborInt(AccountStart + int64(i)) + if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil { return nil, err } } @@ -55,22 +57,19 @@ func SetupInitActor(bs bstore.Blockstore, netname string, initialActors []genesi if err := json.Unmarshal(rootVerifier.Meta, &ainfo); err != nil { return nil, xerrors.Errorf("unmarshaling account meta: %w", err) } - if err := amap.Set(context.TODO(), string(ainfo.Owner.Bytes()), 80); err != nil { + value := cbg.CborInt(80) + if err := amap.Put(adt.AddrKey(ainfo.Owner), &value); err != nil { return nil, err } } - if err := amap.Flush(context.TODO()); err != nil { - return nil, err - } - amapcid, err := cst.Put(context.TODO(), amap) + amapaddr, err := amap.Root() if err != nil { return nil, err } + ias.AddressMap = amapaddr - ias.AddressMap = amapcid - - statecid, err := cst.Put(context.TODO(), &ias) + statecid, err := store.Put(store.Context(), &ias) if err != nil { return nil, err } diff --git a/chain/gen/genesis/t04_power.go b/chain/gen/genesis/t04_power.go index 89ee95a6b..b20045ca3 100644 --- a/chain/gen/genesis/t04_power.go +++ b/chain/gen/genesis/t04_power.go @@ -2,11 +2,12 @@ package genesis import ( "context" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/filecoin-project/specs-actors/actors/builtin/power" - "github.com/ipfs/go-hamt-ipld" bstore "github.com/ipfs/go-ipfs-blockstore" cbor "github.com/ipfs/go-ipld-cbor" @@ -14,10 +15,8 @@ import ( ) func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) { - ctx := context.TODO() - cst := cbor.NewCborStore(bs) - nd := hamt.NewNode(cst, hamt.UseTreeBitWidth(5)) - emptyhamt, err := cst.Put(ctx, nd) + store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs)) + emptyhamt, err := adt.MakeEmptyMap(store).Root() if err != nil { return nil, err } @@ -36,7 +35,7 @@ func SetupStoragePowerActor(bs bstore.Blockstore) (*types.Actor, error) { ProofValidationBatch: nil, } - stcid, err := cst.Put(ctx, sms) + stcid, err := store.Put(store.Context(), sms) if err != nil { return nil, err } diff --git a/chain/gen/genesis/t05_market.go b/chain/gen/genesis/t05_market.go index 9c55dff19..1673f1255 100644 --- a/chain/gen/genesis/t05_market.go +++ b/chain/gen/genesis/t05_market.go @@ -2,11 +2,10 @@ package genesis import ( "context" - "github.com/ipfs/go-hamt-ipld" - "github.com/filecoin-project/go-amt-ipld/v2" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/market" + "github.com/filecoin-project/specs-actors/actors/util/adt" bstore "github.com/ipfs/go-ipfs-blockstore" cbor "github.com/ipfs/go-ipld-cbor" @@ -14,20 +13,20 @@ import ( ) func SetupStorageMarketActor(bs bstore.Blockstore) (*types.Actor, error) { - cst := cbor.NewCborStore(bs) + store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs)) - a, err := amt.NewAMT(cst).Flush(context.TODO()) + a, err := adt.MakeEmptyArray(store).Root() if err != nil { return nil, err } - h, err := cst.Put(context.TODO(), hamt.NewNode(cst, hamt.UseTreeBitWidth(5))) + h, err := adt.MakeEmptyMap(store).Root() if err != nil { return nil, err } sms := market.ConstructState(a, h, h) - stcid, err := cst.Put(context.TODO(), sms) + stcid, err := store.Put(store.Context(), sms) if err != nil { return nil, err } diff --git a/chain/gen/genesis/t06_vreg.go b/chain/gen/genesis/t06_vreg.go index 4e77b924e..aeca8395d 100644 --- a/chain/gen/genesis/t06_vreg.go +++ b/chain/gen/genesis/t06_vreg.go @@ -4,12 +4,12 @@ import ( "context" "github.com/filecoin-project/go-address" - "github.com/ipfs/go-hamt-ipld" bstore "github.com/ipfs/go-ipfs-blockstore" cbor "github.com/ipfs/go-ipld-cbor" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" + "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/chain/types" ) @@ -27,16 +27,16 @@ func init() { } func SetupVerifiedRegistryActor(bs bstore.Blockstore) (*types.Actor, error) { - cst := cbor.NewCborStore(bs) + store := adt.WrapStore(context.TODO(), cbor.NewCborStore(bs)) - h, err := cst.Put(context.TODO(), hamt.NewNode(cst, hamt.UseTreeBitWidth(5))) + h, err := adt.MakeEmptyMap(store).Root() if err != nil { return nil, err } sms := verifreg.ConstructState(h, RootVerifierID) - stcid, err := cst.Put(context.TODO(), sms) + stcid, err := store.Put(store.Context(), sms) if err != nil { return nil, err } diff --git a/chain/gen/mining.go b/chain/gen/mining.go index bc809a888..67cf59a58 100644 --- a/chain/gen/mining.go +++ b/chain/gen/mining.go @@ -4,8 +4,8 @@ import ( "context" bls "github.com/filecoin-project/filecoin-ffi" - amt "github.com/filecoin-project/go-amt-ipld/v2" "github.com/filecoin-project/specs-actors/actors/crypto" + "github.com/filecoin-project/specs-actors/actors/util/adt" cid "github.com/ipfs/go-cid" cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" @@ -78,17 +78,17 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal } } - bs := cbor.NewCborStore(sm.ChainStore().Blockstore()) - blsmsgroot, err := amt.FromArray(ctx, bs, toIfArr(blsMsgCids)) + store := sm.ChainStore().Store(ctx) + blsmsgroot, err := toArray(store, blsMsgCids) if err != nil { return nil, xerrors.Errorf("building bls amt: %w", err) } - secpkmsgroot, err := amt.FromArray(ctx, bs, toIfArr(secpkMsgCids)) + secpkmsgroot, err := toArray(store, secpkMsgCids) if err != nil { return nil, xerrors.Errorf("building secpk amt: %w", err) } - mmcid, err := bs.Put(ctx, &types.MsgMeta{ + mmcid, err := store.Put(store.Context(), &types.MsgMeta{ BlsMessages: blsmsgroot, SecpkMessages: secpkmsgroot, }) @@ -167,11 +167,13 @@ func aggregateSignatures(sigs []crypto.Signature) (*crypto.Signature, error) { }, nil } -func toIfArr(cids []cid.Cid) []cbg.CBORMarshaler { - out := make([]cbg.CBORMarshaler, 0, len(cids)) - for _, c := range cids { +func toArray(store adt.Store, cids []cid.Cid) (cid.Cid, error) { + arr := adt.MakeEmptyArray(store) + for i, c := range cids { oc := cbg.CborCid(c) - out = append(out, &oc) + if err := arr.Set(uint64(i), &oc); err != nil { + return cid.Undef, err + } } - return out + return arr.Root() } diff --git a/chain/messagepool/messagepool.go b/chain/messagepool/messagepool.go index c12359482..c02ea3712 100644 --- a/chain/messagepool/messagepool.go +++ b/chain/messagepool/messagepool.go @@ -117,12 +117,14 @@ func (ms *msgSet) add(m *types.SignedMessage) error { minPrice := exms.Message.GasPrice minPrice = types.BigAdd(minPrice, types.BigDiv(types.BigMul(minPrice, rbfNum), rbfDenom)) minPrice = types.BigAdd(minPrice, types.NewInt(1)) - if types.BigCmp(m.Message.GasPrice, minPrice) > 0 { + if types.BigCmp(m.Message.GasPrice, minPrice) >= 0 { log.Infow("add with RBF", "oldprice", exms.Message.GasPrice, "newprice", m.Message.GasPrice, "addr", m.Message.From, "nonce", m.Message.Nonce) } else { log.Info("add with duplicate nonce") - return xerrors.Errorf("message to %s with nonce %d already in mpool", m.Message.To, m.Message.Nonce) + return xerrors.Errorf("message from %s with nonce %d already in mpool,"+ + " increase GasPrice to %s from %s to trigger replace by fee", + m.Message.From, m.Message.Nonce, minPrice, m.Message.GasPrice) } } } @@ -617,6 +619,14 @@ func (mp *MessagePool) Pending() ([]*types.SignedMessage, *types.TipSet) { return out, mp.curTs } +func (mp *MessagePool) PendingFor(a address.Address) ([]*types.SignedMessage, *types.TipSet) { + mp.curTsLk.Lock() + defer mp.curTsLk.Unlock() + + mp.lk.Lock() + defer mp.lk.Unlock() + return mp.pendingFor(a), mp.curTs +} func (mp *MessagePool) pendingFor(a address.Address) []*types.SignedMessage { mset := mp.pending[a] diff --git a/chain/state/statetree.go b/chain/state/statetree.go index 024524835..3280590e2 100644 --- a/chain/state/statetree.go +++ b/chain/state/statetree.go @@ -9,7 +9,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" - hamt "github.com/ipfs/go-hamt-ipld" cbor "github.com/ipfs/go-ipld-cbor" logging "github.com/ipfs/go-log/v2" "go.opencensus.io/trace" @@ -23,7 +22,7 @@ var log = logging.Logger("statetree") // StateTree stores actors state by their ID. type StateTree struct { - root *hamt.Node + root *adt.Map Store cbor.IpldStore snaps *stateSnaps @@ -117,15 +116,16 @@ func (ss *stateSnaps) deleteActor(addr address.Address) { } func NewStateTree(cst cbor.IpldStore) (*StateTree, error) { + return &StateTree{ - root: hamt.NewNode(cst, hamt.UseTreeBitWidth(5)), + root: adt.MakeEmptyMap(adt.WrapStore(context.TODO(), cst)), Store: cst, snaps: newStateSnaps(), }, nil } func LoadStateTree(cst cbor.IpldStore, c cid.Cid) (*StateTree, error) { - nd, err := hamt.LoadNode(context.Background(), cst, c, hamt.UseTreeBitWidth(5)) + nd, err := adt.AsMap(adt.WrapStore(context.TODO(), cst), c) if err != nil { log.Errorf("loading hamt node %s failed: %s", c, err) return nil, err @@ -206,12 +206,10 @@ func (st *StateTree) GetActor(addr address.Address) (*types.Actor, error) { } var act types.Actor - err = st.root.Find(context.TODO(), string(addr.Bytes()), &act) - if err != nil { - if err == hamt.ErrNotFound { - return nil, types.ErrActorNotFound - } + if found, err := st.root.Get(adt.AddrKey(addr), &act); err != nil { return nil, xerrors.Errorf("hamt find failed: %w", err) + } else if !found { + return nil, types.ErrActorNotFound } st.snaps.setActor(addr, &act) @@ -253,21 +251,17 @@ func (st *StateTree) Flush(ctx context.Context) (cid.Cid, error) { for addr, sto := range st.snaps.layers[0].actors { if sto.Delete { - if err := st.root.Delete(ctx, string(addr.Bytes())); err != nil { + if err := st.root.Delete(adt.AddrKey(addr)); err != nil { return cid.Undef, err } } else { - if err := st.root.Set(ctx, string(addr.Bytes()), &sto.Act); err != nil { + if err := st.root.Put(adt.AddrKey(addr), &sto.Act); err != nil { return cid.Undef, err } } } - if err := st.root.Flush(ctx); err != nil { - return cid.Undef, err - } - - return st.Store.Put(ctx, st.root) + return st.root.Root() } func (st *StateTree) Snapshot(ctx context.Context) error { diff --git a/chain/state/statetree_test.go b/chain/state/statetree_test.go index 3c832f7cc..e45090d1a 100644 --- a/chain/state/statetree_test.go +++ b/chain/state/statetree_test.go @@ -272,7 +272,7 @@ func TestStateTreeConsistency(t *testing.T) { } fmt.Println("root is: ", root) - if root.String() != "bafy2bzaceadyjnrv3sbjvowfl3jr4pdn5p2bf3exjjie2f3shg4oy5sub7h34" { + if root.String() != "bafy2bzaceb2bhqw75pqp44efoxvlnm73lnctq6djair56bfn5x3gw56epcxbi" { t.Fatal("MISMATCH!") } } diff --git a/chain/stmgr/call.go b/chain/stmgr/call.go index 29c97c3d8..4da912614 100644 --- a/chain/stmgr/call.go +++ b/chain/stmgr/call.go @@ -86,7 +86,7 @@ func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types. return sm.CallRaw(ctx, msg, state, r, ts.Height()) } -func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) { +func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, priorMsgs []types.ChainMsg, ts *types.TipSet) (*api.InvocResult, error) { ctx, span := trace.StartSpan(ctx, "statemanager.CallWithGas") defer span.End() @@ -110,6 +110,13 @@ func (sm *StateManager) CallWithGas(ctx context.Context, msg *types.Message, ts if err != nil { return nil, xerrors.Errorf("failed to set up vm: %w", err) } + for i, m := range priorMsgs { + _, err := vmi.ApplyMessage(ctx, m) + if err != nil { + return nil, xerrors.Errorf("applying prior message (%d, %s): %w", i, m.Cid(), err) + } + } + fromActor, err := vmi.StateTree().GetActor(msg.From) if err != nil { return nil, xerrors.Errorf("call raw get actor: %s", err) diff --git a/chain/stmgr/forks_test.go b/chain/stmgr/forks_test.go index 5a6c8a34e..0fc28f92c 100644 --- a/chain/stmgr/forks_test.go +++ b/chain/stmgr/forks_test.go @@ -156,7 +156,7 @@ func TestForkHeightTriggers(t *testing.T) { } inv.Register(builtin.PaymentChannelActorCodeID, &testActor{}, &testActorState{}) - sm.SetVMConstructor(func(c cid.Cid, h abi.ChainEpoch, r vm.Rand, b blockstore.Blockstore, s runtime.Syscalls) (*vm.VM, error) { + sm.SetVMConstructor(func(c cid.Cid, h abi.ChainEpoch, r vm.Rand, b blockstore.Blockstore, s vm.SyscallBuilder) (*vm.VM, error) { nvm, err := vm.NewVM(c, h, r, b, s) if err != nil { return nil, err diff --git a/chain/stmgr/stmgr.go b/chain/stmgr/stmgr.go index 0559e2d79..a888e869a 100644 --- a/chain/stmgr/stmgr.go +++ b/chain/stmgr/stmgr.go @@ -6,7 +6,6 @@ import ( "sync" "github.com/filecoin-project/go-address" - amt "github.com/filecoin-project/go-amt-ipld/v2" "github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/actors" @@ -19,14 +18,12 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/reward" - "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/specs-actors/actors/util/adt" cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" bls "github.com/filecoin-project/filecoin-ffi" "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" logging "github.com/ipfs/go-log/v2" @@ -41,7 +38,7 @@ type StateManager struct { stCache map[string][]cid.Cid compWait map[string]chan struct{} stlk sync.Mutex - newVM func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, runtime.Syscalls) (*vm.VM, error) + newVM func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, vm.SyscallBuilder) (*vm.VM, error) } func NewStateManager(cs *store.ChainStore) *StateManager { @@ -254,8 +251,13 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B return cid.Undef, cid.Undef, xerrors.Errorf("CheckProofSubmissions exit was non-zero: %d", ret.ExitCode) } - bs := cbor.NewCborStore(sm.cs.Blockstore()) - rectroot, err := amt.FromArray(ctx, bs, receipts) + rectarr := adt.MakeEmptyArray(sm.cs.Store(ctx)) + for i, receipt := range receipts { + if err := rectarr.Set(uint64(i), receipt); err != nil { + return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err) + } + } + rectroot, err := rectarr.Root() if err != nil { return cid.Undef, cid.Undef, xerrors.Errorf("failed to build receipts amt: %w", err) } @@ -652,14 +654,13 @@ func (sm *StateManager) ListAllActors(ctx context.Context, ts *types.TipSet) ([] return nil, err } - cst := cbor.NewCborStore(sm.cs.Blockstore()) - r, err := hamt.LoadNode(ctx, cst, st, hamt.UseTreeBitWidth(5)) + r, err := adt.AsMap(sm.cs.Store(ctx), st) if err != nil { return nil, err } var out []address.Address - err = r.ForEach(ctx, func(k string, val interface{}) error { + err = r.ForEach(nil, func(k string) error { addr, err := address.NewFromBytes([]byte(k)) if err != nil { return xerrors.Errorf("address in state tree was not valid: %w", err) @@ -754,6 +755,6 @@ func (sm *StateManager) ValidateChain(ctx context.Context, ts *types.TipSet) err return nil } -func (sm *StateManager) SetVMConstructor(nvm func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, runtime.Syscalls) (*vm.VM, error)) { +func (sm *StateManager) SetVMConstructor(nvm func(cid.Cid, abi.ChainEpoch, vm.Rand, blockstore.Blockstore, vm.SyscallBuilder) (*vm.VM, error)) { sm.newVM = nvm } diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index 79585ba68..e30a245de 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -13,7 +13,6 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - amt "github.com/filecoin-project/go-amt-ipld/v2" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/specs-actors/actors/abi" @@ -258,7 +257,7 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S return nil, xerrors.Errorf("failed to enumerate all sector IDs: %w", err) } - sectorAmt, err := amt.LoadAMT(ctx, sm.cs.Store(ctx), mas.Sectors) + sectorAmt, err := adt.AsArray(sm.cs.Store(ctx), mas.Sectors) if err != nil { return nil, xerrors.Errorf("failed to load sectors amt: %w", err) } @@ -268,8 +267,10 @@ func GetSectorsForWinningPoSt(ctx context.Context, pv ffiwrapper.Verifier, sm *S sid := sectors[n] var sinfo miner.SectorOnChainInfo - if err := sectorAmt.Get(ctx, sid, &sinfo); err != nil { + if found, err := sectorAmt.Get(sid, &sinfo); err != nil { return nil, xerrors.Errorf("failed to get sector %d: %w", sid, err) + } else if !found { + return nil, xerrors.Errorf("failed to find sector %d", sid) } out[i] = abi.SectorInfo{ @@ -328,18 +329,21 @@ func GetStorageDeal(ctx context.Context, sm *StateManager, dealID abi.DealID, ts if _, err := sm.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { return nil, err } + store := sm.ChainStore().Store(ctx) - da, err := amt.LoadAMT(ctx, cbor.NewCborStore(sm.ChainStore().Blockstore()), state.Proposals) + da, err := adt.AsArray(store, state.Proposals) if err != nil { return nil, err } var dp market.DealProposal - if err := da.Get(ctx, uint64(dealID), &dp); err != nil { + if found, err := da.Get(uint64(dealID), &dp); err != nil { return nil, err + } else if !found { + return nil, xerrors.Errorf("deal %d not found", dealID) } - sa, err := market.AsDealStateArray(sm.ChainStore().Store(ctx), state.States) + sa, err := market.AsDealStateArray(store, state.States) if err != nil { return nil, err } @@ -391,15 +395,16 @@ func ListMinerActors(ctx context.Context, sm *StateManager, ts *types.TipSet) ([ } func LoadSectorsFromSet(ctx context.Context, bs blockstore.Blockstore, ssc cid.Cid, filter *abi.BitField, filterOut bool) ([]*api.ChainSectorInfo, error) { - a, err := amt.LoadAMT(ctx, cbor.NewCborStore(bs), ssc) + a, err := adt.AsArray(store.ActorStore(ctx, bs), ssc) if err != nil { return nil, err } var sset []*api.ChainSectorInfo - if err := a.ForEach(ctx, func(i uint64, v *cbg.Deferred) error { + var v cbg.Deferred + if err := a.ForEach(&v, func(i int64) error { if filter != nil { - set, err := filter.IsSet(i) + set, err := filter.IsSet(uint64(i)) if err != nil { return xerrors.Errorf("filter check error: %w", err) } diff --git a/chain/store/store.go b/chain/store/store.go index e0cd0e91a..13f317693 100644 --- a/chain/store/store.go +++ b/chain/store/store.go @@ -9,14 +9,11 @@ import ( "os" "sync" - "github.com/filecoin-project/lotus/lib/adtutil" - "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/minio/blake2b-simd" "github.com/filecoin-project/go-address" "github.com/filecoin-project/specs-actors/actors/abi" - "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/lotus/api" @@ -28,8 +25,6 @@ import ( "go.opencensus.io/trace" "go.uber.org/multierr" - amt "github.com/filecoin-project/go-amt-ipld/v2" - "github.com/filecoin-project/lotus/chain/types" lru "github.com/hashicorp/golang-lru" @@ -85,10 +80,10 @@ type ChainStore struct { mmCache *lru.ARCCache tsCache *lru.ARCCache - vmcalls runtime.Syscalls + vmcalls vm.SyscallBuilder } -func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls runtime.Syscalls) *ChainStore { +func NewChainStore(bs bstore.Blockstore, ds dstore.Batching, vmcalls vm.SyscallBuilder) *ChainStore { c, _ := lru.NewARC(2048) tsc, _ := lru.NewARC(4096) cs := &ChainStore{ @@ -688,20 +683,25 @@ func (cs *ChainStore) GetSignedMessage(c cid.Cid) (*types.SignedMessage, error) func (cs *ChainStore) readAMTCids(root cid.Cid) ([]cid.Cid, error) { ctx := context.TODO() - bs := cbor.NewCborStore(cs.bs) - a, err := amt.LoadAMT(ctx, bs, root) + a, err := adt.AsArray(cs.Store(ctx), root) if err != nil { return nil, xerrors.Errorf("amt load: %w", err) } - var cids []cid.Cid - for i := uint64(0); i < a.Count; i++ { - var c cbg.CborCid - if err := a.Get(ctx, i, &c); err != nil { - return nil, xerrors.Errorf("failed to load cid from amt: %w", err) - } + var ( + cids []cid.Cid + cborCid cbg.CborCid + ) + if err := a.ForEach(&cborCid, func(i int64) error { + c := cid.Cid(cborCid) + cids = append(cids, c) + return nil + }); err != nil { + return nil, xerrors.Errorf("failed to traverse amt: %w", err) + } - cids = append(cids, cid.Cid(c)) + if uint64(len(cids)) != a.Length() { + return nil, xerrors.Errorf("found %d cids, expected %d", len(cids), a.Length()) } return cids, nil @@ -849,15 +849,16 @@ func (cs *ChainStore) MessagesForBlock(b *types.BlockHeader) ([]*types.Message, func (cs *ChainStore) GetParentReceipt(b *types.BlockHeader, i int) (*types.MessageReceipt, error) { ctx := context.TODO() - bs := cbor.NewCborStore(cs.bs) - a, err := amt.LoadAMT(ctx, bs, b.ParentMessageReceipts) + a, err := adt.AsArray(cs.Store(ctx), b.ParentMessageReceipts) if err != nil { return nil, xerrors.Errorf("amt load: %w", err) } var r types.MessageReceipt - if err := a.Get(ctx, uint64(i), &r); err != nil { + if found, err := a.Get(uint64(i), &r); err != nil { return nil, err + } else if !found { + return nil, xerrors.Errorf("failed to find receipt %d", i) } return &r, nil @@ -896,14 +897,14 @@ func (cs *ChainStore) Blockstore() bstore.Blockstore { } func ActorStore(ctx context.Context, bs blockstore.Blockstore) adt.Store { - return adtutil.NewStore(ctx, cbor.NewCborStore(bs)) + return adt.WrapStore(ctx, cbor.NewCborStore(bs)) } func (cs *ChainStore) Store(ctx context.Context) adt.Store { return ActorStore(ctx, cs.bs) } -func (cs *ChainStore) VMSys() runtime.Syscalls { +func (cs *ChainStore) VMSys() vm.SyscallBuilder { return cs.vmcalls } diff --git a/chain/sub/incoming.go b/chain/sub/incoming.go index 0db132562..875e2658f 100644 --- a/chain/sub/incoming.go +++ b/chain/sub/incoming.go @@ -4,15 +4,14 @@ import ( "bytes" "context" "fmt" - "github.com/filecoin-project/lotus/lib/adtutil" "sync" "time" "golang.org/x/xerrors" address "github.com/filecoin-project/go-address" - amt "github.com/filecoin-project/go-amt-ipld/v2" miner "github.com/filecoin-project/specs-actors/actors/builtin/miner" + "github.com/filecoin-project/specs-actors/actors/util/adt" lru "github.com/hashicorp/golang-lru" "github.com/ipfs/go-cid" dstore "github.com/ipfs/go-datastore" @@ -239,31 +238,36 @@ func (bv *BlockValidator) isChainNearSynced() bool { } func (bv *BlockValidator) validateMsgMeta(ctx context.Context, msg *types.BlockMsg) error { - var bcids, scids []cbg.CBORMarshaler - for _, m := range msg.BlsMessages { - c := cbg.CborCid(m) - bcids = append(bcids, &c) - } - - for _, m := range msg.SecpkMessages { - c := cbg.CborCid(m) - scids = append(scids, &c) - } - // TODO there has to be a simpler way to do this without the blockstore dance - bs := cbor.NewCborStore(bstore.NewBlockstore(dstore.NewMapDatastore())) + store := adt.WrapStore(ctx, cbor.NewCborStore(bstore.NewBlockstore(dstore.NewMapDatastore()))) + bmArr := adt.MakeEmptyArray(store) + smArr := adt.MakeEmptyArray(store) - bmroot, err := amt.FromArray(ctx, bs, bcids) + for i, m := range msg.BlsMessages { + c := cbg.CborCid(m) + if err := bmArr.Set(uint64(i), &c); err != nil { + return err + } + } + + for i, m := range msg.SecpkMessages { + c := cbg.CborCid(m) + if err := smArr.Set(uint64(i), &c); err != nil { + return err + } + } + + bmroot, err := bmArr.Root() if err != nil { return err } - smroot, err := amt.FromArray(ctx, bs, scids) + smroot, err := smArr.Root() if err != nil { return err } - mrcid, err := bs.Put(ctx, &types.MsgMeta{ + mrcid, err := store.Put(store.Context(), &types.MsgMeta{ BlsMessages: bmroot, SecpkMessages: smroot, }) @@ -318,7 +322,7 @@ func (bv *BlockValidator) getMinerWorkerKey(ctx context.Context, msg *types.Bloc return address.Undef, err } - info, err := mst.GetInfo(adtutil.NewStore(ctx, cst)) + info, err := mst.GetInfo(adt.WrapStore(ctx, cst)) if err != nil { return address.Undef, err } diff --git a/chain/sync.go b/chain/sync.go index 1ed7a3507..20475171e 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -27,7 +27,6 @@ import ( bls "github.com/filecoin-project/filecoin-ffi" "github.com/filecoin-project/go-address" - amt "github.com/filecoin-project/go-amt-ipld/v2" "github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin" @@ -256,15 +255,13 @@ func (syncer *Syncer) ValidateMsgMeta(fblk *types.FullBlock) error { } // Collect the CIDs of both types of messages separately: BLS and Secpk. - var bcids, scids []cbg.CBORMarshaler + var bcids, scids []cid.Cid for _, m := range fblk.BlsMessages { - c := cbg.CborCid(m.Cid()) - bcids = append(bcids, &c) + bcids = append(bcids, m.Cid()) } for _, m := range fblk.SecpkMessages { - c := cbg.CborCid(m.Cid()) - scids = append(scids, &c) + scids = append(scids, m.Cid()) } // TODO: IMPORTANT(GARBAGE). These message puts and the msgmeta @@ -354,19 +351,17 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types } var smsgs []*types.SignedMessage - var smsgCids []cbg.CBORMarshaler + var smsgCids []cid.Cid for _, m := range smi[bi] { smsgs = append(smsgs, allsmsgs[m]) - c := cbg.CborCid(allsmsgs[m].Cid()) - smsgCids = append(smsgCids, &c) + smsgCids = append(smsgCids, allsmsgs[m].Cid()) } var bmsgs []*types.Message - var bmsgCids []cbg.CBORMarshaler + var bmsgCids []cid.Cid for _, m := range bmi[bi] { bmsgs = append(bmsgs, allbmsgs[m]) - c := cbg.CborCid(allbmsgs[m].Cid()) - bmsgCids = append(bmsgCids, &c) + bmsgCids = append(bmsgCids, allbmsgs[m].Cid()) } mrcid, err := computeMsgMeta(bs, bmsgCids, smsgCids) @@ -392,19 +387,36 @@ func zipTipSetAndMessages(bs cbor.IpldStore, ts *types.TipSet, allbmsgs []*types // computeMsgMeta computes the root CID of the combined arrays of message CIDs // of both types (BLS and Secpk). -func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cbg.CBORMarshaler) (cid.Cid, error) { - ctx := context.TODO() - bmroot, err := amt.FromArray(ctx, bs, bmsgCids) +func computeMsgMeta(bs cbor.IpldStore, bmsgCids, smsgCids []cid.Cid) (cid.Cid, error) { + store := adt.WrapStore(context.TODO(), bs) + bmArr := adt.MakeEmptyArray(store) + smArr := adt.MakeEmptyArray(store) + + for i, m := range bmsgCids { + c := cbg.CborCid(m) + if err := bmArr.Set(uint64(i), &c); err != nil { + return cid.Undef, err + } + } + + for i, m := range smsgCids { + c := cbg.CborCid(m) + if err := smArr.Set(uint64(i), &c); err != nil { + return cid.Undef, err + } + } + + bmroot, err := bmArr.Root() if err != nil { return cid.Undef, err } - smroot, err := amt.FromArray(ctx, bs, smsgCids) + smroot, err := smArr.Root() if err != nil { return cid.Undef, err } - mrcid, err := bs.Put(ctx, &types.MsgMeta{ + mrcid, err := store.Put(store.Context(), &types.MsgMeta{ BlsMessages: bmroot, SecpkMessages: smroot, }) @@ -851,6 +863,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er "%d errors occurred:\n\t%s\n\n", len(es), strings.Join(points, "\n\t")) } + return mulErr } if err := syncer.store.MarkBlockAsValidated(ctx, b.Cid()); err != nil { @@ -908,7 +921,7 @@ func (syncer *Syncer) VerifyWinningPoStProof(ctx context.Context, h *types.Block } if !ok { - log.Errorf("invalid winning post (%x; %v)", rand, sectors) + log.Errorf("invalid winning post (block: %s, %x; %v)", h.Cid(), rand, sectors) return xerrors.Errorf("winning post was invalid") } @@ -992,18 +1005,21 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock return nil } - var blsCids []cbg.CBORMarshaler + store := adt.WrapStore(ctx, cst) + bmArr := adt.MakeEmptyArray(store) for i, m := range b.BlsMessages { if err := checkMsg(m); err != nil { return xerrors.Errorf("block had invalid bls message at index %d: %w", i, err) } c := cbg.CborCid(m.Cid()) - blsCids = append(blsCids, &c) + if err := bmArr.Set(uint64(i), &c); err != nil { + return xerrors.Errorf("failed to put bls message at index %d: %w", i, err) + } } - var secpkCids []cbg.CBORMarshaler + smArr := adt.MakeEmptyArray(store) for i, m := range b.SecpkMessages { if err := checkMsg(m); err != nil { return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err) @@ -1021,17 +1037,19 @@ func (syncer *Syncer) checkBlockMessages(ctx context.Context, b *types.FullBlock } c := cbg.CborCid(m.Cid()) - secpkCids = append(secpkCids, &c) + if err := smArr.Set(uint64(i), &c); err != nil { + return xerrors.Errorf("failed to put secpk message at index %d: %w", i, err) + } } - bmroot, err := amt.FromArray(ctx, cst, blsCids) + bmroot, err := bmArr.Root() if err != nil { - return xerrors.Errorf("failed to build amt from bls msg cids: %w", err) + return err } - smroot, err := amt.FromArray(ctx, cst, secpkCids) + smroot, err := smArr.Root() if err != nil { - return xerrors.Errorf("failed to build amt from bls msg cids: %w", err) + return err } mrcid, err := cst.Put(ctx, &types.MsgMeta{ @@ -1056,6 +1074,10 @@ func (syncer *Syncer) verifyBlsAggregate(ctx context.Context, sig *crypto.Signat trace.Int64Attribute("msgCount", int64(len(msgs))), ) + if len(msgs) == 0 { + return nil + } + bmsgs := make([]bls.Message, len(msgs)) for i, m := range msgs { bmsgs[i] = m.Bytes() diff --git a/chain/sync_test.go b/chain/sync_test.go index efb601041..451ba1959 100644 --- a/chain/sync_test.go +++ b/chain/sync_test.go @@ -170,7 +170,7 @@ func (tu *syncTestUtil) pushTsExpectErr(to int, fts *store.FullTipSet, experr bo } } -func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, src int, miners []int, wait, fail bool) *store.FullTipSet { +func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, to int, miners []int, wait, fail bool) *store.FullTipSet { if miners == nil { for i := range tu.g.Miners { miners = append(miners, i) @@ -188,9 +188,9 @@ func (tu *syncTestUtil) mineOnBlock(blk *store.FullTipSet, src int, miners []int require.NoError(tu.t, err) if fail { - tu.pushTsExpectErr(src, mts.TipSet, true) + tu.pushTsExpectErr(to, mts.TipSet, true) } else { - tu.pushFtsAndWait(src, mts.TipSet, wait) + tu.pushFtsAndWait(to, mts.TipSet, wait) } return mts.TipSet @@ -433,6 +433,41 @@ func TestSyncBadTimestamp(t *testing.T) { } } +type badWpp struct{} + +func (wpp badWpp) GenerateCandidates(context.Context, abi.PoStRandomness, uint64) ([]uint64, error) { + return []uint64{1}, nil +} + +func (wpp badWpp) ComputeProof(context.Context, []abi.SectorInfo, abi.PoStRandomness) ([]abi.PoStProof, error) { + return []abi.PoStProof{ + abi.PoStProof{ + PoStProof: abi.RegisteredPoStProof_StackedDrgWinning2KiBV1, + ProofBytes: []byte("evil"), + }, + }, nil +} + +func TestSyncBadWinningPoSt(t *testing.T) { + H := 15 + tu := prepSyncTest(t, H) + + client := tu.addClientNode() + + require.NoError(t, tu.mn.LinkAll()) + tu.connect(client, 0) + tu.waitUntilSync(0, client) + + base := tu.g.CurTipset + + // both miners now produce invalid winning posts + tu.g.SetWinningPoStProver(tu.g.Miners[0], &badWpp{}) + tu.g.SetWinningPoStProver(tu.g.Miners[1], &badWpp{}) + + // now ensure that new blocks are not accepted + tu.mineOnBlock(base, client, nil, false, true) +} + func (tu *syncTestUtil) loadChainToNode(to int) { // utility to simulate incoming blocks without miner process // TODO: should call syncer directly, this won't work correctly in all cases diff --git a/chain/validation/applier.go b/chain/validation/applier.go index 153c8ca71..62ea09894 100644 --- a/chain/validation/applier.go +++ b/chain/validation/applier.go @@ -10,7 +10,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/puppet" - "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/ipfs/go-cid" vtypes "github.com/filecoin-project/chain-validation/chain/types" @@ -25,12 +24,12 @@ import ( // Applier applies messages to state trees and storage. type Applier struct { stateWrapper *StateWrapper - syscalls runtime.Syscalls + syscalls vm.SyscallBuilder } var _ vstate.Applier = &Applier{} -func NewApplier(sw *StateWrapper, syscalls runtime.Syscalls) *Applier { +func NewApplier(sw *StateWrapper, syscalls vm.SyscallBuilder) *Applier { return &Applier{sw, syscalls} } diff --git a/chain/validation/factories.go b/chain/validation/factories.go index d3771d87d..6d5386023 100644 --- a/chain/validation/factories.go +++ b/chain/validation/factories.go @@ -1,7 +1,10 @@ package validation import ( + "context" + "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/specs-actors/actors/runtime" + cbor "github.com/ipfs/go-ipld-cbor" vstate "github.com/filecoin-project/chain-validation/state" ) @@ -18,7 +21,9 @@ func NewFactories() *Factories { func (f *Factories) NewStateAndApplier(syscalls runtime.Syscalls) (vstate.VMWrapper, vstate.Applier) { st := NewState() - return st, NewApplier(st, syscalls) + return st, NewApplier(st, func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls { + return syscalls + }) } func (f *Factories) NewKeyManager() vstate.KeyManager { diff --git a/chain/vectors/vectors_test.go b/chain/vectors/vectors_test.go index c9ebc98fa..587ea22d1 100644 --- a/chain/vectors/vectors_test.go +++ b/chain/vectors/vectors_test.go @@ -18,6 +18,7 @@ func LoadVector(t *testing.T, f string, out interface{}) { if err != nil { t.Fatal(err) } + defer fi.Close() if err := json.NewDecoder(fi).Decode(out); err != nil { t.Fatal(err) diff --git a/chain/vm/gas.go b/chain/vm/gas.go index 81a5fc8e3..8520aca38 100644 --- a/chain/vm/gas.go +++ b/chain/vm/gas.go @@ -13,7 +13,7 @@ import ( ) const ( - GasStorageMulti = 1 + GasStorageMulti = 1000 GasComputeMulti = 1 ) @@ -85,10 +85,10 @@ type Pricelist interface { var prices = map[abi.ChainEpoch]Pricelist{ abi.ChainEpoch(0): &pricelistV0{ onChainMessageComputeBase: 137137, - onChainMessageStorageBase: 0, // TODO gas - onChainMessageStoragePerByte: 2, // TODO gas + onChainMessageStorageBase: 36, + onChainMessageStoragePerByte: 1, - onChainReturnValuePerByte: 8, // TODO gas + onChainReturnValuePerByte: 1, sendBase: 97236, sendTransferFunds: 96812, @@ -97,11 +97,11 @@ var prices = map[abi.ChainEpoch]Pricelist{ ipldGetBase: 417230, ipldPutBase: 396100, - ipldPutPerByte: 2, // TODO gas + ipldPutPerByte: 1, createActorCompute: 750011, - createActorStorage: 500, // TODO gas - deleteActor: -500, // -createActorStorage + createActorStorage: 36 + 40, + deleteActor: -(36 + 40), // -createActorStorage verifySignature: map[crypto.SigType]int64{ crypto.SigTypeBLS: 219946580, diff --git a/chain/vm/runtime.go b/chain/vm/runtime.go index 039bccc0b..c82f5a84d 100644 --- a/chain/vm/runtime.go +++ b/chain/vm/runtime.go @@ -20,7 +20,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-cid" - hamt "github.com/ipfs/go-hamt-ipld" cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" "go.opencensus.io/trace" @@ -464,7 +463,7 @@ func (rt *Runtime) GetBalance(a address.Address) (types.BigInt, aerrors.ActorErr switch err { default: return types.EmptyInt, aerrors.Escalate(err, "failed to look up actor balance") - case hamt.ErrNotFound: + case types.ErrActorNotFound: return types.NewInt(0), nil case nil: return act.Balance, nil @@ -582,12 +581,12 @@ func (rt *Runtime) abortIfAlreadyValidated() { func (rt *Runtime) Log(level vmr.LogLevel, msg string, args ...interface{}) { switch level { case vmr.DEBUG: - actorLog.Debugf(msg, args) + actorLog.Debugf(msg, args...) case vmr.INFO: - actorLog.Infof(msg, args) + actorLog.Infof(msg, args...) case vmr.WARN: - actorLog.Warnf(msg, args) + actorLog.Warnf(msg, args...) case vmr.ERROR: - actorLog.Errorf(msg, args) + actorLog.Errorf(msg, args...) } } diff --git a/chain/vm/syscalls.go b/chain/vm/syscalls.go index 887e138fd..d25c947d6 100644 --- a/chain/vm/syscalls.go +++ b/chain/vm/syscalls.go @@ -16,12 +16,12 @@ import ( "github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/lib/adtutil" "github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/runtime" + "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/sector-storage/ffiwrapper" ) @@ -32,15 +32,26 @@ func init() { // Actual type is defined in chain/types/vmcontext.go because the VMContext interface is there -func Syscalls(verifier ffiwrapper.Verifier) runtime.Syscalls { - return &syscallShim{verifier: verifier} +type SyscallBuilder func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls + +func Syscalls(verifier ffiwrapper.Verifier) SyscallBuilder { + return func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls { + return &syscallShim{ + ctx: ctx, + + cstate: cstate, + cst: cst, + + verifier: verifier, + } + } } type syscallShim struct { ctx context.Context cstate *state.StateTree - cst *cbor.BasicIpldStore + cst cbor.IpldStore verifier ffiwrapper.Verifier } @@ -180,7 +191,7 @@ func (ss *syscallShim) VerifyBlockSig(blk *types.BlockHeader) error { return err } - info, err := mas.GetInfo(adtutil.NewStore(ss.ctx, ss.cst)) + info, err := mas.GetInfo(adt.WrapStore(ss.ctx, ss.cst)) if err != nil { return err } diff --git a/chain/vm/vm.go b/chain/vm/vm.go index 6aab57393..d9e056be6 100644 --- a/chain/vm/vm.go +++ b/chain/vm/vm.go @@ -24,7 +24,6 @@ import ( "github.com/filecoin-project/specs-actors/actors/builtin/account" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/specs-actors/actors/crypto" - "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/specs-actors/actors/runtime/exitcode" "github.com/filecoin-project/lotus/build" @@ -115,7 +114,7 @@ func (vm *VM) makeRuntime(ctx context.Context, msg *types.Message, origin addres Atlas: vm.cst.Atlas, } rt.sys = pricedSyscalls{ - under: vm.Syscalls, + under: vm.Syscalls(ctx, vm.cstate, rt.cst), chargeGas: rt.chargeGasFunc(1), pl: rt.pricelist, } @@ -148,10 +147,10 @@ type VM struct { inv *Invoker rand Rand - Syscalls runtime.Syscalls + Syscalls SyscallBuilder } -func NewVM(base cid.Cid, height abi.ChainEpoch, r Rand, cbs blockstore.Blockstore, syscalls runtime.Syscalls) (*VM, error) { +func NewVM(base cid.Cid, height abi.ChainEpoch, r Rand, cbs blockstore.Blockstore, syscalls SyscallBuilder) (*VM, error) { buf := bufbstore.NewBufferedBstore(cbs) cst := cbor.NewCborStore(buf) state, err := state.LoadStateTree(cst, base) @@ -347,6 +346,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, ExitCode: exitcode.SysErrSenderInvalid, GasUsed: 0, }, + ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "actor not found: %s", msg.From), Penalty: minerPenaltyAmount, Duration: time.Since(start), }, nil @@ -361,6 +361,7 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, ExitCode: exitcode.SysErrSenderInvalid, GasUsed: 0, }, + ActorErr: aerrors.Newf(exitcode.SysErrSenderInvalid, "send from not account actor: %s", fromActor.Code), Penalty: minerPenaltyAmount, Duration: time.Since(start), }, nil @@ -373,6 +374,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, ExitCode: exitcode.SysErrSenderStateInvalid, GasUsed: 0, }, + ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid, + "actor nonce invalid: msg:%d != state:%d", msg.Nonce, fromActor.Nonce), Penalty: minerPenaltyAmount, Duration: time.Since(start), }, nil @@ -386,6 +389,8 @@ func (vm *VM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet, ExitCode: exitcode.SysErrSenderStateInvalid, GasUsed: 0, }, + ActorErr: aerrors.Newf(exitcode.SysErrSenderStateInvalid, + "actor balance less than needed: %s < %s", types.FIL(fromActor.Balance), types.FIL(totalCost)), Penalty: minerPenaltyAmount, Duration: time.Since(start), }, nil diff --git a/cli/cmd.go b/cli/cmd.go index 69194b0d6..d750ec4c9 100644 --- a/cli/cmd.go +++ b/cli/cmd.go @@ -242,24 +242,24 @@ var CommonCommands = []*cli.Command{ } var Commands = []*cli.Command{ - withCategory("basic", sendCmd), - withCategory("basic", walletCmd), - withCategory("basic", clientCmd), - withCategory("basic", multisigCmd), - withCategory("basic", paychCmd), - withCategory("developer", authCmd), - withCategory("developer", mpoolCmd), - withCategory("developer", stateCmd), - withCategory("developer", chainCmd), - withCategory("developer", logCmd), - withCategory("developer", waitApiCmd), - withCategory("developer", fetchParamCmd), - withCategory("network", netCmd), - withCategory("network", syncCmd), + WithCategory("basic", sendCmd), + WithCategory("basic", walletCmd), + WithCategory("basic", clientCmd), + WithCategory("basic", multisigCmd), + WithCategory("basic", paychCmd), + WithCategory("developer", authCmd), + WithCategory("developer", mpoolCmd), + WithCategory("developer", stateCmd), + WithCategory("developer", chainCmd), + WithCategory("developer", logCmd), + WithCategory("developer", waitApiCmd), + WithCategory("developer", fetchParamCmd), + WithCategory("network", netCmd), + WithCategory("network", syncCmd), versionCmd, } -func withCategory(cat string, cmd *cli.Command) *cli.Command { +func WithCategory(cat string, cmd *cli.Command) *cli.Command { cmd.Category = cat return cmd } diff --git a/cli/helper.go b/cli/helper.go new file mode 100644 index 000000000..536301e87 --- /dev/null +++ b/cli/helper.go @@ -0,0 +1,46 @@ +package cli + +import ( + "fmt" + "os" + + "github.com/urfave/cli/v2" + "golang.org/x/xerrors" +) + +type PrintHelpErr struct { + Err error + Ctx *cli.Context +} + +func (e *PrintHelpErr) Error() string { + return e.Err.Error() +} + +func (e *PrintHelpErr) Unwrap() error { + return e.Err +} + +func (e *PrintHelpErr) Is(o error) bool { + _, ok := o.(*PrintHelpErr) + return ok +} + +func ShowHelp(cctx *cli.Context, err error) error { + return &PrintHelpErr{Err: err, Ctx: cctx} +} + +func RunApp(app *cli.App) { + if err := app.Run(os.Args); err != nil { + if os.Getenv("LOTUS_DEV") != "" { + log.Warnf("%+v", err) + } else { + fmt.Printf("ERROR: %s\n\n", err) + } + var phe *PrintHelpErr + if xerrors.As(err, &phe) { + cli.ShowCommandHelp(phe.Ctx, phe.Ctx.Command.Name) + } + os.Exit(1) + } +} diff --git a/cli/mpool.go b/cli/mpool.go index 5281c8eb1..d5f3eaa10 100644 --- a/cli/mpool.go +++ b/cli/mpool.go @@ -4,11 +4,13 @@ import ( "encoding/json" "fmt" "sort" + "strconv" "github.com/urfave/cli/v2" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/lotus/chain/types" ) @@ -20,6 +22,8 @@ var mpoolCmd = &cli.Command{ mpoolPending, mpoolSub, mpoolStat, + mpoolReplaceCmd, + mpoolFindCmd, }, } @@ -228,3 +232,165 @@ var mpoolStat = &cli.Command{ return nil }, } + +var mpoolReplaceCmd = &cli.Command{ + Name: "replace", + Usage: "replace a message in the mempool", + Flags: []cli.Flag{ + &cli.Int64Flag{ + Name: "gas-price", + Usage: "gas price for new message", + }, + &cli.Int64Flag{ + Name: "gas-limit", + Usage: "gas price for new message", + }, + }, + ArgsUsage: "[from] [nonce]", + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() < 2 { + return cli.ShowCommandHelp(cctx, cctx.Command.Name) + } + + from, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return err + } + + nonce, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64) + if err != nil { + return err + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + ts, err := api.ChainHead(ctx) + if err != nil { + return xerrors.Errorf("getting chain head: %w", err) + } + + pending, err := api.MpoolPending(ctx, ts.Key()) + if err != nil { + return err + } + + var found *types.SignedMessage + for _, p := range pending { + if p.Message.From == from && p.Message.Nonce == nonce { + found = p + break + } + } + + if found == nil { + return fmt.Errorf("no pending message found from %s with nonce %d", from, nonce) + } + + msg := found.Message + + msg.GasLimit = cctx.Int64("gas-limit") + msg.GasPrice = types.NewInt(uint64(cctx.Int64("gas-price"))) + + smsg, err := api.WalletSignMessage(ctx, msg.From, &msg) + if err != nil { + return fmt.Errorf("failed to sign message: %w", err) + } + + cid, err := api.MpoolPush(ctx, smsg) + if err != nil { + return fmt.Errorf("failed to push new message to mempool: %w", err) + } + + fmt.Println("new message cid: ", cid) + return nil + }, +} + +var mpoolFindCmd = &cli.Command{ + Name: "find", + Usage: "find a message in the mempool", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "from", + Usage: "search for messages with given 'from' address", + }, + &cli.StringFlag{ + Name: "to", + Usage: "search for messages with given 'to' address", + }, + &cli.Int64Flag{ + Name: "method", + Usage: "search for messages with given method", + }, + }, + Action: func(cctx *cli.Context) error { + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + pending, err := api.MpoolPending(ctx, types.EmptyTSK) + if err != nil { + return err + } + + var toFilter, fromFilter address.Address + if cctx.IsSet("to") { + a, err := address.NewFromString(cctx.String("to")) + if err != nil { + return fmt.Errorf("'to' address was invalid: %w", err) + } + + toFilter = a + } + + if cctx.IsSet("from") { + a, err := address.NewFromString(cctx.String("from")) + if err != nil { + return fmt.Errorf("'from' address was invalid: %w", err) + } + + fromFilter = a + } + + var methodFilter *abi.MethodNum + if cctx.IsSet("method") { + m := abi.MethodNum(cctx.Int64("method")) + methodFilter = &m + } + + var out []*types.SignedMessage + for _, m := range pending { + if toFilter != address.Undef && m.Message.To != toFilter { + continue + } + + if fromFilter != address.Undef && m.Message.From != fromFilter { + continue + } + + if methodFilter != nil && *methodFilter != m.Message.Method { + continue + } + + out = append(out, m) + } + + b, err := json.MarshalIndent(out, "", " ") + if err != nil { + return err + } + + fmt.Println(string(b)) + return nil + }, +} diff --git a/cli/multisig.go b/cli/multisig.go index ef38c8168..983bf55c1 100644 --- a/cli/multisig.go +++ b/cli/multisig.go @@ -12,15 +12,14 @@ import ( "text/tabwriter" "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/go-address" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" samsig "github.com/filecoin-project/specs-actors/actors/builtin/multisig" cid "github.com/ipfs/go-cid" - "github.com/ipfs/go-hamt-ipld" cbor "github.com/ipfs/go-ipld-cbor" "github.com/urfave/cli/v2" - cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/api" @@ -68,6 +67,10 @@ var msigCreateCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + if cctx.Args().Len() < 1 { + return ShowHelp(cctx, fmt.Errorf("multisigs must have at least one signer")) + } + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -75,10 +78,6 @@ var msigCreateCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) - if cctx.Args().Len() < 1 { - return fmt.Errorf("multisigs must have at least one signer") - } - var addrs []address.Address for _, a := range cctx.Args().Slice() { addr, err := address.NewFromString(a) @@ -159,6 +158,10 @@ var msigInspectCmd = &cli.Command{ ArgsUsage: "[address]", Flags: []cli.Flag{}, Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return ShowHelp(cctx, fmt.Errorf("must specify address of multisig to inspect")) + } + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -166,10 +169,6 @@ var msigInspectCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) - if !cctx.Args().Present() { - return fmt.Errorf("must specify address of multisig to inspect") - } - maddr, err := address.NewFromString(cctx.Args().First()) if err != nil { return err @@ -237,24 +236,20 @@ var msigInspectCmd = &cli.Command{ func GetMultisigPending(ctx context.Context, lapi api.FullNode, hroot cid.Cid) (map[int64]*samsig.Transaction, error) { bs := apibstore.NewAPIBlockstore(lapi) - cst := cbor.NewCborStore(bs) + store := adt.WrapStore(ctx, cbor.NewCborStore(bs)) - nd, err := hamt.LoadNode(ctx, cst, hroot, hamt.UseTreeBitWidth(5)) + nd, err := adt.AsMap(store, hroot) if err != nil { return nil, err } txs := make(map[int64]*samsig.Transaction) - err = nd.ForEach(ctx, func(k string, val interface{}) error { - d := val.(*cbg.Deferred) - var tx samsig.Transaction - if err := tx.UnmarshalCBOR(bytes.NewReader(d.Raw)); err != nil { - return err - } - + var tx samsig.Transaction + err = nd.ForEach(&tx, func(k string) error { txid, _ := binary.Varint([]byte(k)) - txs[txid] = &tx + cpy := tx // copy so we don't clobber on future iterations. + txs[txid] = &cpy return nil }) if err != nil { @@ -287,6 +282,14 @@ var msigProposeCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + if cctx.Args().Len() < 3 { + return ShowHelp(cctx, fmt.Errorf("must pass at least multisig address, destination, and value")) + } + + if cctx.Args().Len() > 3 && cctx.Args().Len() != 5 { + return ShowHelp(cctx, fmt.Errorf("must either pass three or five arguments")) + } + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -294,14 +297,6 @@ var msigProposeCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) - if cctx.Args().Len() < 3 { - return fmt.Errorf("must pass multisig address, destination, and value") - } - - if cctx.Args().Len() > 3 && cctx.Args().Len() != 5 { - return fmt.Errorf("usage: msig propose [ ]") - } - msig, err := address.NewFromString(cctx.Args().Get(0)) if err != nil { return err @@ -391,6 +386,14 @@ var msigApproveCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + if cctx.Args().Len() < 5 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address, message ID, proposer address, destination, and value")) + } + + if cctx.Args().Len() > 5 && cctx.Args().Len() != 7 { + return ShowHelp(cctx, fmt.Errorf("usage: msig approve [ ]")) + } + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -398,14 +401,6 @@ var msigApproveCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) - if cctx.Args().Len() < 5 { - return fmt.Errorf("must pass multisig address, message ID, proposer address, destination, and value") - } - - if cctx.Args().Len() > 5 && cctx.Args().Len() != 7 { - return fmt.Errorf("usage: msig approve [ ]") - } - msig, err := address.NewFromString(cctx.Args().Get(0)) if err != nil { return err @@ -500,6 +495,10 @@ var msigSwapProposeCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 3 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address, old signer address, new signer address")) + } + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -507,10 +506,6 @@ var msigSwapProposeCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) - if cctx.Args().Len() != 3 { - return fmt.Errorf("must pass multisig address, old signer address, new signer address") - } - msig, err := address.NewFromString(cctx.Args().Get(0)) if err != nil { return err @@ -572,6 +567,10 @@ var msigSwapApproveCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 5 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address, proposer address, transaction id, old signer address, new signer address")) + } + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -579,10 +578,6 @@ var msigSwapApproveCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) - if cctx.Args().Len() != 5 { - return fmt.Errorf("must pass multisig address, proposer address, transaction id, old signer address, new signer address") - } - msig, err := address.NewFromString(cctx.Args().Get(0)) if err != nil { return err @@ -654,6 +649,10 @@ var msigSwapCancelCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 4 { + return ShowHelp(cctx, fmt.Errorf("must pass multisig address, transaction id, old signer address, new signer address")) + } + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -661,10 +660,6 @@ var msigSwapCancelCmd = &cli.Command{ defer closer() ctx := ReqContext(cctx) - if cctx.Args().Len() != 4 { - return fmt.Errorf("must pass multisig address, transaction id, old signer address, new signer address") - } - msig, err := address.NewFromString(cctx.Args().Get(0)) if err != nil { return err diff --git a/cli/paych.go b/cli/paych.go index 070645152..4c191505b 100644 --- a/cli/paych.go +++ b/cli/paych.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/base64" "fmt" + "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/go-address" @@ -20,6 +21,8 @@ var paychCmd = &cli.Command{ paychGetCmd, paychListCmd, paychVoucherCmd, + paychSettleCmd, + paychCloseCmd, }, } @@ -29,22 +32,22 @@ var paychGetCmd = &cli.Command{ ArgsUsage: "[fromAddress toAddress amount]", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 3 { - return fmt.Errorf("must pass three arguments: ") + return ShowHelp(cctx, fmt.Errorf("must pass three arguments: ")) } from, err := address.NewFromString(cctx.Args().Get(0)) if err != nil { - return fmt.Errorf("failed to parse from address: %s", err) + return ShowHelp(cctx, fmt.Errorf("failed to parse from address: %s", err)) } to, err := address.NewFromString(cctx.Args().Get(1)) if err != nil { - return fmt.Errorf("failed to parse to address: %s", err) + return ShowHelp(cctx, fmt.Errorf("failed to parse to address: %s", err)) } amt, err := types.BigFromString(cctx.Args().Get(2)) if err != nil { - return fmt.Errorf("parsing amount failed: %s", err) + return ShowHelp(cctx, fmt.Errorf("parsing amount failed: %s", err)) } api, closer, err := GetFullNodeAPI(cctx) @@ -89,6 +92,86 @@ var paychListCmd = &cli.Command{ }, } +var paychSettleCmd = &cli.Command{ + Name: "settle", + Usage: "Settle a payment channel", + ArgsUsage: "[channelAddress]", + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 1 { + return fmt.Errorf("must pass payment channel address") + } + + ch, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return fmt.Errorf("failed to parse payment channel address: %s", err) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + mcid, err := api.PaychSettle(ctx, ch) + if err != nil { + return err + } + + mwait, err := api.StateWaitMsg(ctx, mcid, build.MessageConfidence) + if err != nil { + return nil + } + if mwait.Receipt.ExitCode != 0 { + return fmt.Errorf("settle message execution failed (exit code %d)", mwait.Receipt.ExitCode) + } + + fmt.Printf("Settled channel %s\n", ch) + return nil + }, +} + +var paychCloseCmd = &cli.Command{ + Name: "collect", + Usage: "Collect funds for a payment channel", + ArgsUsage: "[channelAddress]", + Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 1 { + return fmt.Errorf("must pass payment channel address") + } + + ch, err := address.NewFromString(cctx.Args().Get(0)) + if err != nil { + return fmt.Errorf("failed to parse payment channel address: %s", err) + } + + api, closer, err := GetFullNodeAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := ReqContext(cctx) + + mcid, err := api.PaychCollect(ctx, ch) + if err != nil { + return err + } + + mwait, err := api.StateWaitMsg(ctx, mcid, build.MessageConfidence) + if err != nil { + return nil + } + if mwait.Receipt.ExitCode != 0 { + return fmt.Errorf("collect message execution failed (exit code %d)", mwait.Receipt.ExitCode) + } + + fmt.Printf("Collected funds for channel %s\n", ch) + return nil + }, +} + var paychVoucherCmd = &cli.Command{ Name: "voucher", Usage: "Interact with payment channel vouchers", @@ -115,7 +198,7 @@ var paychVoucherCreateCmd = &cli.Command{ }, Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 2 { - return fmt.Errorf("must pass two arguments: ") + return ShowHelp(cctx, fmt.Errorf("must pass two arguments: ")) } ch, err := address.NewFromString(cctx.Args().Get(0)) @@ -159,7 +242,7 @@ var paychVoucherCheckCmd = &cli.Command{ ArgsUsage: "[channelAddress voucher]", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 2 { - return fmt.Errorf("must pass payment channel address and voucher to validate") + return ShowHelp(cctx, fmt.Errorf("must pass payment channel address and voucher to validate")) } ch, err := address.NewFromString(cctx.Args().Get(0)) @@ -195,7 +278,7 @@ var paychVoucherAddCmd = &cli.Command{ ArgsUsage: "[channelAddress voucher]", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 2 { - return fmt.Errorf("must pass payment channel address and voucher") + return ShowHelp(cctx, fmt.Errorf("must pass payment channel address and voucher")) } ch, err := address.NewFromString(cctx.Args().Get(0)) @@ -237,7 +320,7 @@ var paychVoucherListCmd = &cli.Command{ }, Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 1 { - return fmt.Errorf("must pass payment channel address") + return ShowHelp(cctx, fmt.Errorf("must pass payment channel address")) } ch, err := address.NewFromString(cctx.Args().Get(0)) @@ -281,7 +364,7 @@ var paychVoucherBestSpendableCmd = &cli.Command{ ArgsUsage: "[channelAddress]", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 1 { - return fmt.Errorf("must pass payment channel address") + return ShowHelp(cctx, fmt.Errorf("must pass payment channel address")) } ch, err := address.NewFromString(cctx.Args().Get(0)) @@ -336,7 +419,7 @@ var paychVoucherSubmitCmd = &cli.Command{ ArgsUsage: "[channelAddress voucher]", Action: func(cctx *cli.Context) error { if cctx.Args().Len() != 2 { - return fmt.Errorf("must pass payment channel address and voucher") + return ShowHelp(cctx, fmt.Errorf("must pass payment channel address and voucher")) } ch, err := address.NewFromString(cctx.Args().Get(0)) diff --git a/cli/send.go b/cli/send.go index ce7879a97..a528f355e 100644 --- a/cli/send.go +++ b/cli/send.go @@ -1,11 +1,20 @@ package cli import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" "fmt" + "reflect" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/specs-actors/actors/abi" "github.com/urfave/cli/v2" + cbg "github.com/whyrusleeping/cbor-gen" ) var sendCmd = &cli.Command{ @@ -22,13 +31,35 @@ var sendCmd = &cli.Command{ Usage: "specify gas price to use in AttoFIL", Value: "0", }, + &cli.Int64Flag{ + Name: "gas-limit", + Usage: "specify gas limit", + Value: 0, + }, &cli.Int64Flag{ Name: "nonce", Usage: "specify the nonce to use", Value: -1, }, + &cli.Uint64Flag{ + Name: "method", + Usage: "specify method to invoke", + Value: 0, + }, + &cli.StringFlag{ + Name: "params-json", + Usage: "specify invocation parameters in json", + }, + &cli.StringFlag{ + Name: "params-hex", + Usage: "specify invocation parameters in hex", + }, }, Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 2 { + return ShowHelp(cctx, fmt.Errorf("'send' expects two arguments, target and amount")) + } + api, closer, err := GetFullNodeAPI(cctx) if err != nil { return err @@ -37,18 +68,14 @@ var sendCmd = &cli.Command{ ctx := ReqContext(cctx) - if cctx.Args().Len() != 2 { - return fmt.Errorf("'send' expects two arguments, target and amount") - } - toAddr, err := address.NewFromString(cctx.Args().Get(0)) if err != nil { - return err + return ShowHelp(cctx, fmt.Errorf("failed to parse target address: %w", err)) } val, err := types.ParseFIL(cctx.Args().Get(1)) if err != nil { - return err + return ShowHelp(cctx, fmt.Errorf("failed to parse amount: %w", err)) } var fromAddr address.Address @@ -73,11 +100,35 @@ var sendCmd = &cli.Command{ return err } + method := abi.MethodNum(cctx.Uint64("method")) + + var params []byte + if cctx.IsSet("params-json") { + decparams, err := decodeTypedParams(ctx, api, toAddr, method, cctx.String("params-json")) + if err != nil { + return fmt.Errorf("failed to decode json params: %w", err) + } + params = decparams + } + if cctx.IsSet("params-hex") { + if params != nil { + return fmt.Errorf("can only specify one of 'params-json' and 'params-hex'") + } + decparams, err := hex.DecodeString(cctx.String("params-hex")) + if err != nil { + return fmt.Errorf("failed to decode hex params: %w", err) + } + params = decparams + } + msg := &types.Message{ From: fromAddr, To: toAddr, Value: types.BigInt(val), GasPrice: gp, + GasLimit: cctx.Int64("gas-limit"), + Method: method, + Params: params, } if cctx.Int64("nonce") > 0 { @@ -103,3 +154,22 @@ var sendCmd = &cli.Command{ return nil }, } + +func decodeTypedParams(ctx context.Context, fapi api.FullNode, to address.Address, method abi.MethodNum, paramstr string) ([]byte, error) { + act, err := fapi.StateGetActor(ctx, to, types.EmptyTSK) + if err != nil { + return nil, err + } + + p := reflect.New(stmgr.MethodsMap[act.Code][method].Params.Elem()).Interface().(cbg.CBORMarshaler) + + if err := json.Unmarshal([]byte(paramstr), p); err != nil { + return nil, fmt.Errorf("unmarshaling input into params type: %w", err) + } + + buf := new(bytes.Buffer) + if err := p.MarshalCBOR(buf); err != nil { + return nil, err + } + return buf.Bytes(), nil +} diff --git a/cmd/lotus-bench/import.go b/cmd/lotus-bench/import.go index 3c56a5707..9ea3e8d0f 100644 --- a/cmd/lotus-bench/import.go +++ b/cmd/lotus-bench/import.go @@ -466,6 +466,7 @@ var importAnalyzeCmd = &cli.Command{ if err != nil { return err } + defer fi.Close() //nolint:errcheck const nWorkers = 16 jsonIn := make(chan []byte, 2*nWorkers) diff --git a/cmd/lotus-chainwatch/main.go b/cmd/lotus-chainwatch/main.go index 4972c1d0d..bcea3193d 100644 --- a/cmd/lotus-chainwatch/main.go +++ b/cmd/lotus-chainwatch/main.go @@ -1,7 +1,6 @@ package main import ( - _ "net/http/pprof" "os" "github.com/filecoin-project/lotus/build" diff --git a/cmd/lotus-chainwatch/processor/common_actors.go b/cmd/lotus-chainwatch/processor/common_actors.go index 81caf666b..3baad612d 100644 --- a/cmd/lotus-chainwatch/processor/common_actors.go +++ b/cmd/lotus-chainwatch/processor/common_actors.go @@ -207,7 +207,8 @@ create temp table iam (like id_address_map excluding constraints) on commit drop return err } - if _, err := tx.Exec(`insert into id_address_map select * from iam on conflict do nothing `); err != nil { + // HACK until chain watch can handle reorgs we need to update this table when ID -> PubKey mappings change + if _, err := tx.Exec(`insert into id_address_map select * from iam on conflict (id) do update set address = EXCLUDED.address`); err != nil { return xerrors.Errorf("actor put: %w", err) } diff --git a/cmd/lotus-chainwatch/run.go b/cmd/lotus-chainwatch/run.go index 2497b5315..0ed08cf8d 100644 --- a/cmd/lotus-chainwatch/run.go +++ b/cmd/lotus-chainwatch/run.go @@ -2,6 +2,8 @@ package main import ( "database/sql" + "net/http" + _ "net/http/pprof" "os" _ "github.com/lib/pq" @@ -12,6 +14,7 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/processor" + "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/scheduler" "github.com/filecoin-project/lotus/cmd/lotus-chainwatch/syncer" ) @@ -25,6 +28,9 @@ var runCmd = &cli.Command{ }, }, Action: func(cctx *cli.Context) error { + go func() { + http.ListenAndServe(":6060", nil) + }() ll := cctx.String("log-level") if err := logging.SetLogLevel("*", ll); err != nil { return err @@ -70,6 +76,9 @@ var runCmd = &cli.Command{ proc := processor.NewProcessor(db, api, maxBatch) proc.Start(ctx) + sched := scheduler.PrepareScheduler(db) + sched.Start(ctx) + <-ctx.Done() os.Exit(0) return nil diff --git a/cmd/lotus-chainwatch/scheduler/refresh_top_miners_by_base_reward.go b/cmd/lotus-chainwatch/scheduler/refresh_top_miners_by_base_reward.go new file mode 100644 index 000000000..50bb561a1 --- /dev/null +++ b/cmd/lotus-chainwatch/scheduler/refresh_top_miners_by_base_reward.go @@ -0,0 +1,29 @@ +package scheduler + +import ( + "context" + "database/sql" + "time" + + "golang.org/x/xerrors" +) + +func refreshTopMinerByBaseReward(ctx context.Context, db *sql.DB) error { + select { + case <-ctx.Done(): + return nil + default: + } + + t := time.Now() + defer func() { + log.Debugw("refresh top_miners_by_base_reward", "duration", time.Since(t).String()) + }() + + _, err := db.Exec("REFRESH MATERIALIZED VIEW top_miners_by_base_reward;") + if err != nil { + return xerrors.Errorf("refresh top_miners_by_base_reward: %w", err) + } + + return nil +} diff --git a/cmd/lotus-chainwatch/scheduler/scheduler.go b/cmd/lotus-chainwatch/scheduler/scheduler.go new file mode 100644 index 000000000..c5c93c310 --- /dev/null +++ b/cmd/lotus-chainwatch/scheduler/scheduler.go @@ -0,0 +1,47 @@ +package scheduler + +import ( + "context" + "database/sql" + "time" + + logging "github.com/ipfs/go-log/v2" +) + +var log = logging.Logger("scheduler") + +// Scheduler manages the execution of jobs triggered +// by tickers. Not externally configuable at runtime. +type Scheduler struct { + db *sql.DB +} + +// PrepareScheduler returns a ready-to-run Scheduler +func PrepareScheduler(db *sql.DB) *Scheduler { + return &Scheduler{db} +} + +// Start the scheduler jobs at the defined intervals +func (s *Scheduler) Start(ctx context.Context) { + log.Debug("Starting Scheduler") + + go func() { + // run once on start after schema has initialized + time.Sleep(5 * time.Second) + if err := refreshTopMinerByBaseReward(ctx, s.db); err != nil { + log.Errorf(err.Error()) + } + refreshTopMinerCh := time.NewTicker(6 * time.Hour) + defer refreshTopMinerCh.Stop() + for { + select { + case <-refreshTopMinerCh.C: + if err := refreshTopMinerByBaseReward(ctx, s.db); err != nil { + log.Errorf(err.Error()) + } + case <-ctx.Done(): + return + } + } + }() +} diff --git a/cmd/lotus-seal-worker/main.go b/cmd/lotus-seal-worker/main.go index 805777e7a..82154d328 100644 --- a/cmd/lotus-seal-worker/main.go +++ b/cmd/lotus-seal-worker/main.go @@ -9,6 +9,7 @@ import ( "net/http" "os" "path/filepath" + "strings" "syscall" "time" @@ -93,7 +94,8 @@ var runCmd = &cli.Command{ Flags: []cli.Flag{ &cli.StringFlag{ Name: "address", - Usage: "Locally reachable address", + Usage: "locally reachable address", + Value: "0.0.0.0", }, &cli.BoolFlag{ Name: "no-local-storage", @@ -114,6 +116,11 @@ var runCmd = &cli.Command{ Usage: "enable commit (32G sectors: all cores or GPUs, 128GiB Memory + 64GiB swap)", Value: true, }, + &cli.StringFlag{ + Name: "timeout", + Usage: "used when address is unspecified. must be a valid duration recognized by golang's time.ParseDuration function", + Value: "30m", + }, }, Action: func(cctx *cli.Context) error { if !cctx.Bool("enable-gpu-proving") { @@ -122,10 +129,6 @@ var runCmd = &cli.Command{ } } - if cctx.String("address") == "" { - return xerrors.Errorf("--address flag is required") - } - // Connect to storage-miner var nodeApi api.StorageMiner var closer func() @@ -259,8 +262,24 @@ var runCmd = &cli.Command{ } log.Info("Opening local storage; connecting to master") + const unspecifiedAddress = "0.0.0.0" + address := cctx.String("address") + addressSlice := strings.Split(address, ":") + if ip := net.ParseIP(addressSlice[0]); ip != nil { + if ip.String() == unspecifiedAddress { + timeout, err := time.ParseDuration(cctx.String("timeout")) + if err != nil { + return err + } + rip, err := extractRoutableIP(timeout) + if err != nil { + return err + } + address = rip + ":" + addressSlice[1] + } + } - localStore, err := stores.NewLocal(ctx, lr, nodeApi, []string{"http://" + cctx.String("address") + "/remote"}) + localStore, err := stores.NewLocal(ctx, lr, nodeApi, []string{"http://" + address + "/remote"}) if err != nil { return err } @@ -289,7 +308,7 @@ var runCmd = &cli.Command{ mux := mux.NewRouter() - log.Info("Setting up control endpoint at " + cctx.String("address")) + log.Info("Setting up control endpoint at " + address) rpcServer := jsonrpc.NewServer() rpcServer.Register("Filecoin", apistruct.PermissionedWorkerAPI(workerApi)) @@ -319,7 +338,7 @@ var runCmd = &cli.Command{ log.Warn("Graceful shutdown successful") }() - nl, err := net.Listen("tcp", cctx.String("address")) + nl, err := net.Listen("tcp", address) if err != nil { return err } @@ -327,7 +346,7 @@ var runCmd = &cli.Command{ log.Info("Waiting for tasks") go func() { - if err := nodeApi.WorkerConnect(ctx, "ws://"+cctx.String("address")+"/rpc/v0"); err != nil { + if err := nodeApi.WorkerConnect(ctx, "ws://"+address+"/rpc/v0"); err != nil { log.Errorf("Registering worker failed: %+v", err) cancel() return @@ -376,3 +395,27 @@ func watchMinerConn(ctx context.Context, cctx *cli.Context, nodeApi api.StorageM } }() } + +func extractRoutableIP(timeout time.Duration) (string, error) { + minerMultiAddrKey := "MINER_API_INFO" + deprecatedMinerMultiAddrKey := "STORAGE_API_INFO" + env, ok := os.LookupEnv(minerMultiAddrKey) + if !ok { + // TODO remove after deprecation period + env, ok = os.LookupEnv(deprecatedMinerMultiAddrKey) + if ok { + log.Warnf("Using a deprecated env(%s) value, please use env(%s) instead.", deprecatedMinerMultiAddrKey, minerMultiAddrKey) + } + return "", xerrors.New("MINER_API_INFO environment variable required to extract IP") + } + minerAddr := strings.Split(env, "/") + conn, err := net.DialTimeout("tcp", minerAddr[2]+":"+minerAddr[4], timeout) + if err != nil { + return "", err + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.TCPAddr) + + return strings.Split(localAddr.IP.String(), ":")[0], nil +} diff --git a/cmd/lotus-seed/genesis.go b/cmd/lotus-seed/genesis.go index 478e30b97..3a9545d2d 100644 --- a/cmd/lotus-seed/genesis.go +++ b/cmd/lotus-seed/genesis.go @@ -241,6 +241,7 @@ func parseMultisigCsv(csvf string) ([]GenAccountEntry, error) { if err != nil { return nil, xerrors.Errorf("read multisig csv: %w", err) } + defer fileReader.Close() //nolint:errcheck r := csv.NewReader(fileReader) records, err := r.ReadAll() if err != nil { diff --git a/cmd/lotus-seed/main.go b/cmd/lotus-seed/main.go index cf0f166d9..67762e4dd 100644 --- a/cmd/lotus-seed/main.go +++ b/cmd/lotus-seed/main.go @@ -155,6 +155,9 @@ var aggregateManifestsCmd = &cli.Command{ } inputs = append(inputs, val) + if err := fi.Close(); err != nil { + return err + } } output := make(map[string]genesis.Miner) diff --git a/cmd/lotus-shed/import-car.go b/cmd/lotus-shed/import-car.go index e54089df0..3347f9825 100644 --- a/cmd/lotus-shed/import-car.go +++ b/cmd/lotus-shed/import-car.go @@ -65,11 +65,17 @@ var importCarCmd = &cli.Command{ fmt.Println() return ds.Close() default: + if err := f.Close(); err != nil { + return err + } fmt.Println() return err case nil: fmt.Printf("\r%s", blk.Cid()) if err := bs.Put(blk); err != nil { + if err := f.Close(); err != nil { + return err + } return xerrors.Errorf("put %s: %w", blk.Cid(), err) } } diff --git a/cmd/lotus-shed/keyinfo.go b/cmd/lotus-shed/keyinfo.go index 028ead413..d4272e5bc 100644 --- a/cmd/lotus-shed/keyinfo.go +++ b/cmd/lotus-shed/keyinfo.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "encoding/base64" "encoding/hex" "encoding/json" @@ -64,10 +65,12 @@ var keyinfoImportCmd = &cli.Command{ input = os.Stdin } else { var err error - input, err = os.Open(cctx.Args().First()) + inputFile, err := os.Open(cctx.Args().First()) if err != nil { return err } + defer inputFile.Close() + input = bufio.NewReader(inputFile) } encoded, err := ioutil.ReadAll(input) @@ -174,10 +177,12 @@ var keyinfoInfoCmd = &cli.Command{ input = os.Stdin } else { var err error - input, err = os.Open(cctx.Args().First()) + inputFile, err := os.Open(cctx.Args().First()) if err != nil { return err } + defer inputFile.Close() + input = bufio.NewReader(inputFile) } encoded, err := ioutil.ReadAll(input) diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index c37b93a42..15cd3cfb3 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -27,6 +27,8 @@ func main() { fetchParamCmd, proofsCmd, verifRegCmd, + miscCmd, + mpoolCmd, } app := &cli.App{ diff --git a/cmd/lotus-shed/misc.go b/cmd/lotus-shed/misc.go new file mode 100644 index 000000000..b342fab0a --- /dev/null +++ b/cmd/lotus-shed/misc.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "strconv" + + "github.com/filecoin-project/go-fil-markets/storagemarket" + "github.com/urfave/cli/v2" +) + +var miscCmd = &cli.Command{ + Name: "misc", + Usage: "Assorted unsorted commands for various purposes", + Flags: []cli.Flag{}, + Subcommands: []*cli.Command{ + dealStateMappingCmd, + }, +} + +var dealStateMappingCmd = &cli.Command{ + Name: "deal-state", + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return cli.ShowCommandHelp(cctx, cctx.Command.Name) + } + + num, err := strconv.Atoi(cctx.Args().First()) + if err != nil { + return err + } + + ststr, ok := storagemarket.DealStates[uint64(num)] + if !ok { + return fmt.Errorf("no such deal state %d", num) + } + fmt.Println(ststr) + return nil + }, +} diff --git a/cmd/lotus-shed/mpool.go b/cmd/lotus-shed/mpool.go new file mode 100644 index 000000000..eddf5b7f8 --- /dev/null +++ b/cmd/lotus-shed/mpool.go @@ -0,0 +1,50 @@ +package main + +import ( + "fmt" + + lcli "github.com/filecoin-project/lotus/cli" + "github.com/filecoin-project/lotus/miner" + "github.com/urfave/cli/v2" +) + +var mpoolCmd = &cli.Command{ + Name: "mpool", + Usage: "Tools for diagnosing mempool issues", + Flags: []cli.Flag{}, + Subcommands: []*cli.Command{ + minerSelectMsgsCmd, + }, +} + +var minerSelectMsgsCmd = &cli.Command{ + Name: "miner-select-msgs", + Action: func(cctx *cli.Context) error { + api, closer, err := lcli.GetFullNodeAPI(cctx) + if err != nil { + return err + } + + defer closer() + ctx := lcli.ReqContext(cctx) + + head, err := api.ChainHead(ctx) + if err != nil { + return err + } + + msgs, err := api.MpoolPending(ctx, head.Key()) + if err != nil { + return err + } + + filtered, err := miner.SelectMessages(ctx, api.StateGetActor, head, msgs) + if err != nil { + return err + } + + fmt.Println("mempool input messages: ", len(msgs)) + fmt.Println("filtered messages: ", len(filtered)) + return nil + }, +} diff --git a/cmd/lotus-shed/verifreg.go b/cmd/lotus-shed/verifreg.go index 90d12bee4..ba7c3004d 100644 --- a/cmd/lotus-shed/verifreg.go +++ b/cmd/lotus-shed/verifreg.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "fmt" "github.com/filecoin-project/go-address" @@ -16,10 +15,8 @@ import ( "github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin/verifreg" - "github.com/ipfs/go-hamt-ipld" + "github.com/filecoin-project/specs-actors/actors/util/adt" cbor "github.com/ipfs/go-ipld-cbor" - - cbg "github.com/whyrusleeping/cbor-gen" ) var verifRegCmd = &cli.Command{ @@ -193,30 +190,25 @@ var verifRegListVerifiersCmd = &cli.Command{ } apibs := apibstore.NewAPIBlockstore(api) - cst := cbor.NewCborStore(apibs) + store := adt.WrapStore(ctx, cbor.NewCborStore(apibs)) var st verifreg.State - if err := cst.Get(ctx, act.Head, &st); err != nil { + if err := store.Get(ctx, act.Head, &st); err != nil { return err } - vh, err := hamt.LoadNode(ctx, cst, st.Verifiers, hamt.UseTreeBitWidth(5)) + vh, err := adt.AsMap(store, st.Verifiers) if err != nil { return err } - if err := vh.ForEach(ctx, func(k string, val interface{}) error { + var dcap verifreg.DataCap + if err := vh.ForEach(&dcap, func(k string) error { addr, err := address.NewFromBytes([]byte(k)) if err != nil { return err } - var dcap verifreg.DataCap - - if err := dcap.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil { - return err - } - fmt.Printf("%s: %s\n", addr, dcap) return nil @@ -245,30 +237,25 @@ var verifRegListClientsCmd = &cli.Command{ } apibs := apibstore.NewAPIBlockstore(api) - cst := cbor.NewCborStore(apibs) + store := adt.WrapStore(ctx, cbor.NewCborStore(apibs)) var st verifreg.State - if err := cst.Get(ctx, act.Head, &st); err != nil { + if err := store.Get(ctx, act.Head, &st); err != nil { return err } - vh, err := hamt.LoadNode(ctx, cst, st.VerifiedClients, hamt.UseTreeBitWidth(5)) + vh, err := adt.AsMap(store, st.VerifiedClients) if err != nil { return err } - if err := vh.ForEach(ctx, func(k string, val interface{}) error { + var dcap verifreg.DataCap + if err := vh.ForEach(&dcap, func(k string) error { addr, err := address.NewFromBytes([]byte(k)) if err != nil { return err } - var dcap verifreg.DataCap - - if err := dcap.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil { - return err - } - fmt.Printf("%s: %s\n", addr, dcap) return nil @@ -340,21 +327,23 @@ var verifRegCheckVerifierCmd = &cli.Command{ } apibs := apibstore.NewAPIBlockstore(api) - cst := cbor.NewCborStore(apibs) + store := adt.WrapStore(ctx, cbor.NewCborStore(apibs)) var st verifreg.State - if err := cst.Get(ctx, act.Head, &st); err != nil { + if err := store.Get(ctx, act.Head, &st); err != nil { return err } - vh, err := hamt.LoadNode(ctx, cst, st.Verifiers, hamt.UseTreeBitWidth(5)) + vh, err := adt.AsMap(store, st.Verifiers) if err != nil { return err } var dcap verifreg.DataCap - if err := vh.Find(ctx, string(vaddr.Bytes()), &dcap); err != nil { + if found, err := vh.Get(adt.AddrKey(vaddr), &dcap); err != nil { return err + } else if !found { + return fmt.Errorf("not found") } fmt.Println(dcap) diff --git a/cmd/lotus-storage-miner/main.go b/cmd/lotus-storage-miner/main.go index 5fec6ad22..0f24d4c35 100644 --- a/cmd/lotus-storage-miner/main.go +++ b/cmd/lotus-storage-miner/main.go @@ -3,7 +3,6 @@ package main import ( "context" "fmt" - "os" logging "github.com/ipfs/go-log/v2" "github.com/urfave/cli/v2" @@ -30,18 +29,18 @@ func main() { lotuslog.SetupLogLevels() local := []*cli.Command{ - actorCmd, - storageDealsCmd, - retrievalDealsCmd, - infoCmd, initCmd, - rewardsCmd, runCmd, stopCmd, - sectorsCmd, - storageCmd, - workersCmd, - provingCmd, + lcli.WithCategory("chain", actorCmd), + lcli.WithCategory("chain", rewardsCmd), + lcli.WithCategory("chain", infoCmd), + lcli.WithCategory("market", storageDealsCmd), + lcli.WithCategory("market", retrievalDealsCmd), + lcli.WithCategory("storage", sectorsCmd), + lcli.WithCategory("storage", provingCmd), + lcli.WithCategory("storage", storageCmd), + lcli.WithCategory("storage", sealingCmd), } jaeger := tracing.SetupJaegerTracing("lotus") defer func() { @@ -96,10 +95,7 @@ func main() { app.Setup() app.Metadata["repoType"] = repo.StorageMiner - if err := app.Run(os.Args); err != nil { - log.Warnf("%+v", err) - os.Exit(1) - } + lcli.RunApp(app) } func getActorAddress(ctx context.Context, nodeAPI api.StorageMiner, overrideMaddr string) (maddr address.Address, err error) { diff --git a/cmd/lotus-storage-miner/workers.go b/cmd/lotus-storage-miner/sealing.go similarity index 63% rename from cmd/lotus-storage-miner/workers.go rename to cmd/lotus-storage-miner/sealing.go index 009d2fb90..68b0a246f 100644 --- a/cmd/lotus-storage-miner/workers.go +++ b/cmd/lotus-storage-miner/sealing.go @@ -2,8 +2,12 @@ package main import ( "fmt" + "golang.org/x/xerrors" + "os" "sort" "strings" + "text/tabwriter" + "time" "github.com/fatih/color" "github.com/urfave/cli/v2" @@ -14,16 +18,17 @@ import ( lcli "github.com/filecoin-project/lotus/cli" ) -var workersCmd = &cli.Command{ - Name: "workers", - Usage: "interact with workers", +var sealingCmd = &cli.Command{ + Name: "sealing", + Usage: "interact with sealing pipeline", Subcommands: []*cli.Command{ - workersListCmd, + sealingJobsCmd, + sealingWorkersCmd, }, } -var workersListCmd = &cli.Command{ - Name: "list", +var sealingWorkersCmd = &cli.Command{ + Name: "workers", Usage: "list workers", Flags: []cli.Flag{ &cli.BoolFlag{Name: "color"}, @@ -106,3 +111,68 @@ var workersListCmd = &cli.Command{ return nil }, } + +var sealingJobsCmd = &cli.Command{ + Name: "jobs", + Usage: "list workers", + Flags: []cli.Flag{ + &cli.BoolFlag{Name: "color"}, + }, + Action: func(cctx *cli.Context) error { + color.NoColor = !cctx.Bool("color") + + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) + if err != nil { + return err + } + defer closer() + + ctx := lcli.ReqContext(cctx) + + jobs, err := nodeApi.WorkerJobs(ctx) + if err != nil { + return xerrors.Errorf("getting worker jobs: %w", err) + } + + type line struct { + storiface.WorkerJob + wid uint64 + } + + lines := make([]line, 0) + + for wid, jobs := range jobs { + for _, job := range jobs { + lines = append(lines, line{ + WorkerJob: job, + wid: wid, + }) + } + } + + // oldest first + sort.Slice(lines, func(i, j int) bool { + return lines[i].Start.Before(lines[j].Start) + }) + + workerHostnames := map[uint64]string{} + + wst, err := nodeApi.WorkerStats(ctx) + if err != nil { + return xerrors.Errorf("getting worker stats: %w", err) + } + + for wid, st := range wst { + workerHostnames[wid] = st.Info.Hostname + } + + tw := tabwriter.NewWriter(os.Stdout, 2, 4, 2, ' ', 0) + _, _ = fmt.Fprintf(tw, "ID\tSector\tWorker\tHostname\tTask\tTime\n") + + for _, l := range lines { + _, _ = fmt.Fprintf(tw, "%d\t%d\t%d\t%s\t%s\t%s\n", l.ID, l.Sector.Number, l.wid, workerHostnames[l.wid], l.Task.Short(), time.Now().Sub(l.Start).Truncate(time.Millisecond*100)) + } + + return tw.Flush() + }, +} diff --git a/cmd/lotus-storage-miner/sectors.go b/cmd/lotus-storage-miner/sectors.go index 24cb7d5f6..5166d1c3d 100644 --- a/cmd/lotus-storage-miner/sectors.go +++ b/cmd/lotus-storage-miner/sectors.go @@ -82,16 +82,16 @@ var sectorsStatusCmd = &cli.Command{ } fmt.Printf("SectorID:\t%d\n", status.SectorID) - fmt.Printf("Status:\t%s\n", status.State) - fmt.Printf("CommD:\t\t%x\n", status.CommD) - fmt.Printf("CommR:\t\t%x\n", status.CommR) + fmt.Printf("Status:\t\t%s\n", status.State) + fmt.Printf("CIDcommD:\t%s\n", status.CommD) + fmt.Printf("CIDcommR:\t%s\n", status.CommR) fmt.Printf("Ticket:\t\t%x\n", status.Ticket.Value) - fmt.Printf("TicketH:\t\t%d\n", status.Ticket.Epoch) + fmt.Printf("TicketH:\t%d\n", status.Ticket.Epoch) fmt.Printf("Seed:\t\t%x\n", status.Seed.Value) fmt.Printf("SeedH:\t\t%d\n", status.Seed.Epoch) fmt.Printf("Proof:\t\t%x\n", status.Proof) fmt.Printf("Deals:\t\t%v\n", status.Deals) - fmt.Printf("Retries:\t\t%d\n", status.Retries) + fmt.Printf("Retries:\t%d\n", status.Retries) if status.LastErr != "" { fmt.Printf("Last Error:\t\t%s\n", status.LastErr) } @@ -251,15 +251,16 @@ var sectorsMarkForUpgradeCmd = &cli.Command{ Usage: "Mark a committed capacity sector for replacement by a sector with deals", ArgsUsage: "", Action: func(cctx *cli.Context) error { + if cctx.Args().Len() != 1 { + return lcli.ShowHelp(cctx, xerrors.Errorf("must pass sector number")) + } + nodeApi, closer, err := lcli.GetStorageMinerAPI(cctx) if err != nil { return err } defer closer() ctx := lcli.ReqContext(cctx) - if cctx.Args().Len() != 1 { - return xerrors.Errorf("must pass sector number") - } id, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64) if err != nil { diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go index bb17c0d87..45a12fe98 100644 --- a/cmd/lotus/daemon.go +++ b/cmd/lotus/daemon.go @@ -317,6 +317,7 @@ func ImportChain(r repo.Repo, fname string) error { if err != nil { return err } + defer fi.Close() //nolint:errcheck lr, err := r.Lock(repo.FullNode) if err != nil { diff --git a/cmd/lotus/main.go b/cmd/lotus/main.go index 5376ce02a..1e2c7faec 100644 --- a/cmd/lotus/main.go +++ b/cmd/lotus/main.go @@ -2,7 +2,6 @@ package main import ( "context" - "os" "github.com/urfave/cli/v2" "go.opencensus.io/trace" @@ -69,17 +68,5 @@ func main() { app.Metadata["traceContext"] = ctx app.Metadata["repoType"] = repo.FullNode - if err := app.Run(os.Args); err != nil { - span.SetStatus(trace.Status{ - Code: trace.StatusCodeFailedPrecondition, - Message: err.Error(), - }) - _, ok := err.(*lcli.ErrCmdFailed) - if ok { - log.Debugf("%+v", err) - } else { - log.Warnf("%+v", err) - } - os.Exit(1) - } + lcli.RunApp(app) } diff --git a/go.mod b/go.mod index 2a7e52880..89a63ec2c 100644 --- a/go.mod +++ b/go.mod @@ -15,22 +15,21 @@ require ( github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4 github.com/drand/kyber v1.1.1 github.com/fatih/color v1.8.0 - github.com/filecoin-project/chain-validation v0.0.6-0.20200720093255-843129967fdf + github.com/filecoin-project/chain-validation v0.0.6-0.20200723211224-ffdcb7a20fe8 github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef - github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2 - github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1 + github.com/filecoin-project/go-bitfield v0.1.0 github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 - github.com/filecoin-project/go-data-transfer v0.4.1-0.20200715144713-b3311844e1a5 + github.com/filecoin-project/go-data-transfer v0.5.0 github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f - github.com/filecoin-project/go-fil-markets v0.4.1-0.20200715201050-c141144ea312 + github.com/filecoin-project/go-fil-markets v0.5.1 github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24 github.com/filecoin-project/go-paramfetch v0.0.2-0.20200701152213-3e0f0afdc261 github.com/filecoin-project/go-statestore v0.1.0 github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b - github.com/filecoin-project/sector-storage v0.0.0-20200717213554-a109ef9cbeab - github.com/filecoin-project/specs-actors v0.8.1-0.20200720115956-cd051eabf328 + github.com/filecoin-project/sector-storage v0.0.0-20200723200950-ed2e57dde6df + github.com/filecoin-project/specs-actors v0.8.1-0.20200724015154-3c690d9b7e1d github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea github.com/filecoin-project/storage-fsm v0.0.0-20200720190000-2cfe2fe3c334 github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1 @@ -53,8 +52,7 @@ require ( github.com/ipfs/go-ds-measure v0.1.0 github.com/ipfs/go-filestore v1.0.0 github.com/ipfs/go-fs-lock v0.0.1 - github.com/ipfs/go-graphsync v0.0.6-0.20200715142715-e2f27c4754e6 - github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f + github.com/ipfs/go-graphsync v0.0.6-0.20200715204712-ef06b3d32e83 github.com/ipfs/go-ipfs-blockstore v1.0.0 github.com/ipfs/go-ipfs-chunker v0.0.5 github.com/ipfs/go-ipfs-ds-help v1.0.0 @@ -109,7 +107,7 @@ require ( github.com/syndtr/goleveldb v1.0.0 github.com/urfave/cli/v2 v2.2.0 github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba - github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377 + github.com/whyrusleeping/cbor-gen v0.0.0-20200723182808-cb5de1c427f5 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 diff --git a/go.sum b/go.sum index 4acc25972..5bafb5f91 100644 --- a/go.sum +++ b/go.sum @@ -216,8 +216,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY= github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8= github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E= -github.com/filecoin-project/chain-validation v0.0.6-0.20200720093255-843129967fdf h1:7SkS/gSZv4ljQaQeDu4SfnF9CcvQuT9QCEf3+Hn1jp8= -github.com/filecoin-project/chain-validation v0.0.6-0.20200720093255-843129967fdf/go.mod h1:9xZvimiD8wsZbTNTUoACMPzXj4/fpIxeZBV2YjQcLhI= +github.com/filecoin-project/chain-validation v0.0.6-0.20200723211224-ffdcb7a20fe8 h1:WA2KU3u/FELAMVElQgiwEKTQe/QLUUsT52AnW4YjPjs= +github.com/filecoin-project/chain-validation v0.0.6-0.20200723211224-ffdcb7a20fe8/go.mod h1:P4FhsyLtySqsVFbOPpPVFeEShVQ4j/iA5Dzo8D2p978= github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0= github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef h1:Wi5E+P1QfHP8IF27eUiTx5vYfqQZwfPxzq3oFEq8w8U= @@ -225,23 +225,27 @@ github.com/filecoin-project/go-address v0.0.2-0.20200504173055-8b6f2fb2b3ef/go.m github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200131012142-05d80eeccc5e/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2 h1:jamfsxfK0Q9yCMHt8MPWx7Aa/O9k2Lve8eSc6FILYGQ= github.com/filecoin-project/go-amt-ipld/v2 v2.0.1-0.20200424220931-6263827e49f2/go.mod h1:boRtQhzmxNocrMxOXo1NYn4oUc1NGvR8tEa79wApNXg= +github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 h1:t6qDiuGYYngDqaLc2ZUvdtAg4UNxPeOYaXhBWSNsVaM= +github.com/filecoin-project/go-amt-ipld/v2 v2.1.0/go.mod h1:nfFPoGyX0CU9SkXX8EoCcSuHN1XcbN0c6KBh7yvP5fs= github.com/filecoin-project/go-bitfield v0.0.0-20200416002808-b3ee67ec9060/go.mod h1:iodsLxOFZnqKtjj2zkgqzoGNrv6vUqj69AT/J8DKXEw= github.com/filecoin-project/go-bitfield v0.0.1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= github.com/filecoin-project/go-bitfield v0.0.2-0.20200518150651-562fdb554b6e/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= github.com/filecoin-project/go-bitfield v0.0.3/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1 h1:xuHlrdznafh7ul5t4xEncnA4qgpQvJZEw+mr98eqHXw= github.com/filecoin-project/go-bitfield v0.0.4-0.20200703174658-f4a5758051a1/go.mod h1:Ry9/iUlWSyjPUzlAvdnfy4Gtvrq4kWmWDztCU1yEgJY= +github.com/filecoin-project/go-bitfield v0.1.0 h1:ZDAQjvXuLzbrLnwfFruQFJP7IhImmXLuO+8i2qeAczM= +github.com/filecoin-project/go-bitfield v0.1.0/go.mod h1:CNl9WG8hgR5mttCnUErjcQjGvuiZjRqK9rHVBsQF4oM= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2 h1:av5fw6wmm58FYMgJeoB/lK9XXrgdugYiTqkdxjTy9k8= github.com/filecoin-project/go-cbor-util v0.0.0-20191219014500-08c40a1e63a2/go.mod h1:pqTiPHobNkOVM5thSRsHYjyQfq7O5QSCMhvuu9JoDlg= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03 h1:2pMXdBnCiXjfCYx/hLqFxccPoqsSveQFxVLvNxy9bus= github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= -github.com/filecoin-project/go-data-transfer v0.4.1-0.20200715144713-b3311844e1a5 h1:/OZ+nr0x3uMZCPrreuUbS5EUOFm9DDo4ljgdav8rp/s= -github.com/filecoin-project/go-data-transfer v0.4.1-0.20200715144713-b3311844e1a5/go.mod h1:duGDSKvsOxiKl6Dueh8DNA6ZbiM30PWUWlSKjo9ac+o= +github.com/filecoin-project/go-data-transfer v0.5.0 h1:pvWlab69BD5dwheRHjjBjFB6m7CEqEZeI+aChtVqKVk= +github.com/filecoin-project/go-data-transfer v0.5.0/go.mod h1:7yckbsPPMGuN3O1+SYNE/lowwheaUn5woGILpjN52UI= github.com/filecoin-project/go-fil-commcid v0.0.0-20200208005934-2b8bd03caca5/go.mod h1:JbkIgFF/Z9BDlvrJO1FuKkaWsH673/UdFaiVS6uIHlA= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f h1:GxJzR3oRIMTPtpZ0b7QF8FKPK6/iPAc7trhlL5k/g+s= github.com/filecoin-project/go-fil-commcid v0.0.0-20200716160307-8f644712406f/go.mod h1:Eaox7Hvus1JgPrL5+M3+h7aSPHc0cVqpSxA+TxIEpZQ= -github.com/filecoin-project/go-fil-markets v0.4.1-0.20200715201050-c141144ea312 h1:oVZggNjDWZWEjomkxPl8U3jrOLURoS4QSZA6t4YU5BY= -github.com/filecoin-project/go-fil-markets v0.4.1-0.20200715201050-c141144ea312/go.mod h1:MvrpKOiETu39e9H167gdQzdzLNcvHsUp48UkXqPSdtU= +github.com/filecoin-project/go-fil-markets v0.5.1 h1:Y69glslNCuXnygfesCmyilTVhEEjcLK7CtAohKP9SL8= +github.com/filecoin-project/go-fil-markets v0.5.1/go.mod h1:GKGigsFNMvKmx/+Mcn7093TdZTiCDLc7YGxQ7d6fq2s= github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24 h1:Jc7vkplmZYVuaEcSXGHDwefvZIdoyyaoGDLqSr8Svms= github.com/filecoin-project/go-jsonrpc v0.1.1-0.20200602181149-522144ab4e24/go.mod h1:j6zV//WXIIY5kky873Q3iIKt/ViOE8rcijovmpxrXzM= github.com/filecoin-project/go-padreader v0.0.0-20200210211231-548257017ca6 h1:92PET+sx1Hb4W/8CgFwGuxaKbttwY+UNspYZTvXY0vs= @@ -260,19 +264,19 @@ github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b/ github.com/filecoin-project/sector-storage v0.0.0-20200615154852-728a47ab99d6/go.mod h1:M59QnAeA/oV+Z8oHFLoNpGMv0LZ8Rll+vHVXX7GirPM= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15 h1:miw6hiusb/MkV1ryoqUKKWnvHhPW00AYtyeCj0L8pqo= github.com/filecoin-project/sector-storage v0.0.0-20200712023225-1d67dcfa3c15/go.mod h1:salgVdX7qeXFo/xaiEQE29J4pPkjn71T0kt0n+VDBzo= -github.com/filecoin-project/sector-storage v0.0.0-20200717213554-a109ef9cbeab h1:jEQtbWFyEKnCw3eAVCW3MSX/K7Nv03B3zzS/rfm2k+Q= -github.com/filecoin-project/sector-storage v0.0.0-20200717213554-a109ef9cbeab/go.mod h1:7EE+f7jM4kCy2MKHoiiwNDQGJSb+QQzZ+y+/17ugq4w= +github.com/filecoin-project/sector-storage v0.0.0-20200723200950-ed2e57dde6df h1:VDdWrCNUNx6qeHnGU9oAy+izuGM02it9V/5+MJyhZQw= +github.com/filecoin-project/sector-storage v0.0.0-20200723200950-ed2e57dde6df/go.mod h1:7EE+f7jM4kCy2MKHoiiwNDQGJSb+QQzZ+y+/17ugq4w= github.com/filecoin-project/specs-actors v0.0.0-20200210130641-2d1fbd8672cf/go.mod h1:xtDZUB6pe4Pksa/bAJbJ693OilaC5Wbot9jMhLm3cZA= github.com/filecoin-project/specs-actors v0.3.0/go.mod h1:nQYnFbQ7Y0bHZyq6HDEuVlCPR+U3z5Q3wMOQ+2aiV+Y= github.com/filecoin-project/specs-actors v0.6.0/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= github.com/filecoin-project/specs-actors v0.6.1/go.mod h1:dRdy3cURykh2R8O/DKqy8olScl70rmIS7GrB4hB1IDY= -github.com/filecoin-project/specs-actors v0.7.0/go.mod h1:+z0htZu/wLBDbOLcQTKKUEC2rkUTFzL2KJ/bRAVWkws= github.com/filecoin-project/specs-actors v0.7.3-0.20200716231407-60a2ae96d2e6 h1:F+GcBdKPdW/wTv6bMJxG9Zj1dc0UGkO6uNOQmKP/g1o= github.com/filecoin-project/specs-actors v0.7.3-0.20200716231407-60a2ae96d2e6/go.mod h1:JOMUa7EijvpOO4ofD1yeHNmqohkmmnhTvz/IpB6so4c= -github.com/filecoin-project/specs-actors v0.8.1-0.20200720061236-f4719fdd7d90 h1:E8M5FyB53tuRXHO5KAAi9DlksOl54ULImW57MrUfyDY= -github.com/filecoin-project/specs-actors v0.8.1-0.20200720061236-f4719fdd7d90/go.mod h1:JOMUa7EijvpOO4ofD1yeHNmqohkmmnhTvz/IpB6so4c= -github.com/filecoin-project/specs-actors v0.8.1-0.20200720115956-cd051eabf328 h1:jZwz1VxqzNCfINY5FDnsT+ZL03wjzLifi+JwdLkehuU= github.com/filecoin-project/specs-actors v0.8.1-0.20200720115956-cd051eabf328/go.mod h1:0+CxQ5Jeii3522irTvhKRDpr4GG1bj5Erq3p/d38DzY= +github.com/filecoin-project/specs-actors v0.8.1-0.20200723200253-a3c01bc62f99 h1:li6OZVhGNrQihzKhUy7x4vwKgUCExnpVSj746VMkq1I= +github.com/filecoin-project/specs-actors v0.8.1-0.20200723200253-a3c01bc62f99/go.mod h1:TLvIheTVl0EIuyncuKSTVXPULaj7gzhLup5CLZ/S+uM= +github.com/filecoin-project/specs-actors v0.8.1-0.20200724015154-3c690d9b7e1d h1:dti6ssgSFG7Tk851S3RdiDr1TNbOJ26ylc6DJ9Y2Le0= +github.com/filecoin-project/specs-actors v0.8.1-0.20200724015154-3c690d9b7e1d/go.mod h1:TLvIheTVl0EIuyncuKSTVXPULaj7gzhLup5CLZ/S+uM= github.com/filecoin-project/specs-storage v0.1.0 h1:PkDgTOT5W5Ao7752onjDl4QSv+sgOVdJbvFjOnD5w94= github.com/filecoin-project/specs-storage v0.1.0/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k= github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea h1:iixjULRQFPn7Q9KlIqfwLJnlAXO10bbkI+xy5GKGdLY= @@ -418,6 +422,8 @@ github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmv github.com/gxed/pubsub v0.0.0-20180201040156-26ebdf44f824/go.mod h1:OiEWyHgK+CWrmOlVquHaIK1vhpUJydC9m0Je6mhaiNE= github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099 h1:vQqOW42RRM5LoM/1K5dK940VipLqpH8lEVGrMz+mNjU= github.com/hannahhoward/cbor-gen-for v0.0.0-20191218204337-9ab7b1bcc099/go.mod h1:WVPCl0HO/0RAL5+vBH2GMxBomlxBF70MAS78+Lu1//k= +github.com/hannahhoward/cbor-gen-for v0.0.0-20200723175505-5892b522820a h1:wfqh5oiHXvn3Rk54xy8Cwqh+HnYihGnjMNzdNb3/ld0= +github.com/hannahhoward/cbor-gen-for v0.0.0-20200723175505-5892b522820a/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8= github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -520,13 +526,12 @@ github.com/ipfs/go-filestore v1.0.0 h1:QR7ekKH+q2AGiWDc7W2Q0qHuYSRZGUJqUn0GsegEP github.com/ipfs/go-filestore v1.0.0/go.mod h1:/XOCuNtIe2f1YPbiXdYvD0BKLA0JR1MgPiFOdcuu9SM= github.com/ipfs/go-fs-lock v0.0.1 h1:XHX8uW4jQBYWHj59XXcjg7BHlHxV9ZOYs6Y43yb7/l0= github.com/ipfs/go-fs-lock v0.0.1/go.mod h1:DNBekbboPKcxs1aukPSaOtFA3QfSdi5C855v0i9XJ8Y= -github.com/ipfs/go-graphsync v0.0.6-0.20200715142715-e2f27c4754e6 h1:+dQnaRkLV4za46Gfw6b1KNVOCcGDrdnEGZrjz3kF80k= -github.com/ipfs/go-graphsync v0.0.6-0.20200715142715-e2f27c4754e6/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= +github.com/ipfs/go-graphsync v0.0.6-0.20200715204712-ef06b3d32e83 h1:tkGDAwcZfzDFeBNyBWYOM02Qw0rGpA2UuCvq49T3K5o= +github.com/ipfs/go-graphsync v0.0.6-0.20200715204712-ef06b3d32e83/go.mod h1:jMXfqIEDFukLPZHqDPp8tJMbHO9Rmeb9CEGevngQbmE= github.com/ipfs/go-hamt-ipld v0.0.15-0.20200131012125-dd88a59d3f2e/go.mod h1:9aQJu/i/TaRDW6jqB5U217dLIDopn50wxLdHXM2CTfE= github.com/ipfs/go-hamt-ipld v0.0.15-0.20200204200533-99b8553ef242/go.mod h1:kq3Pi+UP3oHhAdKexE+kHHYRKMoFNuGero0R7q3hWGg= -github.com/ipfs/go-hamt-ipld v0.1.1-0.20200501020327-d53d20a7063e/go.mod h1:giiPqWYCnRBYpNTsJ/EX1ojldX5kTXrXYckSJQ7ko9M= -github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f h1:mchhWiYYUSoCuE3wDfRCo8cho5kqSoxkgnOtGcnNMZw= -github.com/ipfs/go-hamt-ipld v0.1.1-0.20200605182717-0310ad2b0b1f/go.mod h1:phOFBB7W73N9dg1glcb1fQ9HtQFDUpeyJgatW8ns0bw= +github.com/ipfs/go-hamt-ipld v0.1.1 h1:0IQdvwnAAUKmDE+PMJa5y1QiwOPHpI9+eAbQEEEYthk= +github.com/ipfs/go-hamt-ipld v0.1.1/go.mod h1:1EZCr2v0jlCnhpa+aZ0JZYp8Tt2w16+JJOAVz17YcDk= github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= @@ -1353,14 +1358,14 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:X github.com/whyrusleeping/cbor-gen v0.0.0-20200206220010-03c9665e2a66/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200402171437-3d27c146c105/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200414195334-429a0b5e922e/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= -github.com/whyrusleeping/cbor-gen v0.0.0-20200501014322-5f9941ef88e0/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= github.com/whyrusleeping/cbor-gen v0.0.0-20200501232601-351665a6e756/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d h1:Y25auOnuZb/GuJvqMflRSDWBz8/HBRME8fiD+H8zLfs= github.com/whyrusleeping/cbor-gen v0.0.0-20200504204219-64967432584d/go.mod h1:W5MvapuoHRP8rz4vxjwCK1pDqF1aQcWsV5PZ+AHbqdg= github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d h1:wSxKhvbN7kUoP0sfRS+w2tWr45qlU8409i94hHLOT8w= github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= -github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377 h1:LHFlP/ktDvOnCap7PsT87cs7Gwd0p+qv6Qm5g2ZPR+I= github.com/whyrusleeping/cbor-gen v0.0.0-20200715143311-227fab5a2377/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200723182808-cb5de1c427f5 h1:dJgLhFKggti1Xd7GczL4DetAUyx68RhpCKCfV71ongg= +github.com/whyrusleeping/cbor-gen v0.0.0-20200723182808-cb5de1c427f5/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= github.com/whyrusleeping/go-ctrlnet v0.0.0-20180313164037-f564fbbdaa95/go.mod h1:SJqKCCPXRfBFCwXjfNT/skfsceF7+MBFLI2OrvuRA7g= diff --git a/lib/adtutil/cststore.go b/lib/adtutil/cststore.go deleted file mode 100644 index 14575442d..000000000 --- a/lib/adtutil/cststore.go +++ /dev/null @@ -1,34 +0,0 @@ -package adtutil - -import ( - "context" - - "github.com/ipfs/go-cid" - cbor "github.com/ipfs/go-ipld-cbor" - - "github.com/filecoin-project/specs-actors/actors/util/adt" -) - -func NewStore(ctx context.Context, cst *cbor.BasicIpldStore) adt.Store { - return &store{ - cst: cst, - ctx: ctx, - } -} - -type store struct { - cst cbor.IpldStore - ctx context.Context -} - -func (a *store) Context() context.Context { - return a.ctx -} - -func (a *store) Get(ctx context.Context, c cid.Cid, out interface{}) error { - return a.cst.Get(ctx, c, out) -} - -func (a *store) Put(ctx context.Context, v interface{}) (cid.Cid, error) { - return a.cst.Put(ctx, v) -} diff --git a/lib/bufbstore/buf_bstore.go b/lib/bufbstore/buf_bstore.go index 4b430828b..4000df7d6 100644 --- a/lib/bufbstore/buf_bstore.go +++ b/lib/bufbstore/buf_bstore.go @@ -104,7 +104,12 @@ func (bs *BufferedBS) Get(c cid.Cid) (block.Block, error) { } func (bs *BufferedBS) GetSize(c cid.Cid) (int, error) { - panic("nyi") + s, err := bs.read.GetSize(c) + if err == bstore.ErrNotFound || s == 0 { + return bs.write.GetSize(c) + } + + return s, err } func (bs *BufferedBS) Put(blk block.Block) error { diff --git a/lib/ipfsbstore/ipfsbstore.go b/lib/ipfsbstore/ipfsbstore.go index 33110e295..ce756ccbb 100644 --- a/lib/ipfsbstore/ipfsbstore.go +++ b/lib/ipfsbstore/ipfsbstore.go @@ -25,10 +25,14 @@ type IpfsBstore struct { } func NewIpfsBstore(ctx context.Context) (*IpfsBstore, error) { - api, err := httpapi.NewLocalApi() + localApi, err := httpapi.NewLocalApi() if err != nil { return nil, xerrors.Errorf("getting local ipfs api: %w", err) } + api, err := localApi.WithOptions(options.Api.Offline(true)) + if err != nil { + return nil, xerrors.Errorf("setting offline mode: %s", err) + } return &IpfsBstore{ ctx: ctx, @@ -37,9 +41,13 @@ func NewIpfsBstore(ctx context.Context) (*IpfsBstore, error) { } func NewRemoteIpfsBstore(ctx context.Context, maddr multiaddr.Multiaddr) (*IpfsBstore, error) { - api, err := httpapi.NewApi(maddr) + httpApi, err := httpapi.NewApi(maddr) if err != nil { - return nil, xerrors.Errorf("getting remote ipfs api: %w", err) + return nil, xerrors.Errorf("setting remote ipfs api: %w", err) + } + api, err := httpApi.WithOptions(options.Api.Offline(true)) + if err != nil { + return nil, xerrors.Errorf("applying offline mode: %s", err) } return &IpfsBstore{ @@ -55,6 +63,13 @@ func (i *IpfsBstore) DeleteBlock(cid cid.Cid) error { func (i *IpfsBstore) Has(cid cid.Cid) (bool, error) { _, err := i.api.Block().Stat(i.ctx, path.IpldPath(cid)) if err != nil { + // The underlying client is running in Offline mode. + // Stat() will fail with an err if the block isn't in the + // blockstore. If that's the case, return false without + // an error since that's the original intention of this method. + if err.Error() == "blockservice: key not found" { + return false, nil + } return false, xerrors.Errorf("getting ipfs block: %w", err) } diff --git a/node/builder.go b/node/builder.go index 780497dba..46fd260d5 100644 --- a/node/builder.go +++ b/node/builder.go @@ -25,7 +25,6 @@ import ( "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/go-fil-markets/storagemarket/impl/storedask" - "github.com/filecoin-project/specs-actors/actors/runtime" storage2 "github.com/filecoin-project/specs-storage/storage" "github.com/filecoin-project/lotus/api" @@ -57,6 +56,7 @@ import ( "github.com/filecoin-project/lotus/node/modules/testing" "github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/paychmgr" + "github.com/filecoin-project/lotus/paychmgr/settler" "github.com/filecoin-project/lotus/storage" "github.com/filecoin-project/lotus/storage/sectorblocks" sectorstorage "github.com/filecoin-project/sector-storage" @@ -118,6 +118,7 @@ const ( // daemon ExtractApiKey HeadMetricsKey + SettlePaymentChannelsKey RunPeerTaggerKey JournalKey @@ -225,7 +226,7 @@ func Online() Option { Override(HandleIncomingMessagesKey, modules.HandleIncomingMessages), Override(new(ffiwrapper.Verifier), ffiwrapper.ProofVerifier), - Override(new(runtime.Syscalls), vm.Syscalls), + Override(new(vm.SyscallBuilder), vm.Syscalls), Override(new(*store.ChainStore), modules.ChainStore), Override(new(*stmgr.StateManager), stmgr.NewStateManager), Override(new(*wallet.Wallet), wallet.NewWallet), @@ -272,6 +273,7 @@ func Online() Option { Override(new(*paychmgr.Store), paychmgr.NewStore), Override(new(*paychmgr.Manager), paychmgr.NewManager), Override(new(*market.FundMgr), market.NewFundMgr), + Override(SettlePaymentChannelsKey, settler.SettlePaymentChannels), ), // miner diff --git a/node/hello/hello.go b/node/hello/hello.go index 5f35faafc..a0dc8d357 100644 --- a/node/hello/hello.go +++ b/node/hello/hello.go @@ -5,6 +5,7 @@ import ( "time" "github.com/filecoin-project/specs-actors/actors/abi" + xerrors "golang.org/x/xerrors" "github.com/filecoin-project/specs-actors/actors/abi/big" "github.com/ipfs/go-cid" @@ -125,7 +126,7 @@ func (hs *Service) HandleStream(s inet.Stream) { func (hs *Service) SayHello(ctx context.Context, pid peer.ID) error { s, err := hs.h.NewStream(ctx, pid, ProtocolID) if err != nil { - return err + return xerrors.Errorf("error opening stream: %w", err) } hts := hs.cs.GetHeaviestTipSet() @@ -149,7 +150,7 @@ func (hs *Service) SayHello(ctx context.Context, pid peer.ID) error { t0 := build.Clock.Now() if err := cborutil.WriteCborRPC(s, hmsg); err != nil { - return err + return xerrors.Errorf("writing rpc to peer: %w", err) } go func() { diff --git a/node/impl/client/client.go b/node/impl/client/client.go index e3eefd3f9..53dacb8de 100644 --- a/node/impl/client/client.go +++ b/node/impl/client/client.go @@ -31,6 +31,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-fil-markets/pieceio" rm "github.com/filecoin-project/go-fil-markets/retrievalmarket" + "github.com/filecoin-project/go-fil-markets/shared" "github.com/filecoin-project/go-fil-markets/storagemarket" "github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/specs-actors/actors/abi" @@ -261,6 +262,7 @@ func (a *API) makeRetrievalQuery(ctx context.Context, rp rm.RetrievalPeer, paylo Piece: piece, Size: queryResponse.Size, MinPrice: queryResponse.PieceRetrievalPrice(), + UnsealPrice: queryResponse.UnsealPrice, PaymentInterval: queryResponse.MaxPaymentInterval, PaymentIntervalIncrease: queryResponse.MaxPaymentIntervalIncrease, Miner: queryResponse.PaymentAddress, // TODO: check @@ -418,10 +420,14 @@ func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref ppb := types.BigDiv(order.Total, types.NewInt(order.Size)) - _, err := a.Retrieval.Retrieve( + params, err := rm.NewParamsV1(ppb, order.PaymentInterval, order.PaymentIntervalIncrease, shared.AllSelector(), order.Piece, order.UnsealPrice) + if err != nil { + return xerrors.Errorf("Error in retrieval params: %s", err) + } + _, err = a.Retrieval.Retrieve( ctx, order.Root, - rm.NewParamsV0(ppb, order.PaymentInterval, order.PaymentIntervalIncrease), + params, order.Total, order.MinerPeerID, order.Client, @@ -434,7 +440,7 @@ func (a *API) ClientRetrieve(ctx context.Context, order api.RetrievalOrder, ref return xerrors.New("Retrieval Timed Out") case err := <-retrievalResult: if err != nil { - return xerrors.Errorf("RetrieveUnixfs: %w", err) + return xerrors.Errorf("Retrieve: %w", err) } } @@ -494,6 +500,7 @@ func (a *API) ClientCalcCommP(ctx context.Context, inpath string, miner address. if err != nil { return nil, err } + defer rdr.Close() stat, err := rdr.Stat() if err != nil { @@ -554,6 +561,7 @@ func (a *API) clientImport(ctx context.Context, ref api.FileRef, store *importmg if err != nil { return cid.Undef, err } + defer f.Close() stat, err := f.Stat() if err != nil { diff --git a/node/impl/full/chain.go b/node/impl/full/chain.go index 802e2a355..bbbd989b7 100644 --- a/node/impl/full/chain.go +++ b/node/impl/full/chain.go @@ -4,19 +4,16 @@ import ( "bytes" "context" "encoding/json" - "fmt" "io" "strconv" "strings" "sync" - "github.com/filecoin-project/go-amt-ipld/v2" "github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/crypto" "github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/ipfs/go-blockservice" "github.com/ipfs/go-cid" - "github.com/ipfs/go-hamt-ipld" blockstore "github.com/ipfs/go-ipfs-blockstore" offline "github.com/ipfs/go-ipfs-exchange-offline" cbor "github.com/ipfs/go-ipld-cbor" @@ -26,6 +23,7 @@ import ( "github.com/ipfs/go-path" "github.com/ipfs/go-path/resolver" mh "github.com/multiformats/go-multihash" + cbg "github.com/whyrusleeping/cbor-gen" "go.uber.org/fx" "golang.org/x/xerrors" @@ -265,8 +263,17 @@ func (a *ChainAPI) ChainTipSetWeight(ctx context.Context, tsk types.TipSetKey) ( return a.Chain.Weight(ctx, ts) } +// This allows us to lookup string keys in the actor's adt.Map type. +type stringKey string + +func (s stringKey) Key() string { + return (string)(s) +} + func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) { return func(ctx context.Context, ds ipld.NodeGetter, nd ipld.Node, names []string) (*ipld.Link, []string, error) { + store := adt.WrapStore(ctx, cbor.NewCborStore(bs)) + if strings.HasPrefix(names[0], "@Ha:") { addr, err := address.NewFromString(names[0][4:]) if err != nil { @@ -290,7 +297,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod if strings.HasPrefix(names[0], "@Hu:") { i, err := strconv.ParseUint(names[0][4:], 10, 64) if err != nil { - return nil, nil, xerrors.Errorf("parsing int64: %w", err) + return nil, nil, xerrors.Errorf("parsing uint64: %w", err) } ik := adt.UIntKey(i) @@ -299,16 +306,20 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod } if strings.HasPrefix(names[0], "@H:") { - cst := cbor.NewCborStore(bs) - - h, err := hamt.LoadNode(ctx, cst, nd.Cid(), hamt.UseTreeBitWidth(5)) + h, err := adt.AsMap(store, nd.Cid()) if err != nil { return nil, nil, xerrors.Errorf("resolving hamt link: %w", err) } - var m interface{} - if err := h.Find(ctx, names[0][3:], &m); err != nil { + var deferred cbg.Deferred + if found, err := h.Get(stringKey(names[0][3:]), &deferred); err != nil { return nil, nil, xerrors.Errorf("resolve hamt: %w", err) + } else if !found { + return nil, nil, xerrors.Errorf("resolve hamt: not found") + } + var m interface{} + if err := cbor.DecodeInto(deferred.Raw, &m); err != nil { + return nil, nil, xerrors.Errorf("failed to decode cbor object: %w", err) } if c, ok := m.(cid.Cid); ok { return &ipld.Link{ @@ -337,7 +348,7 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod } if strings.HasPrefix(names[0], "@A:") { - a, err := amt.LoadAMT(ctx, cbor.NewCborStore(bs), nd.Cid()) + a, err := adt.AsArray(store, nd.Cid()) if err != nil { return nil, nil, xerrors.Errorf("load amt: %w", err) } @@ -347,11 +358,17 @@ func resolveOnce(bs blockstore.Blockstore) func(ctx context.Context, ds ipld.Nod return nil, nil, xerrors.Errorf("parsing amt index: %w", err) } - var m interface{} - if err := a.Get(ctx, idx, &m); err != nil { - return nil, nil, xerrors.Errorf("amt get: %w", err) + var deferred cbg.Deferred + if found, err := a.Get(idx, &deferred); err != nil { + return nil, nil, xerrors.Errorf("resolve amt: %w", err) + } else if !found { + return nil, nil, xerrors.Errorf("resolve amt: not found") } - fmt.Printf("AG %T %v\n", m, m) + var m interface{} + if err := cbor.DecodeInto(deferred.Raw, &m); err != nil { + return nil, nil, xerrors.Errorf("failed to decode cbor object: %w", err) + } + if c, ok := m.(cid.Cid); ok { return &ipld.Link{ Name: names[0][3:], diff --git a/node/impl/full/gas.go b/node/impl/full/gas.go index 1d09e5844..74b288640 100644 --- a/node/impl/full/gas.go +++ b/node/impl/full/gas.go @@ -5,6 +5,7 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/types" @@ -17,6 +18,7 @@ type GasAPI struct { fx.In Stmgr *stmgr.StateManager Cs *store.ChainStore + Mpool *messagepool.MessagePool } const MinGasPrice = 1 @@ -35,19 +37,25 @@ func (a *GasAPI) GasEstimateGasPrice(ctx context.Context, nblocksincl uint64, } } -func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message, - tsk types.TipSetKey) (int64, error) { +func (a *GasAPI) GasEstimateGasLimit(ctx context.Context, msgIn *types.Message, _ types.TipSetKey) (int64, error) { msg := *msgIn msg.GasLimit = build.BlockGasLimit msg.GasPrice = types.NewInt(1) - ts, err := a.Cs.GetTipSetFromKey(tsk) + currTs := a.Cs.GetHeaviestTipSet() + fromA, err := a.Stmgr.ResolveToKeyAddress(ctx, msgIn.From, currTs) if err != nil { - return -1, xerrors.Errorf("could not get tipset: %w", err) + return -1, xerrors.Errorf("getting key address: %w", err) } - res, err := a.Stmgr.CallWithGas(ctx, &msg, ts) + pending, ts := a.Mpool.PendingFor(fromA) + priorMsgs := make([]types.ChainMsg, 0, len(pending)) + for _, m := range pending { + priorMsgs = append(priorMsgs, m) + } + + res, err := a.Stmgr.CallWithGas(ctx, &msg, priorMsgs, ts) if err != nil { return -1, xerrors.Errorf("CallWithGas failed: %w", err) } diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 94e28eae9..917bfd841 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -8,14 +8,12 @@ import ( "strconv" cid "github.com/ipfs/go-cid" - "github.com/ipfs/go-hamt-ipld" cbor "github.com/ipfs/go-ipld-cbor" cbg "github.com/whyrusleeping/cbor-gen" "go.uber.org/fx" "golang.org/x/xerrors" "github.com/filecoin-project/go-address" - "github.com/filecoin-project/go-amt-ipld/v2" "github.com/filecoin-project/go-bitfield" "github.com/filecoin-project/sector-storage/ffiwrapper" "github.com/filecoin-project/specs-actors/actors/abi" @@ -522,30 +520,27 @@ func (a *StateAPI) StateMarketParticipants(ctx context.Context, tsk types.TipSet if _, err := a.StateManager.LoadActorState(ctx, builtin.StorageMarketActorAddr, &state, ts); err != nil { return nil, err } - cst := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore()) - escrow, err := hamt.LoadNode(ctx, cst, state.EscrowTable, hamt.UseTreeBitWidth(5)) // todo: adt map + store := a.StateManager.ChainStore().Store(ctx) + escrow, err := adt.AsMap(store, state.EscrowTable) if err != nil { return nil, err } - locked, err := hamt.LoadNode(ctx, cst, state.LockedTable, hamt.UseTreeBitWidth(5)) + locked, err := adt.AsMap(store, state.LockedTable) if err != nil { return nil, err } - err = escrow.ForEach(ctx, func(k string, val interface{}) error { - cv := val.(*cbg.Deferred) + var es, lk abi.TokenAmount + err = escrow.ForEach(&es, func(k string) error { a, err := address.NewFromBytes([]byte(k)) if err != nil { return err } - var es abi.TokenAmount - if err := es.UnmarshalCBOR(bytes.NewReader(cv.Raw)); err != nil { - return err - } - var lk abi.TokenAmount - if err := locked.Find(ctx, k, &es); err != nil { + if found, err := locked.Get(adt.AddrKey(a), &lk); err != nil { return err + } else if !found { + return fmt.Errorf("locked funds not found") } out[a.String()] = api.MarketBalance{ @@ -572,29 +567,23 @@ func (a *StateAPI) StateMarketDeals(ctx context.Context, tsk types.TipSetKey) (m return nil, err } - blks := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore()) - da, err := amt.LoadAMT(ctx, blks, state.Proposals) + store := a.StateManager.ChainStore().Store(ctx) + da, err := adt.AsArray(store, state.Proposals) if err != nil { return nil, err } - sa, err := amt.LoadAMT(ctx, blks, state.States) + sa, err := adt.AsArray(store, state.States) if err != nil { return nil, err } - if err := da.ForEach(ctx, func(i uint64, v *cbg.Deferred) error { - var d market.DealProposal - if err := d.UnmarshalCBOR(bytes.NewReader(v.Raw)); err != nil { - return err - } - + var d market.DealProposal + if err := da.ForEach(&d, func(i int64) error { var s market.DealState - if err := sa.Get(ctx, i, &s); err != nil { - if _, ok := err.(*amt.ErrNotFound); !ok { - return xerrors.Errorf("failed to get state for deal in proposals array: %w", err) - } - + if found, err := sa.Get(uint64(i), &s); err != nil { + return xerrors.Errorf("failed to get state for deal in proposals array: %w", err) + } else if !found { s.SectorStartEpoch = -1 } out[strconv.FormatInt(int64(i), 10)] = api.MarketDeal{ @@ -617,47 +606,51 @@ func (a *StateAPI) StateMarketStorageDeal(ctx context.Context, dealId abi.DealID } func (a *StateAPI) StateChangedActors(ctx context.Context, old cid.Cid, new cid.Cid) (map[string]types.Actor, error) { - cst := cbor.NewCborStore(a.Chain.Blockstore()) + store := adt.WrapStore(ctx, cbor.NewCborStore(a.Chain.Blockstore())) - nh, err := hamt.LoadNode(ctx, cst, new, hamt.UseTreeBitWidth(5)) + nh, err := adt.AsMap(store, new) if err != nil { return nil, err } - oh, err := hamt.LoadNode(ctx, cst, old, hamt.UseTreeBitWidth(5)) + oh, err := adt.AsMap(store, old) if err != nil { return nil, err } out := map[string]types.Actor{} - err = nh.ForEach(ctx, func(k string, nval interface{}) error { - ncval := nval.(*cbg.Deferred) + var ( + ncval, ocval cbg.Deferred + buf = bytes.NewReader(nil) + ) + err = nh.ForEach(&ncval, func(k string) error { var act types.Actor - var ocval cbg.Deferred + addr, err := address.NewFromBytes([]byte(k)) + if err != nil { + return xerrors.Errorf("address in state tree was not valid: %w", err) + } - switch err := oh.Find(ctx, k, &ocval); err { - case nil: - if bytes.Equal(ocval.Raw, ncval.Raw) { - return nil // not changed - } - fallthrough - case hamt.ErrNotFound: - if err := act.UnmarshalCBOR(bytes.NewReader(ncval.Raw)); err != nil { - return err - } - - addr, err := address.NewFromBytes([]byte(k)) - if err != nil { - return xerrors.Errorf("address in state tree was not valid: %w", err) - } - - out[addr.String()] = act - default: + found, err := oh.Get(adt.AddrKey(addr), &ocval) + if err != nil { return err } + if found && bytes.Equal(ocval.Raw, ncval.Raw) { + return nil // not changed + } + + buf.Reset(ncval.Raw) + err = act.UnmarshalCBOR(buf) + buf.Reset(nil) + + if err != nil { + return err + } + + out[addr.String()] = act + return nil }) if err != nil { @@ -1000,7 +993,7 @@ func (a *StateAPI) StateMinerInitialPledgeCollateral(ctx context.Context, maddr } sectorWeight := miner.QAPowerForWeight(ssize, duration, dealWeights.DealWeight, dealWeights.VerifiedDealWeight) - initialPledge := miner.InitialPledgeForPower(sectorWeight, powerState.TotalQualityAdjPower, reward.BaselinePowerAt(ts.Height()), powerState.TotalPledgeCollateral, rewardState.ThisEpochReward, circSupply) + initialPledge := miner.InitialPledgeForPower(sectorWeight, powerState.TotalQualityAdjPower, reward.SlowConvenientBaselineForEpoch(ts.Height()), powerState.TotalPledgeCollateral, rewardState.ThisEpochReward, circSupply) return types.BigDiv(types.BigMul(initialPledge, initialPledgeNum), initialPledgeDen), nil } @@ -1039,24 +1032,23 @@ func (a *StateAPI) StateVerifiedClientStatus(ctx context.Context, addr address.A return nil, err } - cst := cbor.NewCborStore(a.StateManager.ChainStore().Blockstore()) + store := a.StateManager.ChainStore().Store(ctx) var st verifreg.State - if err := cst.Get(ctx, act.Head, &st); err != nil { + if err := store.Get(ctx, act.Head, &st); err != nil { return nil, err } - vh, err := hamt.LoadNode(ctx, cst, st.VerifiedClients, hamt.UseTreeBitWidth(5)) + vh, err := adt.AsMap(store, st.VerifiedClients) if err != nil { return nil, err } var dcap verifreg.DataCap - if err := vh.Find(ctx, string(addr.Bytes()), &dcap); err != nil { - if err == hamt.ErrNotFound { - return nil, nil - } + if found, err := vh.Get(adt.AddrKey(addr), &dcap); err != nil { return nil, err + } else if !found { + return nil, nil } return &dcap, nil diff --git a/node/impl/full/wallet.go b/node/impl/full/wallet.go index d2dd4ee12..68550a4f3 100644 --- a/node/impl/full/wallet.go +++ b/node/impl/full/wallet.go @@ -2,6 +2,8 @@ package full import ( "context" + "github.com/filecoin-project/specs-actors/actors/abi/big" + init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" "github.com/filecoin-project/lotus/lib/sigs" @@ -37,10 +39,16 @@ func (a *WalletAPI) WalletList(ctx context.Context) ([]address.Address, error) { func (a *WalletAPI) WalletBalance(ctx context.Context, addr address.Address) (types.BigInt, error) { var bal types.BigInt - return bal, a.StateManager.WithParentStateTsk(types.EmptyTSK, a.StateManager.WithActor(addr, func(act *types.Actor) error { + err := a.StateManager.WithParentStateTsk(types.EmptyTSK, a.StateManager.WithActor(addr, func(act *types.Actor) error { bal = act.Balance return nil })) + + if xerrors.Is(err, init_.ErrAddressNotFound) { + return big.Zero(), nil + } else { + return bal, err + } } func (a *WalletAPI) WalletSign(ctx context.Context, k address.Address, msg []byte) (*crypto.Signature, error) { diff --git a/node/impl/paych/paych.go b/node/impl/paych/paych.go index f7a51fc25..c9f2f215d 100644 --- a/node/impl/paych/paych.go +++ b/node/impl/paych/paych.go @@ -107,36 +107,43 @@ func (a *PaychAPI) PaychStatus(ctx context.Context, pch address.Address) (*api.P }, nil } -func (a *PaychAPI) PaychClose(ctx context.Context, addr address.Address) (cid.Cid, error) { - panic("TODO Settle logic") +func (a *PaychAPI) PaychSettle(ctx context.Context, addr address.Address) (cid.Cid, error) { ci, err := a.PaychMgr.GetChannelInfo(addr) if err != nil { return cid.Undef, err } - nonce, err := a.MpoolGetNonce(ctx, ci.Control) - if err != nil { - return cid.Undef, err - } - msg := &types.Message{ To: addr, From: ci.Control, Value: types.NewInt(0), Method: builtin.MethodsPaych.Settle, - Nonce: nonce, - - GasLimit: 0, - GasPrice: types.NewInt(0), } + smgs, err := a.MpoolPushMessage(ctx, msg) - smsg, err := a.WalletSignMessage(ctx, ci.Control, msg) + if err != nil { + return cid.Undef, err + } + return smgs.Cid(), nil +} + +func (a *PaychAPI) PaychCollect(ctx context.Context, addr address.Address) (cid.Cid, error) { + + ci, err := a.PaychMgr.GetChannelInfo(addr) if err != nil { return cid.Undef, err } - if _, err := a.MpoolPush(ctx, smsg); err != nil { + msg := &types.Message{ + To: addr, + From: ci.Control, + Value: types.NewInt(0), + Method: builtin.MethodsPaych.Collect, + } + + smsg, err := a.MpoolPushMessage(ctx, msg) + if err != nil { return cid.Undef, err } @@ -219,11 +226,6 @@ func (a *PaychAPI) PaychVoucherSubmit(ctx context.Context, ch address.Address, s return cid.Undef, err } - nonce, err := a.MpoolGetNonce(ctx, ci.Control) - if err != nil { - return cid.Undef, err - } - if sv.Extra != nil || len(sv.SecretPreimage) > 0 { return cid.Undef, fmt.Errorf("cant handle more advanced payment channel stuff yet") } @@ -236,25 +238,17 @@ func (a *PaychAPI) PaychVoucherSubmit(ctx context.Context, ch address.Address, s } msg := &types.Message{ - From: ci.Control, - To: ch, - Value: types.NewInt(0), - Nonce: nonce, - Method: builtin.MethodsPaych.UpdateChannelState, - Params: enc, - GasLimit: 0, - GasPrice: types.NewInt(0), + From: ci.Control, + To: ch, + Value: types.NewInt(0), + Method: builtin.MethodsPaych.UpdateChannelState, + Params: enc, } - smsg, err := a.WalletSignMessage(ctx, ci.Control, msg) + smsg, err := a.MpoolPushMessage(ctx, msg) if err != nil { return cid.Undef, err } - if _, err := a.MpoolPush(ctx, smsg); err != nil { - return cid.Undef, err - } - - // TODO: should we wait for it...? return smsg.Cid(), nil } diff --git a/node/impl/storminer.go b/node/impl/storminer.go index 7289e50c1..a5a405735 100644 --- a/node/impl/storminer.go +++ b/node/impl/storminer.go @@ -74,6 +74,10 @@ func (sm *StorageMinerAPI) WorkerStats(context.Context) (map[uint64]storiface.Wo return sm.StorageMgr.WorkerStats(), nil } +func (sm *StorageMinerAPI) WorkerJobs(ctx context.Context) (map[uint64][]storiface.WorkerJob, error) { + return sm.StorageMgr.WorkerJobs(), nil +} + func (sm *StorageMinerAPI) ActorAddress(context.Context) (address.Address, error) { return sm.Miner.Address(), nil } diff --git a/node/modules/chain.go b/node/modules/chain.go index 229a97cc4..380c13fe7 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -3,6 +3,7 @@ package modules import ( "bytes" "context" + "github.com/filecoin-project/lotus/chain/vm" "github.com/ipfs/go-bitswap" "github.com/ipfs/go-bitswap/network" @@ -17,7 +18,6 @@ import ( "golang.org/x/xerrors" "github.com/filecoin-project/sector-storage/ffiwrapper" - "github.com/filecoin-project/specs-actors/actors/runtime" "github.com/filecoin-project/lotus/chain" "github.com/filecoin-project/lotus/chain/beacon" @@ -83,7 +83,7 @@ func ChainBlockservice(bs dtypes.ChainBlockstore, rem dtypes.ChainExchange) dtyp return blockservice.New(bs, rem) } -func ChainStore(lc fx.Lifecycle, bs dtypes.ChainBlockstore, ds dtypes.MetadataDS, syscalls runtime.Syscalls) *store.ChainStore { +func ChainStore(lc fx.Lifecycle, bs dtypes.ChainBlockstore, ds dtypes.MetadataDS, syscalls vm.SyscallBuilder) *store.ChainStore { chain := store.NewChainStore(bs, ds, syscalls) if err := chain.Load(); err != nil { diff --git a/node/modules/core.go b/node/modules/core.go index 84179bd63..d72dad148 100644 --- a/node/modules/core.go +++ b/node/modules/core.go @@ -92,8 +92,8 @@ func BuiltinBootstrap() (dtypes.BootstrapPeers, error) { return build.BuiltinBootstrap() } -func DrandBootstrap() (dtypes.DrandBootstrap, error) { - return build.DrandBootstrap() +func DrandBootstrap(d dtypes.DrandConfig) (dtypes.DrandBootstrap, error) { + return addrutil.ParseAddresses(context.TODO(), d.Relays) } func SetupJournal(lr repo.LockedRepo) error { diff --git a/node/modules/dtypes/beacon.go b/node/modules/dtypes/beacon.go index f3ebc4fac..2231f0e08 100644 --- a/node/modules/dtypes/beacon.go +++ b/node/modules/dtypes/beacon.go @@ -2,5 +2,6 @@ package dtypes type DrandConfig struct { Servers []string + Relays []string ChainInfoJSON string } diff --git a/node/modules/services.go b/node/modules/services.go index d439843c4..3b7fff46a 100644 --- a/node/modules/services.go +++ b/node/modules/services.go @@ -41,7 +41,9 @@ func RunHello(mctx helpers.MetricsCtx, lc fx.Lifecycle, h host.Host, svc *hello. pic := evt.(event.EvtPeerIdentificationCompleted) go func() { if err := svc.SayHello(helpers.LifecycleCtx(mctx, lc), pic.Peer); err != nil { - log.Warnw("failed to say hello", "error", err, "peer", pic.Peer) + protos, _ := h.Peerstore().GetProtocols(pic.Peer) + agent, _ := h.Peerstore().Get(pic.Peer, "AgentVersion") + log.Warnw("failed to say hello", "error", err, "peer", pic.Peer, "supported", protos, "agent", agent) return } }() @@ -114,7 +116,7 @@ type RandomBeaconParams struct { } func BuiltinDrandConfig() dtypes.DrandConfig { - return build.DrandConfig + return build.DrandConfig() } func RandomBeacon(p RandomBeaconParams, _ dtypes.AfterGenesisSet) (beacon.RandomBeacon, error) { diff --git a/node/modules/testing/genesis.go b/node/modules/testing/genesis.go index 41587ed72..40df68bf3 100644 --- a/node/modules/testing/genesis.go +++ b/node/modules/testing/genesis.go @@ -17,12 +17,11 @@ import ( "github.com/mitchellh/go-homedir" "golang.org/x/xerrors" - "github.com/filecoin-project/specs-actors/actors/runtime" - "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/gen" genesis2 "github.com/filecoin-project/lotus/chain/gen/genesis" "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/genesis" "github.com/filecoin-project/lotus/node/modules" "github.com/filecoin-project/lotus/node/modules/dtypes" @@ -30,8 +29,8 @@ import ( var glog = logging.Logger("genesis") -func MakeGenesisMem(out io.Writer, template genesis.Template) func(bs dtypes.ChainBlockstore, syscalls runtime.Syscalls) modules.Genesis { - return func(bs dtypes.ChainBlockstore, syscalls runtime.Syscalls) modules.Genesis { +func MakeGenesisMem(out io.Writer, template genesis.Template) func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder) modules.Genesis { + return func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder) modules.Genesis { return func() (*types.BlockHeader, error) { glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network") b, err := genesis2.MakeGenesisBlock(context.TODO(), bs, syscalls, template) @@ -51,8 +50,8 @@ func MakeGenesisMem(out io.Writer, template genesis.Template) func(bs dtypes.Cha } } -func MakeGenesis(outFile, genesisTemplate string) func(bs dtypes.ChainBlockstore, syscalls runtime.Syscalls) modules.Genesis { - return func(bs dtypes.ChainBlockstore, syscalls runtime.Syscalls) modules.Genesis { +func MakeGenesis(outFile, genesisTemplate string) func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder) modules.Genesis { + return func(bs dtypes.ChainBlockstore, syscalls vm.SyscallBuilder) modules.Genesis { return func() (*types.BlockHeader, error) { glog.Warn("Generating new random genesis block, note that this SHOULD NOT happen unless you are setting up new network") genesisTemplate, err := homedir.Expand(genesisTemplate) diff --git a/node/node_test.go b/node/node_test.go index b729217b2..321732046 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -382,8 +382,12 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test } } + for i, def := range storage { // TODO: support non-bootstrap miners + + minerID := abi.ActorID(genesis2.MinerStart + uint64(i)) + if def.Full != 0 { t.Fatal("storage nodes only supported on the first full node") } @@ -396,9 +400,17 @@ func mockSbBuilder(t *testing.T, nFull int, storage []test.StorageMiner) ([]test return nil, nil } + sectors := make([]abi.SectorID, len(genms[i].Sectors)) + for i, sector := range genms[i].Sectors { + sectors[i] = abi.SectorID{ + Miner: minerID, + Number: sector.SectorID, + } + } + storers[i] = testStorageNode(ctx, t, genms[i].Worker, maddrs[i], pidKeys[i], f, mn, node.Options( node.Override(new(sectorstorage.SectorManager), func() (sectorstorage.SectorManager, error) { - return mock.NewMockSectorMgr(build.DefaultSectorSize()), nil + return mock.NewMockSectorMgr(build.DefaultSectorSize(), sectors), nil }), node.Override(new(ffiwrapper.Verifier), mock.MockVerifier), node.Unset(new(*sectorstorage.Manager)), @@ -536,7 +548,7 @@ func TestWindowedPost(t *testing.T) { logging.SetLogLevel("sub", "ERROR") logging.SetLogLevel("storageminer", "ERROR") - test.TestWindowPost(t, mockSbBuilder, 5*time.Millisecond, 10) + test.TestWindowPost(t, mockSbBuilder, 2*time.Millisecond, 10) } func TestCCUpgrade(t *testing.T) { @@ -548,3 +560,14 @@ func TestCCUpgrade(t *testing.T) { test.TestCCUpgrade(t, mockSbBuilder, 5*time.Millisecond) } + +func TestPaymentChannels(t *testing.T) { + logging.SetLogLevel("miner", "ERROR") + logging.SetLogLevel("chainstore", "ERROR") + logging.SetLogLevel("chain", "ERROR") + logging.SetLogLevel("sub", "ERROR") + logging.SetLogLevel("pubsub", "ERROR") + logging.SetLogLevel("storageminer", "ERROR") + + test.TestPaymentChannels(t, mockSbBuilder, 5*time.Millisecond) +} diff --git a/node/repo/fsrepo.go b/node/repo/fsrepo.go index 11d1cb5e7..470d016cd 100644 --- a/node/repo/fsrepo.go +++ b/node/repo/fsrepo.go @@ -390,6 +390,7 @@ func (fsr *fsLockedRepo) List() ([]string, error) { if err != nil { return nil, xerrors.Errorf("opening dir to list keystore: %w", err) } + defer dir.Close() //nolint:errcheck files, err := dir.Readdir(-1) if err != nil { return nil, xerrors.Errorf("reading keystore dir: %w", err) diff --git a/paychmgr/paych.go b/paychmgr/paych.go index d78afb381..85db664cd 100644 --- a/paychmgr/paych.go +++ b/paychmgr/paych.go @@ -185,7 +185,7 @@ func (pm *Manager) checkVoucherValid(ctx context.Context, ch address.Address, sv // CheckVoucherSpendable checks if the given voucher is currently spendable func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { - owner, err := pm.getPaychOwner(ctx, ch) + recipient, err := pm.getPaychRecipient(ctx, ch) if err != nil { return false, err } @@ -222,7 +222,7 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address } ret, err := pm.sm.Call(ctx, &types.Message{ - From: owner, + From: recipient, To: ch, Method: builtin.MethodsPaych.UpdateChannelState, Params: enc, @@ -238,13 +238,13 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address return true, nil } -func (pm *Manager) getPaychOwner(ctx context.Context, ch address.Address) (address.Address, error) { +func (pm *Manager) getPaychRecipient(ctx context.Context, ch address.Address) (address.Address, error) { var state paych.State if _, err := pm.sm.LoadActorState(ctx, ch, &state, nil); err != nil { return address.Address{}, err } - return state.From, nil + return state.To, nil } func (pm *Manager) AddVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { diff --git a/paychmgr/settler/settler.go b/paychmgr/settler/settler.go new file mode 100644 index 000000000..636684118 --- /dev/null +++ b/paychmgr/settler/settler.go @@ -0,0 +1,141 @@ +package settler + +import ( + "context" + "sync" + + "go.uber.org/fx" + + "github.com/ipfs/go-cid" + logging "github.com/ipfs/go-log/v2" + + "github.com/filecoin-project/go-address" + "github.com/filecoin-project/specs-actors/actors/abi" + "github.com/filecoin-project/specs-actors/actors/builtin" + "github.com/filecoin-project/specs-actors/actors/builtin/paych" + + "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build" + "github.com/filecoin-project/lotus/chain/events" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/impl/full" + payapi "github.com/filecoin-project/lotus/node/impl/paych" +) + +var log = logging.Logger("payment-channel-settler") + +// API are the dependencies need to run the payment channel settler +type API struct { + fx.In + + full.ChainAPI + full.StateAPI + payapi.PaychAPI +} + +type settlerAPI interface { + PaychList(context.Context) ([]address.Address, error) + PaychStatus(context.Context, address.Address) (*api.PaychStatus, error) + PaychVoucherCheckSpendable(context.Context, address.Address, *paych.SignedVoucher, []byte, []byte) (bool, error) + PaychVoucherList(context.Context, address.Address) ([]*paych.SignedVoucher, error) + PaychVoucherSubmit(context.Context, address.Address, *paych.SignedVoucher) (cid.Cid, error) + StateWaitMsg(ctx context.Context, cid cid.Cid, confidence uint64) (*api.MsgLookup, error) +} + +type paymentChannelSettler struct { + ctx context.Context + api settlerAPI +} + +// SettlePaymentChannels checks the chain for events related to payment channels settling and +// submits any vouchers for inbound channels tracked for this node +func SettlePaymentChannels(lc fx.Lifecycle, api API) error { + lc.Append(fx.Hook{ + OnStart: func(ctx context.Context) error { + pcs := newPaymentChannelSettler(ctx, &api) + ev := events.NewEvents(ctx, &api) + return ev.Called(pcs.check, pcs.messageHandler, pcs.revertHandler, int(build.MessageConfidence+1), events.NoTimeout, pcs.matcher) + }, + }) + return nil +} + +func newPaymentChannelSettler(ctx context.Context, api settlerAPI) *paymentChannelSettler { + return &paymentChannelSettler{ + ctx: ctx, + api: api, + } +} + +func (pcs *paymentChannelSettler) check(ts *types.TipSet) (done bool, more bool, err error) { + return false, true, nil +} + +func (pcs *paymentChannelSettler) messageHandler(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (more bool, err error) { + vouchers, err := pcs.api.PaychVoucherList(pcs.ctx, msg.To) + if err != nil { + return true, err + } + + bestByLane := make(map[uint64]*paych.SignedVoucher) + for _, voucher := range vouchers { + spendable, err := pcs.api.PaychVoucherCheckSpendable(pcs.ctx, msg.To, voucher, nil, nil) + if err != nil { + return true, err + } + if spendable { + if bestByLane[voucher.Lane] == nil || voucher.Amount.GreaterThan(bestByLane[voucher.Lane].Amount) { + bestByLane[voucher.Lane] = voucher + } + } + } + var wg sync.WaitGroup + wg.Add(len(bestByLane)) + for _, voucher := range bestByLane { + submitMessageCID, err := pcs.api.PaychVoucherSubmit(pcs.ctx, msg.To, voucher) + if err != nil { + return true, err + } + go func(voucher *paych.SignedVoucher, submitMessageCID cid.Cid) { + defer wg.Done() + msgLookup, err := pcs.api.StateWaitMsg(pcs.ctx, submitMessageCID, build.MessageConfidence) + if err != nil { + log.Errorf("submitting voucher: %s", err.Error()) + } + if msgLookup.Receipt.ExitCode != 0 { + log.Errorf("failed submitting voucher: %+v", voucher) + } + }(voucher, submitMessageCID) + } + wg.Wait() + return true, nil +} + +func (pcs *paymentChannelSettler) revertHandler(ctx context.Context, ts *types.TipSet) error { + return nil +} + +func (pcs *paymentChannelSettler) matcher(msg *types.Message) (matchOnce bool, matched bool, err error) { + // Check if this is a settle payment channel message + if msg.Method != builtin.MethodsPaych.Settle { + return false, false, nil + } + // Check if this payment channel is of concern to this node (i.e. tracked in payment channel store), + // and its inbound (i.e. we're getting vouchers that we may need to redeem) + trackedAddresses, err := pcs.api.PaychList(pcs.ctx) + if err != nil { + return false, false, err + } + for _, addr := range trackedAddresses { + if msg.To == addr { + status, err := pcs.api.PaychStatus(pcs.ctx, addr) + if err != nil { + return false, false, err + } + if status.Direction == api.PCHInbound { + return false, true, nil + } + } + } + return false, false, nil +} diff --git a/storage/wdpost_run.go b/storage/wdpost_run.go index abe3e8f4c..d21102df7 100644 --- a/storage/wdpost_run.go +++ b/storage/wdpost_run.go @@ -331,7 +331,7 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo params := &miner.SubmitWindowedPoStParams{ Deadline: di.Index, - Partitions: make([]miner.PoStPartition, len(partitions)), + Partitions: make([]miner.PoStPartition, 0, len(partitions)), Proofs: nil, } @@ -373,20 +373,19 @@ func (s *WindowPoStScheduler) runPost(ctx context.Context, di miner.DeadlineInfo return nil, xerrors.Errorf("getting sorted sector info: %w", err) } + if len(ssi) == 0 { + continue + } + sinfos = append(sinfos, ssi...) for _, si := range ssi { sidToPart[si.SectorNumber] = uint64(partIdx) } - if len(ssi) == 0 { - log.Warn("attempted to run windowPost without any sectors...") - return nil, xerrors.Errorf("no sectors to run windowPost on") - } - - params.Partitions[partIdx] = miner.PoStPartition{ + params.Partitions = append(params.Partitions, miner.PoStPartition{ Index: uint64(partIdx), Skipped: skipped, - } + }) } if len(sinfos) == 0 { @@ -458,14 +457,12 @@ func (s *WindowPoStScheduler) submitPost(ctx context.Context, proof *miner.Submi } msg := &types.Message{ - To: s.actor, - From: s.worker, - Method: builtin.MethodsMiner.SubmitWindowedPoSt, - Params: enc, - Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late - // TODO: Gaslimit needs to be calculated accurately. Before that, use the largest Gaslimit - GasLimit: build.BlockGasLimit, - GasPrice: types.NewInt(1), + To: s.actor, + From: s.worker, + Method: builtin.MethodsMiner.SubmitWindowedPoSt, + Params: enc, + Value: types.NewInt(1000), // currently hard-coded late fee in actor, returned if not late + GasPrice: types.NewInt(3), } // TODO: consider maybe caring about the output