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>
1084 lines
25 KiB
Go
1084 lines
25 KiB
Go
// stm: #unit
|
|
package messagepool
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/ipfs/go-cid"
|
|
"github.com/ipfs/go-datastore"
|
|
logging "github.com/ipfs/go-log/v2"
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
"github.com/filecoin-project/go-state-types/abi"
|
|
"github.com/filecoin-project/go-state-types/crypto"
|
|
"github.com/filecoin-project/go-state-types/network"
|
|
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
|
|
|
"github.com/filecoin-project/lotus/api"
|
|
"github.com/filecoin-project/lotus/build"
|
|
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
|
"github.com/filecoin-project/lotus/chain/messagepool/gasguess"
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
"github.com/filecoin-project/lotus/chain/types/mock"
|
|
"github.com/filecoin-project/lotus/chain/wallet"
|
|
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
|
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
|
)
|
|
|
|
func init() {
|
|
_ = logging.SetLogLevel("*", "INFO")
|
|
}
|
|
|
|
type testMpoolAPI struct {
|
|
cb func(rev, app []*types.TipSet) error
|
|
|
|
bmsgs map[cid.Cid][]*types.SignedMessage
|
|
statenonce map[address.Address]uint64
|
|
balance map[address.Address]types.BigInt
|
|
|
|
tipsets []*types.TipSet
|
|
|
|
published int
|
|
|
|
baseFee types.BigInt
|
|
}
|
|
|
|
func newTestMpoolAPI() *testMpoolAPI {
|
|
tma := &testMpoolAPI{
|
|
bmsgs: make(map[cid.Cid][]*types.SignedMessage),
|
|
statenonce: make(map[address.Address]uint64),
|
|
balance: make(map[address.Address]types.BigInt),
|
|
baseFee: types.NewInt(100),
|
|
}
|
|
genesis := mock.MkBlock(nil, 1, 1)
|
|
tma.tipsets = append(tma.tipsets, mock.TipSet(genesis))
|
|
return tma
|
|
}
|
|
|
|
func (tma *testMpoolAPI) nextBlock() *types.BlockHeader {
|
|
newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1)
|
|
tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk))
|
|
return newBlk
|
|
}
|
|
|
|
func (tma *testMpoolAPI) nextBlockWithHeight(height uint64) *types.BlockHeader {
|
|
newBlk := mock.MkBlock(tma.tipsets[len(tma.tipsets)-1], 1, 1)
|
|
newBlk.Height = abi.ChainEpoch(height)
|
|
tma.tipsets = append(tma.tipsets, mock.TipSet(newBlk))
|
|
return newBlk
|
|
}
|
|
|
|
func (tma *testMpoolAPI) applyBlock(t *testing.T, b *types.BlockHeader) {
|
|
t.Helper()
|
|
if err := tma.cb(nil, []*types.TipSet{mock.TipSet(b)}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func (tma *testMpoolAPI) revertBlock(t *testing.T, b *types.BlockHeader) {
|
|
t.Helper()
|
|
if err := tma.cb([]*types.TipSet{mock.TipSet(b)}, nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func (tma *testMpoolAPI) setStateNonce(addr address.Address, v uint64) {
|
|
tma.statenonce[addr] = v
|
|
}
|
|
|
|
func (tma *testMpoolAPI) setBalance(addr address.Address, v uint64) {
|
|
tma.balance[addr] = types.FromFil(v)
|
|
}
|
|
|
|
func (tma *testMpoolAPI) setBalanceRaw(addr address.Address, v types.BigInt) {
|
|
tma.balance[addr] = v
|
|
}
|
|
|
|
func (tma *testMpoolAPI) setBlockMessages(h *types.BlockHeader, msgs ...*types.SignedMessage) {
|
|
tma.bmsgs[h.Cid()] = msgs
|
|
}
|
|
|
|
func (tma *testMpoolAPI) SubscribeHeadChanges(cb func(rev, app []*types.TipSet) error) *types.TipSet {
|
|
tma.cb = cb
|
|
return tma.tipsets[0]
|
|
}
|
|
|
|
func (tma *testMpoolAPI) PutMessage(ctx context.Context, m types.ChainMsg) (cid.Cid, error) {
|
|
return cid.Undef, nil
|
|
}
|
|
|
|
func (tma *testMpoolAPI) IsLite() bool {
|
|
return false
|
|
}
|
|
|
|
func (tma *testMpoolAPI) PubSubPublish(string, []byte) error {
|
|
tma.published++
|
|
return nil
|
|
}
|
|
|
|
func (tma *testMpoolAPI) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
|
// regression check for load bug
|
|
if ts == nil {
|
|
panic("GetActorAfter called with nil tipset")
|
|
}
|
|
|
|
balance, ok := tma.balance[addr]
|
|
if !ok {
|
|
balance = types.NewInt(1000e6)
|
|
tma.balance[addr] = balance
|
|
}
|
|
|
|
msgs := make([]*types.SignedMessage, 0)
|
|
for _, b := range ts.Blocks() {
|
|
for _, m := range tma.bmsgs[b.Cid()] {
|
|
if m.Message.From == addr {
|
|
msgs = append(msgs, m)
|
|
}
|
|
}
|
|
}
|
|
|
|
sort.Slice(msgs, func(i, j int) bool {
|
|
return msgs[i].Message.Nonce < msgs[j].Message.Nonce
|
|
})
|
|
|
|
nonce := tma.statenonce[addr]
|
|
|
|
for _, m := range msgs {
|
|
if m.Message.Nonce != nonce {
|
|
break
|
|
}
|
|
nonce++
|
|
}
|
|
|
|
return &types.Actor{
|
|
Code: builtin2.StorageMarketActorCodeID,
|
|
Nonce: nonce,
|
|
Balance: balance,
|
|
}, nil
|
|
}
|
|
|
|
func (tma *testMpoolAPI) StateAccountKeyAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
|
if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 {
|
|
return address.Undef, fmt.Errorf("given address was not a key addr")
|
|
}
|
|
return addr, nil
|
|
}
|
|
|
|
func (tma *testMpoolAPI) StateNetworkVersion(ctx context.Context, h abi.ChainEpoch) network.Version {
|
|
return build.TestNetworkVersion
|
|
}
|
|
|
|
func (tma *testMpoolAPI) MessagesForBlock(ctx context.Context, h *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) {
|
|
return nil, tma.bmsgs[h.Cid()], nil
|
|
}
|
|
|
|
func (tma *testMpoolAPI) MessagesForTipset(ctx context.Context, ts *types.TipSet) ([]types.ChainMsg, error) {
|
|
if len(ts.Blocks()) != 1 {
|
|
panic("cant deal with multiblock tipsets in this test")
|
|
}
|
|
|
|
bm, sm, err := tma.MessagesForBlock(ctx, ts.Blocks()[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var out []types.ChainMsg
|
|
for _, m := range bm {
|
|
out = append(out, m)
|
|
}
|
|
|
|
for _, m := range sm {
|
|
out = append(out, m)
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
func (tma *testMpoolAPI) LoadTipSet(ctx context.Context, tsk types.TipSetKey) (*types.TipSet, error) {
|
|
for _, ts := range tma.tipsets {
|
|
if types.CidArrsEqual(tsk.Cids(), ts.Cids()) {
|
|
return ts, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("tipset not found")
|
|
}
|
|
|
|
func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipSet) (types.BigInt, error) {
|
|
return tma.baseFee, nil
|
|
}
|
|
|
|
func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) {
|
|
t.Helper()
|
|
//stm: @CHAIN_MEMPOOL_GET_NONCE_001
|
|
n, err := mp.GetNonce(context.TODO(), addr, types.EmptyTSK)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if n != val {
|
|
t.Fatalf("expected nonce of %d, got %d", val, n)
|
|
}
|
|
}
|
|
|
|
func mustAdd(t *testing.T, mp *MessagePool, msg *types.SignedMessage) {
|
|
t.Helper()
|
|
if err := mp.Add(context.TODO(), msg); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestMessagePool(t *testing.T) {
|
|
//stm: @CHAIN_MEMPOOL_GET_NONCE_001
|
|
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a := tma.nextBlock()
|
|
|
|
sender, err := w.WalletNew(context.Background(), types.KTSecp256k1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
target := mock.Address(1001)
|
|
|
|
var msgs []*types.SignedMessage
|
|
for i := 0; i < 5; i++ {
|
|
msgs = append(msgs, mock.MkMessage(sender, target, uint64(i), w))
|
|
}
|
|
|
|
tma.setStateNonce(sender, 0)
|
|
assertNonce(t, mp, sender, 0)
|
|
mustAdd(t, mp, msgs[0])
|
|
assertNonce(t, mp, sender, 1)
|
|
mustAdd(t, mp, msgs[1])
|
|
assertNonce(t, mp, sender, 2)
|
|
|
|
tma.setBlockMessages(a, msgs[0], msgs[1])
|
|
tma.applyBlock(t, a)
|
|
|
|
assertNonce(t, mp, sender, 2)
|
|
}
|
|
|
|
func TestCheckMessageBig(t *testing.T) {
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
assert.NoError(t, err)
|
|
|
|
from, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
assert.NoError(t, err)
|
|
|
|
tma.setBalance(from, 1000e9)
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
assert.NoError(t, err)
|
|
|
|
to := mock.Address(1001)
|
|
|
|
{
|
|
msg := &types.Message{
|
|
To: to,
|
|
From: from,
|
|
Value: types.NewInt(1),
|
|
Nonce: 0,
|
|
GasLimit: 60000000,
|
|
GasFeeCap: types.NewInt(100),
|
|
GasPremium: types.NewInt(1),
|
|
Params: make([]byte, 41<<10), // 41KiB payload
|
|
}
|
|
|
|
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
sm := &types.SignedMessage{
|
|
Message: *msg,
|
|
Signature: *sig,
|
|
}
|
|
mustAdd(t, mp, sm)
|
|
}
|
|
|
|
{
|
|
msg := &types.Message{
|
|
To: to,
|
|
From: from,
|
|
Value: types.NewInt(1),
|
|
Nonce: 0,
|
|
GasLimit: 50000000,
|
|
GasFeeCap: types.NewInt(100),
|
|
GasPremium: types.NewInt(1),
|
|
Params: make([]byte, 64<<10), // 64KiB payload
|
|
}
|
|
|
|
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
sm := &types.SignedMessage{
|
|
Message: *msg,
|
|
Signature: *sig,
|
|
}
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
err = mp.Add(context.TODO(), sm)
|
|
assert.ErrorIs(t, err, ErrMessageTooBig)
|
|
}
|
|
}
|
|
|
|
func TestMessagePoolMessagesInEachBlock(t *testing.T) {
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a := tma.nextBlock()
|
|
|
|
sender, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
target := mock.Address(1001)
|
|
|
|
var msgs []*types.SignedMessage
|
|
for i := 0; i < 5; i++ {
|
|
m := mock.MkMessage(sender, target, uint64(i), w)
|
|
msgs = append(msgs, m)
|
|
mustAdd(t, mp, m)
|
|
}
|
|
|
|
tma.setStateNonce(sender, 0)
|
|
|
|
tma.setBlockMessages(a, msgs[0], msgs[1])
|
|
tma.applyBlock(t, a)
|
|
tsa := mock.TipSet(a)
|
|
|
|
//stm: @CHAIN_MEMPOOL_PENDING_001
|
|
_, _ = mp.Pending(context.TODO())
|
|
|
|
//stm: @CHAIN_MEMPOOL_SELECT_001
|
|
selm, _ := mp.SelectMessages(context.Background(), tsa, 1)
|
|
if len(selm) == 0 {
|
|
t.Fatal("should have returned the rest of the messages")
|
|
}
|
|
}
|
|
|
|
func TestRevertMessages(t *testing.T) {
|
|
futureDebug = true
|
|
defer func() {
|
|
futureDebug = false
|
|
}()
|
|
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a := tma.nextBlock()
|
|
b := tma.nextBlock()
|
|
|
|
sender, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
target := mock.Address(1001)
|
|
|
|
var msgs []*types.SignedMessage
|
|
for i := 0; i < 5; i++ {
|
|
msgs = append(msgs, mock.MkMessage(sender, target, uint64(i), w))
|
|
}
|
|
|
|
tma.setBlockMessages(a, msgs[0])
|
|
tma.setBlockMessages(b, msgs[1], msgs[2], msgs[3])
|
|
|
|
mustAdd(t, mp, msgs[0])
|
|
mustAdd(t, mp, msgs[1])
|
|
mustAdd(t, mp, msgs[2])
|
|
mustAdd(t, mp, msgs[3])
|
|
|
|
tma.setStateNonce(sender, 0)
|
|
tma.applyBlock(t, a)
|
|
assertNonce(t, mp, sender, 4)
|
|
|
|
tma.setStateNonce(sender, 1)
|
|
tma.applyBlock(t, b)
|
|
assertNonce(t, mp, sender, 4)
|
|
tma.setStateNonce(sender, 0)
|
|
tma.revertBlock(t, b)
|
|
|
|
assertNonce(t, mp, sender, 4)
|
|
|
|
//stm: @CHAIN_MEMPOOL_PENDING_001
|
|
p, _ := mp.Pending(context.TODO())
|
|
fmt.Printf("%+v\n", p)
|
|
if len(p) != 3 {
|
|
t.Fatal("expected three messages in mempool")
|
|
}
|
|
|
|
}
|
|
|
|
func TestPruningSimple(t *testing.T) {
|
|
oldMaxNonceGap := MaxNonceGap
|
|
MaxNonceGap = 1000
|
|
defer func() {
|
|
MaxNonceGap = oldMaxNonceGap
|
|
}()
|
|
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a := tma.nextBlock()
|
|
tma.applyBlock(t, a)
|
|
|
|
sender, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tma.setBalance(sender, 1) // in FIL
|
|
target := mock.Address(1001)
|
|
|
|
for i := 0; i < 5; i++ {
|
|
smsg := mock.MkMessage(sender, target, uint64(i), w)
|
|
if err := mp.Add(context.TODO(), smsg); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
for i := 10; i < 50; i++ {
|
|
smsg := mock.MkMessage(sender, target, uint64(i), w)
|
|
if err := mp.Add(context.TODO(), smsg); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
mp.cfg.SizeLimitHigh = 40
|
|
mp.cfg.SizeLimitLow = 10
|
|
|
|
mp.Prune()
|
|
|
|
//stm: @CHAIN_MEMPOOL_PENDING_001
|
|
msgs, _ := mp.Pending(context.TODO())
|
|
if len(msgs) != 5 {
|
|
t.Fatal("expected only 5 messages in pool, got: ", len(msgs))
|
|
}
|
|
}
|
|
|
|
func TestLoadLocal(t *testing.T) {
|
|
tma := newTestMpoolAPI()
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// the actors
|
|
w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tma.setBalance(a1, 1) // in FIL
|
|
tma.setBalance(a2, 1) // in FIL
|
|
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
|
|
msgs := make(map[cid.Cid]struct{})
|
|
for i := 0; i < 10; i++ {
|
|
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
cid, err := mp.Push(context.TODO(), m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
msgs[cid] = struct{}{}
|
|
}
|
|
err = mp.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mp, err = New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
//stm: @CHAIN_MEMPOOL_PENDING_001
|
|
pmsgs, _ := mp.Pending(context.TODO())
|
|
if len(msgs) != len(pmsgs) {
|
|
t.Fatalf("expected %d messages, but got %d", len(msgs), len(pmsgs))
|
|
}
|
|
|
|
for _, m := range pmsgs {
|
|
cid := m.Cid()
|
|
_, ok := msgs[cid]
|
|
if !ok {
|
|
t.Fatal("unknown message")
|
|
}
|
|
|
|
delete(msgs, cid)
|
|
}
|
|
|
|
if len(msgs) > 0 {
|
|
t.Fatalf("not all messages were laoded; missing %d messages", len(msgs))
|
|
}
|
|
}
|
|
|
|
func TestClearAll(t *testing.T) {
|
|
tma := newTestMpoolAPI()
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// the actors
|
|
w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tma.setBalance(a1, 1) // in FIL
|
|
tma.setBalance(a2, 1) // in FIL
|
|
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
|
|
for i := 0; i < 10; i++ {
|
|
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
_, err := mp.Push(context.TODO(), m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
m := makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1))
|
|
mustAdd(t, mp, m)
|
|
}
|
|
|
|
//stm: @CHAIN_MEMPOOL_CLEAR_001
|
|
mp.Clear(context.Background(), true)
|
|
|
|
//stm: @CHAIN_MEMPOOL_PENDING_001
|
|
pending, _ := mp.Pending(context.TODO())
|
|
if len(pending) > 0 {
|
|
t.Fatalf("cleared the mpool, but got %d pending messages", len(pending))
|
|
}
|
|
}
|
|
|
|
func TestClearNonLocal(t *testing.T) {
|
|
tma := newTestMpoolAPI()
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// the actors
|
|
w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tma.setBalance(a1, 1) // in FIL
|
|
tma.setBalance(a2, 1) // in FIL
|
|
|
|
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
|
|
for i := 0; i < 10; i++ {
|
|
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
_, err := mp.Push(context.TODO(), m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
m := makeTestMessage(w2, a2, a1, uint64(i), gasLimit, uint64(i+1))
|
|
mustAdd(t, mp, m)
|
|
}
|
|
|
|
//stm: @CHAIN_MEMPOOL_CLEAR_001
|
|
mp.Clear(context.Background(), false)
|
|
|
|
//stm: @CHAIN_MEMPOOL_PENDING_001
|
|
pending, _ := mp.Pending(context.TODO())
|
|
if len(pending) != 10 {
|
|
t.Fatalf("expected 10 pending messages, but got %d instead", len(pending))
|
|
}
|
|
|
|
for _, m := range pending {
|
|
if m.Message.From != a1 {
|
|
t.Fatalf("expected message from %s but got one from %s instead", a1, m.Message.From)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUpdates(t *testing.T) {
|
|
tma := newTestMpoolAPI()
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// the actors
|
|
w1, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a1, err := w1.WalletNew(context.Background(), types.KTSecp256k1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
w2, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
a2, err := w2.WalletNew(context.Background(), types.KTSecp256k1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(context.TODO())
|
|
defer cancel()
|
|
|
|
ch, err := mp.Updates(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
|
|
|
|
tma.setBalance(a1, 1) // in FIL
|
|
tma.setBalance(a2, 1) // in FIL
|
|
|
|
for i := 0; i < 10; i++ {
|
|
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
_, err := mp.Push(context.TODO(), m)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, ok := <-ch
|
|
if !ok {
|
|
t.Fatal("expected update, but got a closed channel instead")
|
|
}
|
|
}
|
|
|
|
err = mp.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, ok := <-ch
|
|
if ok {
|
|
t.Fatal("expected closed channel, but got an update instead")
|
|
}
|
|
}
|
|
|
|
func TestMessageBelowMinGasFee(t *testing.T) {
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
assert.NoError(t, err)
|
|
|
|
from, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
assert.NoError(t, err)
|
|
|
|
tma.setBalance(from, 1000e9)
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
assert.NoError(t, err)
|
|
|
|
to := mock.Address(1001)
|
|
|
|
// fee is just below minimum gas fee
|
|
fee := minimumBaseFee.Uint64() - 1
|
|
{
|
|
msg := &types.Message{
|
|
To: to,
|
|
From: from,
|
|
Value: types.NewInt(1),
|
|
Nonce: 0,
|
|
GasLimit: 50000000,
|
|
GasFeeCap: types.NewInt(fee),
|
|
GasPremium: types.NewInt(1),
|
|
Params: make([]byte, 32<<10),
|
|
}
|
|
|
|
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
sm := &types.SignedMessage{
|
|
Message: *msg,
|
|
Signature: *sig,
|
|
}
|
|
err = mp.Add(context.TODO(), sm)
|
|
assert.ErrorIs(t, err, ErrGasFeeCapTooLow)
|
|
}
|
|
}
|
|
|
|
func TestMessageValueTooHigh(t *testing.T) {
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
assert.NoError(t, err)
|
|
|
|
from, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
assert.NoError(t, err)
|
|
|
|
tma.setBalance(from, 1000e9)
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
assert.NoError(t, err)
|
|
|
|
to := mock.Address(1001)
|
|
|
|
totalFil := types.TotalFilecoinInt
|
|
extra := types.NewInt(1)
|
|
|
|
value := types.BigAdd(totalFil, extra)
|
|
{
|
|
msg := &types.Message{
|
|
To: to,
|
|
From: from,
|
|
Value: value,
|
|
Nonce: 0,
|
|
GasLimit: 50000000,
|
|
GasFeeCap: types.NewInt(minimumBaseFee.Uint64()),
|
|
GasPremium: types.NewInt(1),
|
|
Params: make([]byte, 32<<10),
|
|
}
|
|
|
|
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
sm := &types.SignedMessage{
|
|
Message: *msg,
|
|
Signature: *sig,
|
|
}
|
|
err = mp.Add(context.TODO(), sm)
|
|
assert.Error(t, err)
|
|
}
|
|
}
|
|
|
|
func TestMessageSignatureInvalid(t *testing.T) {
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
assert.NoError(t, err)
|
|
|
|
from, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
assert.NoError(t, err)
|
|
|
|
tma.setBalance(from, 1000e9)
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
assert.NoError(t, err)
|
|
|
|
to := mock.Address(1001)
|
|
|
|
{
|
|
msg := &types.Message{
|
|
To: to,
|
|
From: from,
|
|
Value: types.NewInt(1),
|
|
Nonce: 0,
|
|
GasLimit: 50000000,
|
|
GasFeeCap: types.NewInt(minimumBaseFee.Uint64()),
|
|
GasPremium: types.NewInt(1),
|
|
Params: make([]byte, 32<<10),
|
|
}
|
|
|
|
badSig := &crypto.Signature{
|
|
Type: crypto.SigTypeSecp256k1,
|
|
Data: make([]byte, 0),
|
|
}
|
|
sm := &types.SignedMessage{
|
|
Message: *msg,
|
|
Signature: *badSig,
|
|
}
|
|
err = mp.Add(context.TODO(), sm)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "invalid signature length")
|
|
}
|
|
}
|
|
|
|
func TestAddMessageTwice(t *testing.T) {
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
assert.NoError(t, err)
|
|
|
|
from, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
assert.NoError(t, err)
|
|
|
|
tma.setBalance(from, 1000e9)
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
assert.NoError(t, err)
|
|
|
|
to := mock.Address(1001)
|
|
|
|
{
|
|
msg := &types.Message{
|
|
To: to,
|
|
From: from,
|
|
Value: types.NewInt(1),
|
|
Nonce: 0,
|
|
GasLimit: 50000000,
|
|
GasFeeCap: types.NewInt(minimumBaseFee.Uint64()),
|
|
GasPremium: types.NewInt(1),
|
|
Params: make([]byte, 32<<10),
|
|
}
|
|
|
|
sig, err := w.WalletSign(context.TODO(), from, msg.Cid().Bytes(), api.MsgMeta{})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
sm := &types.SignedMessage{
|
|
Message: *msg,
|
|
Signature: *sig,
|
|
}
|
|
mustAdd(t, mp, sm)
|
|
|
|
err = mp.Add(context.TODO(), sm)
|
|
assert.Contains(t, err.Error(), "with nonce 0 already in mpool")
|
|
}
|
|
}
|
|
|
|
func TestAddMessageTwiceNonceGap(t *testing.T) {
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
assert.NoError(t, err)
|
|
|
|
from, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
assert.NoError(t, err)
|
|
|
|
tma.setBalance(from, 1000e9)
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
assert.NoError(t, err)
|
|
|
|
to := mock.Address(1001)
|
|
|
|
{
|
|
// create message with invalid nonce (1)
|
|
sm := makeTestMessage(w, from, to, 1, 50_000_000, minimumBaseFee.Uint64())
|
|
mustAdd(t, mp, sm)
|
|
|
|
// then try to add message again
|
|
err = mp.Add(context.TODO(), sm)
|
|
assert.Contains(t, err.Error(), "unfulfilled nonce gap")
|
|
}
|
|
}
|
|
|
|
func TestAddMessageTwiceCidDiff(t *testing.T) {
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
assert.NoError(t, err)
|
|
|
|
from, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
assert.NoError(t, err)
|
|
|
|
tma.setBalance(from, 1000e9)
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
assert.NoError(t, err)
|
|
|
|
to := mock.Address(1001)
|
|
|
|
{
|
|
sm := makeTestMessage(w, from, to, 0, 50_000_000, minimumBaseFee.Uint64())
|
|
mustAdd(t, mp, sm)
|
|
|
|
// Create message with different data, so CID is different
|
|
sm2 := makeTestMessage(w, from, to, 0, 50_000_001, minimumBaseFee.Uint64())
|
|
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
// then try to add message again
|
|
err = mp.Add(context.TODO(), sm2)
|
|
// assert.Contains(t, err.Error(), "replace by fee has too low GasPremium")
|
|
assert.Error(t, err)
|
|
}
|
|
}
|
|
|
|
func TestAddMessageTwiceCidDiffReplaced(t *testing.T) {
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
assert.NoError(t, err)
|
|
|
|
from, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
assert.NoError(t, err)
|
|
|
|
tma.setBalance(from, 1000e9)
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
assert.NoError(t, err)
|
|
|
|
to := mock.Address(1001)
|
|
|
|
{
|
|
sm := makeTestMessage(w, from, to, 0, 50_000_000, minimumBaseFee.Uint64())
|
|
mustAdd(t, mp, sm)
|
|
|
|
// Create message with different data, so CID is different
|
|
sm2 := makeTestMessage(w, from, to, 0, 50_000_000, minimumBaseFee.Uint64()*2)
|
|
mustAdd(t, mp, sm2)
|
|
}
|
|
}
|
|
|
|
func TestRemoveMessage(t *testing.T) {
|
|
//stm: @CHAIN_MEMPOOL_PUSH_001
|
|
tma := newTestMpoolAPI()
|
|
|
|
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
|
assert.NoError(t, err)
|
|
|
|
from, err := w.WalletNew(context.Background(), types.KTBLS)
|
|
assert.NoError(t, err)
|
|
|
|
tma.setBalance(from, 1000e9)
|
|
|
|
ds := datastore.NewMapDatastore()
|
|
|
|
mp, err := New(context.Background(), tma, ds, filcns.DefaultUpgradeSchedule(), "mptest", nil)
|
|
assert.NoError(t, err)
|
|
|
|
to := mock.Address(1001)
|
|
|
|
{
|
|
sm := makeTestMessage(w, from, to, 0, 50_000_000, minimumBaseFee.Uint64())
|
|
mustAdd(t, mp, sm)
|
|
|
|
//stm: @CHAIN_MEMPOOL_REMOVE_001
|
|
// remove message for sender
|
|
mp.Remove(context.TODO(), from, sm.Message.Nonce, true)
|
|
|
|
//stm: @CHAIN_MEMPOOL_PENDING_FOR_001
|
|
// check messages in pool: should be none present
|
|
msgs := mp.pendingFor(context.TODO(), from)
|
|
assert.Len(t, msgs, 0)
|
|
}
|
|
}
|