bd10bdf99a
* build: Bump version to v1.17.3-dev * build: set version to v1.18.0-dev * chore: actors: Allow builtin-actors to return a map of methods (#9342) * Allow builtin-actors to return a map of methods * go mod * Fix tests * Fix tests, check carefully please * Delete lotus-pond (#9352) * feat: add StateNetworkVersion to mpool API * chore: refactor: rename NewestNetworkVersion * feat: actors: Integrate datacap actor into lotus (#9348) * Integrate datacap actor * Implement datacap actor in chain/builtin * feat: support typed errors over RPC * chore: deps: update to go-jsonrpc 0.1.8 * remove duplicate import * fix: itest: check for closed connection * chore: refactor: move retry test to API * address magik supernit * Add ability to only have single partition per msg for partitions with recovery sectors * doc gen * Address comments * Return beneficiary info from miner state Info() * Update builtin-actors to dev/20220922-v9 which includes FIP-0045 changes in progress * Integrate verifreg changes to lotus * Setup datacap actor * Update builtin-actors to dev/20220922-v9-1 * Update datacap actor to query datacap instead of verifreg * update gst * update markets * update actors with hamt fix * update gst * Update datacap to parse tokens * Update bundles * datacap and verifreg actors use ID addresses without protocol byte * update builtin-actors to rc1 * update go-fil-markets * Update bundles to rc2 * Integrate the v9 migration * Add api for getting allocation * Add upgrade epoch for butterfly * Tweak PreSeal struct to be infra-friendly * docsgen * More tweaking of PreSeal for genesis * review fixes * Use fake cid for test * add butterfly artifacts for oct 5 upgrade * check datacaps for v8 verifreg match v9 datacap actor * Remove print statements * Update to go-state-types master * Update to go-state-types v0.9.0-rc1 * review fixes * use go-fil-markets v1.24.0-v17 * Add accessors for allocations and claims maps * fix: missing permissions tag * butterfly * update butterfly artifacts * sealing pipeline: Prepare deal assigning logic for FIP-45 * sealing pipeline: Get allocationId with StateApi * use NoAllocationID instead of nil AllocationId * address review * Add datacap actor to registry.go * Add cli for listing allocations and removing expired allocations * Update to go-state-types master * deps: upgrade go-merkledag to 0.8.0 * shark params * Update cli/filplus.go Co-authored-by: Aayush Rajasekaran <arajasek94@gmail.com> * revert change to verifreg util * docsgen-cli * miss the stuff * Update FFI * Update go-state-types to v0.9.0 * Update builtin-actors to v9.0.0 * add calib upgrade epcoh * update the upgrade envvar * kill shark * Remove fvm splash banner from nv17 upgrade * check invariance for pending deals and allocations * check pending verified deal proposal migrated to allocation * Add check for unsealed CID in precommit sectors * Fix counting of allocations in nv17 migration test * make gen * pass state trees as pointers * Add assertion that migrations with & without cache are the same * compare allocation to verified deal proposal * Fix miner state precommit info * fix migration test tool * add changelog * Update to go-state-types v0.9.1 * Integrate builtin-actors v9.0.1 * chore: ver: bump version for rc3 (#9512) * Bump version to 1.18.0-rc3 * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: Aayush Rajasekaran <arajasek94@gmail.com> * Update CHANGELOG.md Co-authored-by: Aayush Rajasekaran <arajasek94@gmail.com> Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Co-authored-by: Aayush Rajasekaran <arajasek94@gmail.com> * Migration: Use autobatch bs * Fix autobatch Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai> * Invoker: Use MethodMeta from go-state-types * Add a second premigration for nv17 * Add more shed tools for migration checking * address review * Lotus release v1.18.0-rc4 * fix: ci: fix app-image build on ci (#9527) * Remove old go version first * Add GO_VERSION file * Use GO_VERSION to set / verify go version * mv GO_VERSION GO_VERSION_MIN * Use GO_VERSION_MIN in Makefile check Co-authored-by: Ian Davis <jungziege@gmail.com> * Update to latest go-state-types for migration fixes * go mod tidy * fix: use api.ErrActorNotFound instead of types.ErrActorNotFound * fix: add fields to ForkUpgradeParams * docs: update actors_version_checklist.md * chore: fix lint * update to go state type v0.9.6 with market migration fix (#9545) * update go-state-types to v-0.9.7 * Add invariant checks to migration * fix invariant check: number of entries in datacap actor should include verifreg * Invariant checks: Only include not-activated deals * test: nv17 migration * Address review * add lotus-shed invariance method * Migration cli takes a stateroot cid and a height * make gen * Update to builtin-actors v9.0.2 * Failing test that shows that notaries can remove datacap from the verifreg actor * Test that should pass when the problem is solved * make gen * Review fixes * statemanager call function will return call information even if call errors * update go-state-types * update builtin-actors * bubble up errors properly from ApplyImplicitMessage * bump to rc5 * set new upgrade heights for calibnet * set new upgrade height for butterfly * tweak calibnet upgrade schedule * clarify changelog note about calibnet * butterfly * update calibnet artifacts * Allow setting local bundles for Debug FVM for av 9+ * fix: autobatch: remove potential deadlock when a block is missing Check the _underlying_ blockstore instead of recursing. Also, drop the lock before we do that. * fix imports * build: set shark mainnet epoch (#9640) * chore: build: Lotus release v1.18.0 (#9641) * Lotus release v1.18.0 * add changelog * address review * changelog improvement Co-authored-by: Jennifer Wang <jiayingw703@gmail.com> Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai> Co-authored-by: Łukasz Magiera <magik6k@gmail.com> Co-authored-by: Łukasz Magiera <magik6k@users.noreply.github.com> Co-authored-by: Aayush <arajasek94@gmail.com> Co-authored-by: Geoff Stuart <geoff.vball@gmail.com> Co-authored-by: Shrenuj Bansal <shrenuj.bansal@protocol.ai> Co-authored-by: simlecode <69969590+simlecode@users.noreply.github.com> Co-authored-by: Rod Vagg <rod@vagg.org> Co-authored-by: Jakub Sztandera <kubuxu@protocol.ai> Co-authored-by: Ian Davis <jungziege@gmail.com> Co-authored-by: zenground0 <ZenGround0@users.noreply.github.com> Co-authored-by: Steven Allen <steven@stebalien.com>
472 lines
17 KiB
Go
472 lines
17 KiB
Go
// stm: #integration
|
|
package itests
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
cbor "github.com/ipfs/go-ipld-cbor"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
|
|
"github.com/filecoin-project/lotus/api"
|
|
"github.com/filecoin-project/lotus/blockstore"
|
|
"github.com/filecoin-project/lotus/build"
|
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
|
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
|
|
"github.com/filecoin-project/lotus/chain/events"
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
"github.com/filecoin-project/lotus/cli"
|
|
"github.com/filecoin-project/lotus/itests/kit"
|
|
)
|
|
|
|
// TestPaymentChannelsBasic does a basic test to exercise the payment channel CLI
|
|
// commands
|
|
func TestPaymentChannelsBasic(t *testing.T) {
|
|
//stm: @CHAIN_SYNCER_LOAD_GENESIS_001, @CHAIN_SYNCER_FETCH_TIPSET_001,
|
|
//stm: @CHAIN_SYNCER_START_001, @CHAIN_SYNCER_SYNC_001, @BLOCKCHAIN_BEACON_VALIDATE_BLOCK_VALUES_01
|
|
//stm: @CHAIN_SYNCER_COLLECT_CHAIN_001, @CHAIN_SYNCER_COLLECT_HEADERS_001, @CHAIN_SYNCER_VALIDATE_TIPSET_001
|
|
//stm: @CHAIN_SYNCER_NEW_PEER_HEAD_001, @CHAIN_SYNCER_VALIDATE_MESSAGE_META_001, @CHAIN_SYNCER_STOP_001
|
|
|
|
//stm: @CHAIN_INCOMING_HANDLE_INCOMING_BLOCKS_001, @CHAIN_INCOMING_VALIDATE_BLOCK_PUBSUB_001, @CHAIN_INCOMING_VALIDATE_MESSAGE_PUBSUB_001
|
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
|
kit.QuietMiningLogs()
|
|
|
|
blocktime := 5 * time.Millisecond
|
|
ctx := context.Background()
|
|
|
|
var (
|
|
paymentCreator kit.TestFullNode
|
|
paymentReceiver kit.TestFullNode
|
|
)
|
|
creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime)
|
|
|
|
// Create mock CLI
|
|
mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull)
|
|
creatorCLI := mockCLI.Client(paymentCreator.ListenAddr)
|
|
receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr)
|
|
|
|
// creator: paych add-funds <creator> <receiver> <amount>
|
|
channelAmt := "100000"
|
|
chstr := creatorCLI.RunCmd("paych", "add-funds", creatorAddr.String(), receiverAddr.String(), channelAmt)
|
|
|
|
chAddr, err := address.NewFromString(chstr)
|
|
require.NoError(t, err)
|
|
|
|
// creator: paych voucher create <channel> <amount>
|
|
voucherAmt := 100
|
|
vamt := strconv.Itoa(voucherAmt)
|
|
voucher := creatorCLI.RunCmd("paych", "voucher", "create", chAddr.String(), vamt)
|
|
|
|
// DEFLAKE: We have observed this test flakily failing when the receiver node hasn't seen the paych create message
|
|
// This makes us wait as much as 10 epochs before giving up and failing
|
|
retry := 0
|
|
_, err = paymentReceiver.StateLookupID(ctx, chAddr, types.EmptyTSK)
|
|
for err != nil && xerrors.Is(err, &api.ErrActorNotFound{}) {
|
|
time.Sleep(blocktime)
|
|
_, err = paymentReceiver.StateLookupID(ctx, chAddr, types.EmptyTSK)
|
|
retry++
|
|
if retry > 10 {
|
|
break
|
|
}
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
|
|
// receiver: paych voucher add <channel> <voucher>
|
|
receiverCLI.RunCmd("paych", "voucher", "add", chAddr.String(), voucher)
|
|
|
|
// creator: paych settle <channel>
|
|
creatorCLI.RunCmd("paych", "settle", chAddr.String())
|
|
|
|
t.Log("wait for chain to reach settle height")
|
|
|
|
// Wait for the chain to reach the settle height
|
|
chState := getPaychState(ctx, t, paymentReceiver, chAddr)
|
|
sa, err := chState.SettlingAt()
|
|
require.NoError(t, err)
|
|
waitForHeight(ctx, t, paymentReceiver, sa)
|
|
|
|
t.Log("settle height reached")
|
|
|
|
// receiver: paych collect <channel>
|
|
receiverCLI.RunCmd("paych", "collect", chAddr.String())
|
|
}
|
|
|
|
type voucherSpec struct {
|
|
serialized string
|
|
amt int
|
|
lane int
|
|
}
|
|
|
|
// TestPaymentChannelStatus tests the payment channel status CLI command
|
|
func TestPaymentChannelStatus(t *testing.T) {
|
|
//stm: @CHAIN_SYNCER_LOAD_GENESIS_001, @CHAIN_SYNCER_FETCH_TIPSET_001,
|
|
//stm: @CHAIN_SYNCER_START_001, @CHAIN_SYNCER_SYNC_001, @BLOCKCHAIN_BEACON_VALIDATE_BLOCK_VALUES_01
|
|
//stm: @CHAIN_SYNCER_COLLECT_CHAIN_001, @CHAIN_SYNCER_COLLECT_HEADERS_001, @CHAIN_SYNCER_VALIDATE_TIPSET_001
|
|
//stm: @CHAIN_SYNCER_NEW_PEER_HEAD_001, @CHAIN_SYNCER_VALIDATE_MESSAGE_META_001, @CHAIN_SYNCER_STOP_001
|
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
|
kit.QuietMiningLogs()
|
|
|
|
blocktime := 5 * time.Millisecond
|
|
ctx := context.Background()
|
|
var (
|
|
paymentCreator kit.TestFullNode
|
|
paymentReceiver kit.TestFullNode
|
|
)
|
|
creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime)
|
|
|
|
// Create mock CLI
|
|
mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull)
|
|
creatorCLI := mockCLI.Client(paymentCreator.ListenAddr)
|
|
|
|
// creator: paych status-by-from-to <creator> <receiver>
|
|
out := creatorCLI.RunCmd("paych", "status-by-from-to", creatorAddr.String(), receiverAddr.String())
|
|
fmt.Println(out)
|
|
noChannelState := "Channel does not exist"
|
|
require.Regexp(t, regexp.MustCompile(noChannelState), out)
|
|
|
|
channelAmt := uint64(100)
|
|
create := make(chan string)
|
|
go func() {
|
|
// creator: paych add-funds <creator> <receiver> <amount>
|
|
create <- creatorCLI.RunCmd(
|
|
"paych",
|
|
"add-funds",
|
|
creatorAddr.String(),
|
|
receiverAddr.String(),
|
|
fmt.Sprintf("%d", channelAmt))
|
|
}()
|
|
|
|
// Wait for the output to stop being "Channel does not exist"
|
|
for regexp.MustCompile(noChannelState).MatchString(out) {
|
|
out = creatorCLI.RunCmd("paych", "status-by-from-to", creatorAddr.String(), receiverAddr.String())
|
|
}
|
|
fmt.Println(out)
|
|
|
|
// The next state should be creating channel or channel created, depending
|
|
// on timing
|
|
stateCreating := regexp.MustCompile("Creating channel").MatchString(out)
|
|
stateCreated := regexp.MustCompile("Channel exists").MatchString(out)
|
|
require.True(t, stateCreating || stateCreated)
|
|
|
|
channelAmtAtto := types.BigMul(types.NewInt(channelAmt), types.NewInt(build.FilecoinPrecision))
|
|
channelAmtStr := fmt.Sprintf("%s", types.FIL(channelAmtAtto))
|
|
if stateCreating {
|
|
// If we're in the creating state (most likely) the amount should be pending
|
|
require.Regexp(t, regexp.MustCompile("Pending Amt.*"+channelAmtStr), out)
|
|
}
|
|
|
|
// Wait for create channel to complete
|
|
chstr := <-create
|
|
|
|
out = creatorCLI.RunCmd("paych", "status", chstr)
|
|
fmt.Println(out)
|
|
// Output should have the channel address
|
|
require.Regexp(t, regexp.MustCompile("Channel.*"+chstr), out)
|
|
// Output should have confirmed amount
|
|
require.Regexp(t, regexp.MustCompile("Confirmed.*"+channelAmtStr), out)
|
|
|
|
chAddr, err := address.NewFromString(chstr)
|
|
require.NoError(t, err)
|
|
|
|
// creator: paych voucher create <channel> <amount>
|
|
voucherAmt := uint64(10)
|
|
creatorCLI.RunCmd("paych", "voucher", "create", chAddr.String(), fmt.Sprintf("%d", voucherAmt))
|
|
|
|
out = creatorCLI.RunCmd("paych", "status", chstr)
|
|
fmt.Println(out)
|
|
voucherAmtAtto := types.BigMul(types.NewInt(voucherAmt), types.NewInt(build.FilecoinPrecision))
|
|
voucherAmtStr := fmt.Sprintf("%s", types.FIL(voucherAmtAtto))
|
|
// Output should include voucher amount
|
|
require.Regexp(t, regexp.MustCompile("Voucher.*"+voucherAmtStr), out)
|
|
}
|
|
|
|
// TestPaymentChannelVouchers does a basic test to exercise some payment
|
|
// channel voucher commands
|
|
func TestPaymentChannelVouchers(t *testing.T) {
|
|
//stm: @CHAIN_SYNCER_LOAD_GENESIS_001, @CHAIN_SYNCER_FETCH_TIPSET_001,
|
|
//stm: @CHAIN_SYNCER_START_001, @CHAIN_SYNCER_SYNC_001, @BLOCKCHAIN_BEACON_VALIDATE_BLOCK_VALUES_01
|
|
//stm: @CHAIN_SYNCER_COLLECT_CHAIN_001, @CHAIN_SYNCER_COLLECT_HEADERS_001, @CHAIN_SYNCER_VALIDATE_TIPSET_001
|
|
//stm: @CHAIN_SYNCER_NEW_PEER_HEAD_001, @CHAIN_SYNCER_VALIDATE_MESSAGE_META_001, @CHAIN_SYNCER_STOP_001
|
|
|
|
//stm: @CHAIN_INCOMING_HANDLE_INCOMING_BLOCKS_001, @CHAIN_INCOMING_VALIDATE_BLOCK_PUBSUB_001, @CHAIN_INCOMING_VALIDATE_MESSAGE_PUBSUB_001
|
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
|
kit.QuietMiningLogs()
|
|
|
|
blocktime := 5 * time.Millisecond
|
|
ctx := context.Background()
|
|
var (
|
|
paymentCreator kit.TestFullNode
|
|
paymentReceiver kit.TestFullNode
|
|
)
|
|
creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime)
|
|
|
|
// Create mock CLI
|
|
mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull)
|
|
creatorCLI := mockCLI.Client(paymentCreator.ListenAddr)
|
|
receiverCLI := mockCLI.Client(paymentReceiver.ListenAddr)
|
|
|
|
// creator: paych add-funds <creator> <receiver> <amount>
|
|
channelAmt := "100000"
|
|
chstr := creatorCLI.RunCmd("paych", "add-funds", creatorAddr.String(), receiverAddr.String(), channelAmt)
|
|
|
|
chAddr, err := address.NewFromString(chstr)
|
|
require.NoError(t, err)
|
|
|
|
var vouchers []voucherSpec
|
|
|
|
// creator: paych voucher create <channel> <amount>
|
|
// Note: implied --lane=0
|
|
voucherAmt1 := 100
|
|
voucher1 := creatorCLI.RunCmd("paych", "voucher", "create", chAddr.String(), strconv.Itoa(voucherAmt1))
|
|
vouchers = append(vouchers, voucherSpec{serialized: voucher1, lane: 0, amt: voucherAmt1})
|
|
|
|
// creator: paych voucher create <channel> <amount> --lane=5
|
|
lane5 := "--lane=5"
|
|
voucherAmt2 := 50
|
|
voucher2 := creatorCLI.RunCmd("paych", "voucher", "create", lane5, chAddr.String(), strconv.Itoa(voucherAmt2))
|
|
vouchers = append(vouchers, voucherSpec{serialized: voucher2, lane: 5, amt: voucherAmt2})
|
|
|
|
// creator: paych voucher create <channel> <amount> --lane=5
|
|
voucherAmt3 := 70
|
|
voucher3 := creatorCLI.RunCmd("paych", "voucher", "create", lane5, chAddr.String(), strconv.Itoa(voucherAmt3))
|
|
vouchers = append(vouchers, voucherSpec{serialized: voucher3, lane: 5, amt: voucherAmt3})
|
|
|
|
// creator: paych voucher create <channel> <amount> --lane=5
|
|
voucherAmt4 := 80
|
|
voucher4 := creatorCLI.RunCmd("paych", "voucher", "create", lane5, chAddr.String(), strconv.Itoa(voucherAmt4))
|
|
vouchers = append(vouchers, voucherSpec{serialized: voucher4, lane: 5, amt: voucherAmt4})
|
|
|
|
// creator: paych voucher list <channel> --export
|
|
list := creatorCLI.RunCmd("paych", "voucher", "list", "--export", chAddr.String())
|
|
|
|
// Check that voucher list output is correct on creator
|
|
checkVoucherOutput(t, list, vouchers)
|
|
|
|
// creator: paych voucher best-spendable <channel>
|
|
bestSpendable := creatorCLI.RunCmd("paych", "voucher", "best-spendable", "--export", chAddr.String())
|
|
|
|
// Check that best spendable output is correct on creator
|
|
bestVouchers := []voucherSpec{
|
|
{serialized: voucher1, lane: 0, amt: voucherAmt1},
|
|
{serialized: voucher4, lane: 5, amt: voucherAmt4},
|
|
}
|
|
checkVoucherOutput(t, bestSpendable, bestVouchers)
|
|
|
|
// receiver: paych voucher add <voucher>
|
|
receiverCLI.RunCmd("paych", "voucher", "add", chAddr.String(), voucher1)
|
|
|
|
// receiver: paych voucher add <voucher>
|
|
receiverCLI.RunCmd("paych", "voucher", "add", chAddr.String(), voucher2)
|
|
|
|
// receiver: paych voucher add <voucher>
|
|
receiverCLI.RunCmd("paych", "voucher", "add", chAddr.String(), voucher3)
|
|
|
|
// receiver: paych voucher add <voucher>
|
|
receiverCLI.RunCmd("paych", "voucher", "add", chAddr.String(), voucher4)
|
|
|
|
// receiver: paych voucher list <channel> --export
|
|
list = receiverCLI.RunCmd("paych", "voucher", "list", "--export", chAddr.String())
|
|
|
|
// Check that voucher list output is correct on receiver
|
|
checkVoucherOutput(t, list, vouchers)
|
|
|
|
// receiver: paych voucher best-spendable <channel>
|
|
bestSpendable = receiverCLI.RunCmd("paych", "voucher", "best-spendable", "--export", chAddr.String())
|
|
|
|
// Check that best spendable output is correct on receiver
|
|
bestVouchers = []voucherSpec{
|
|
{serialized: voucher1, lane: 0, amt: voucherAmt1},
|
|
{serialized: voucher4, lane: 5, amt: voucherAmt4},
|
|
}
|
|
checkVoucherOutput(t, bestSpendable, bestVouchers)
|
|
|
|
// receiver: paych voucher submit <channel> <voucher>
|
|
receiverCLI.RunCmd("paych", "voucher", "submit", chAddr.String(), voucher1)
|
|
|
|
// receiver: paych voucher best-spendable <channel>
|
|
bestSpendable = receiverCLI.RunCmd("paych", "voucher", "best-spendable", "--export", chAddr.String())
|
|
|
|
// Check that best spendable output no longer includes submitted voucher
|
|
bestVouchers = []voucherSpec{
|
|
{serialized: voucher4, lane: 5, amt: voucherAmt4},
|
|
}
|
|
checkVoucherOutput(t, bestSpendable, bestVouchers)
|
|
|
|
// There are three vouchers in lane 5: 50, 70, 80
|
|
// Submit the voucher for 50. Best spendable should still be 80.
|
|
// receiver: paych voucher submit <channel> <voucher>
|
|
receiverCLI.RunCmd("paych", "voucher", "submit", chAddr.String(), voucher2)
|
|
|
|
// receiver: paych voucher best-spendable <channel>
|
|
bestSpendable = receiverCLI.RunCmd("paych", "voucher", "best-spendable", "--export", chAddr.String())
|
|
|
|
// Check that best spendable output still includes the voucher for 80
|
|
bestVouchers = []voucherSpec{
|
|
{serialized: voucher4, lane: 5, amt: voucherAmt4},
|
|
}
|
|
checkVoucherOutput(t, bestSpendable, bestVouchers)
|
|
|
|
// Submit the voucher for 80
|
|
// receiver: paych voucher submit <channel> <voucher>
|
|
receiverCLI.RunCmd("paych", "voucher", "submit", chAddr.String(), voucher4)
|
|
|
|
// receiver: paych voucher best-spendable <channel>
|
|
bestSpendable = receiverCLI.RunCmd("paych", "voucher", "best-spendable", "--export", chAddr.String())
|
|
|
|
// Check that best spendable output no longer includes submitted voucher
|
|
bestVouchers = []voucherSpec{}
|
|
checkVoucherOutput(t, bestSpendable, bestVouchers)
|
|
}
|
|
|
|
// TestPaymentChannelVoucherCreateShortfall verifies that if a voucher amount
|
|
// is greater than what's left in the channel, voucher create fails
|
|
func TestPaymentChannelVoucherCreateShortfall(t *testing.T) {
|
|
//stm: @CHAIN_SYNCER_LOAD_GENESIS_001, @CHAIN_SYNCER_FETCH_TIPSET_001,
|
|
//stm: @CHAIN_SYNCER_START_001, @CHAIN_SYNCER_SYNC_001, @BLOCKCHAIN_BEACON_VALIDATE_BLOCK_VALUES_01
|
|
//stm: @CHAIN_SYNCER_COLLECT_CHAIN_001, @CHAIN_SYNCER_COLLECT_HEADERS_001, @CHAIN_SYNCER_VALIDATE_TIPSET_001
|
|
//stm: @CHAIN_SYNCER_NEW_PEER_HEAD_001, @CHAIN_SYNCER_VALIDATE_MESSAGE_META_001, @CHAIN_SYNCER_STOP_001
|
|
|
|
//stm: @CHAIN_INCOMING_HANDLE_INCOMING_BLOCKS_001, @CHAIN_INCOMING_VALIDATE_BLOCK_PUBSUB_001, @CHAIN_INCOMING_VALIDATE_MESSAGE_PUBSUB_001
|
|
_ = os.Setenv("BELLMAN_NO_GPU", "1")
|
|
kit.QuietMiningLogs()
|
|
|
|
blocktime := 5 * time.Millisecond
|
|
ctx := context.Background()
|
|
var (
|
|
paymentCreator kit.TestFullNode
|
|
paymentReceiver kit.TestFullNode
|
|
)
|
|
creatorAddr, receiverAddr := startPaychCreatorReceiverMiner(ctx, t, &paymentCreator, &paymentReceiver, blocktime)
|
|
|
|
// Create mock CLI
|
|
mockCLI := kit.NewMockCLI(ctx, t, cli.Commands, api.NodeFull)
|
|
creatorCLI := mockCLI.Client(paymentCreator.ListenAddr)
|
|
|
|
// creator: paych add-funds <creator> <receiver> <amount>
|
|
channelAmt := 100
|
|
chstr := creatorCLI.RunCmd(
|
|
"paych",
|
|
"add-funds",
|
|
creatorAddr.String(),
|
|
receiverAddr.String(),
|
|
fmt.Sprintf("%d", channelAmt))
|
|
|
|
chAddr, err := address.NewFromString(chstr)
|
|
require.NoError(t, err)
|
|
|
|
// creator: paych voucher create <channel> <amount> --lane=1
|
|
voucherAmt1 := 60
|
|
lane1 := "--lane=1"
|
|
voucher1 := creatorCLI.RunCmd(
|
|
"paych",
|
|
"voucher",
|
|
"create",
|
|
lane1,
|
|
chAddr.String(),
|
|
strconv.Itoa(voucherAmt1))
|
|
fmt.Println(voucher1)
|
|
|
|
// creator: paych voucher create <channel> <amount> --lane=2
|
|
lane2 := "--lane=2"
|
|
voucherAmt2 := 70
|
|
_, err = creatorCLI.RunCmdRaw(
|
|
"paych",
|
|
"voucher",
|
|
"create",
|
|
lane2,
|
|
chAddr.String(),
|
|
strconv.Itoa(voucherAmt2))
|
|
|
|
// Should fail because channel doesn't have required amount
|
|
require.Error(t, err)
|
|
|
|
shortfall := voucherAmt1 + voucherAmt2 - channelAmt
|
|
require.Regexp(t, regexp.MustCompile(fmt.Sprintf("shortfall: %d", shortfall)), err.Error())
|
|
}
|
|
|
|
func checkVoucherOutput(t *testing.T, list string, vouchers []voucherSpec) {
|
|
lines := strings.Split(list, "\n")
|
|
listVouchers := make(map[string]string)
|
|
for _, line := range lines {
|
|
parts := strings.Split(line, ";")
|
|
if len(parts) == 2 {
|
|
serialized := strings.TrimSpace(parts[1])
|
|
listVouchers[serialized] = strings.TrimSpace(parts[0])
|
|
}
|
|
}
|
|
for _, vchr := range vouchers {
|
|
res, ok := listVouchers[vchr.serialized]
|
|
require.True(t, ok)
|
|
require.Regexp(t, fmt.Sprintf("Lane %d", vchr.lane), res)
|
|
require.Regexp(t, fmt.Sprintf("%d", vchr.amt), res)
|
|
delete(listVouchers, vchr.serialized)
|
|
}
|
|
for _, vchr := range listVouchers {
|
|
require.Fail(t, "Extra voucher "+vchr)
|
|
}
|
|
}
|
|
|
|
// waitForHeight waits for the node to reach the given chain epoch
|
|
func waitForHeight(ctx context.Context, t *testing.T, node kit.TestFullNode, height abi.ChainEpoch) {
|
|
atHeight := make(chan struct{})
|
|
chainEvents, err := events.NewEvents(ctx, node)
|
|
require.NoError(t, err)
|
|
err = chainEvents.ChainAt(ctx, func(ctx context.Context, ts *types.TipSet, curH abi.ChainEpoch) error {
|
|
close(atHeight)
|
|
return nil
|
|
}, nil, 1, height)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
select {
|
|
case <-atHeight:
|
|
case <-ctx.Done():
|
|
}
|
|
}
|
|
|
|
// getPaychState gets the state of the payment channel with the given address
|
|
func getPaychState(ctx context.Context, t *testing.T, node kit.TestFullNode, chAddr address.Address) paych.State {
|
|
act, err := node.StateGetActor(ctx, chAddr, types.EmptyTSK)
|
|
require.NoError(t, err)
|
|
|
|
store := cbor.NewCborStore(blockstore.NewAPIBlockstore(node))
|
|
chState, err := paych.Load(adt.WrapStore(ctx, store), act)
|
|
require.NoError(t, err)
|
|
|
|
return chState
|
|
}
|
|
|
|
func startPaychCreatorReceiverMiner(ctx context.Context, t *testing.T, paymentCreator *kit.TestFullNode, paymentReceiver *kit.TestFullNode, blocktime time.Duration) (address.Address, address.Address) {
|
|
var miner kit.TestMiner
|
|
opts := kit.ThroughRPC()
|
|
kit.NewEnsemble(t, kit.MockProofs()).
|
|
FullNode(paymentCreator, opts).
|
|
FullNode(paymentReceiver, opts).
|
|
Miner(&miner, paymentCreator, kit.WithAllSubsystems()).
|
|
Start().
|
|
InterconnectAll().
|
|
BeginMining(blocktime)
|
|
|
|
// Send some funds to the second node
|
|
receiverAddr, err := paymentReceiver.WalletDefaultAddress(ctx)
|
|
require.NoError(t, err)
|
|
kit.SendFunds(ctx, t, paymentCreator, receiverAddr, abi.NewTokenAmount(1e18))
|
|
|
|
// Get the first node's address
|
|
creatorAddr, err := paymentCreator.WalletDefaultAddress(ctx)
|
|
require.NoError(t, err)
|
|
return creatorAddr, receiverAddr
|
|
}
|