diff --git a/.circleci/config.yml b/.circleci/config.yml index e9d286fc2f..258932ddb9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,7 +25,7 @@ commands: description: Coverage flag. Set to the empty string to disable. go-test-flags: type: string - default: "-timeout 30m" + default: "-timeout 45m" description: Flags passed to go test. suite: type: string diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1734a8fff3..04ca80ce7d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,7 +59,7 @@ jobs: run: go test -coverpkg=./... -coverprofile=coverage_venus_shared.txt -covermode=atomic -timeout=30m -parallel=4 -v ./venus-shared/... - name: Unit Test - run: go test -coverpkg=./... -coverprofile=coverage_unit.txt -covermode=atomic -timeout=30m -parallel=4 -v $(go list ./... | grep -v /venus-shared/) -integration=false -unit=true + run: go test -coverpkg=./... -coverprofile=coverage_unit.txt -covermode=atomic -timeout=45m -parallel=4 -v $(go list ./... | grep -v /venus-shared/) -integration=false -unit=true - name: Integration Test run: go test -coverpkg=./... -coverprofile=coverage_integration.txt -covermode=atomic -timeout=30m -parallel=4 -v $(go list ./... | grep -v /venus-shared/) -integration=true -unit=false diff --git a/pkg/messagepool/messagepool_test.go b/pkg/messagepool/messagepool_test.go index efc0f71947..f82ae3a172 100644 --- a/pkg/messagepool/messagepool_test.go +++ b/pkg/messagepool/messagepool_test.go @@ -690,6 +690,36 @@ func TestPruningSimple(t *testing.T) { } } +func TestGasRewardNegative(t *testing.T) { + var mp MessagePool + + msg := types.SignedMessage{ + Message: types.Message{ + GasLimit: 1000, + GasFeeCap: tbig.NewInt(20000), + GasPremium: tbig.NewInt(15000), + }, + } + baseFee := tbig.NewInt(30000) + // Over the GasPremium, but under the BaseFee + gr1 := mp.getGasReward(&msg, baseFee) + + msg.Message.GasFeeCap = tbig.NewInt(15000) + // Equal to GasPremium, under the BaseFee + gr2 := mp.getGasReward(&msg, baseFee) + + msg.Message.GasFeeCap = tbig.NewInt(10000) + // Under both GasPremium and BaseFee + gr3 := mp.getGasReward(&msg, baseFee) + + assert.True(t, gr1.Sign() < 0) + assert.True(t, gr2.Sign() < 0) + assert.True(t, gr3.Sign() < 0) + + assert.True(t, gr1.Cmp(gr2) > 0) + assert.True(t, gr2.Cmp(gr3) > 0) +} + func TestLoadLocal(t *testing.T) { tf.UnitTest(t) diff --git a/pkg/messagepool/selection_test.go b/pkg/messagepool/selection_test.go index 80bdcb7137..9387e53d52 100644 --- a/pkg/messagepool/selection_test.go +++ b/pkg/messagepool/selection_test.go @@ -12,6 +12,7 @@ import ( "os" "sort" "testing" + "time" "github.com/stretchr/testify/require" cbg "github.com/whyrusleeping/cbor-gen" @@ -1604,3 +1605,185 @@ readLoop: t.Fatalf("failed to pack with tq=0.01; packed %d, minimum packing: %d", gasLimit, minGasLimit) } } + +func TestRealWorldSelectionTiming(t *testing.T) { + //stm: @TOKEN_WALLET_NEW_001, @TOKEN_WALLET_SIGN_001, @CHAIN_MEMPOOL_SELECT_001 + + // load test-messages.json.gz and rewrite the messages so that + // 1) we map each real actor to a test actor so that we can sign the messages + // 2) adjust the nonces so that they start from 0 + file, err := os.Open("test-messages2.json.gz") + if err != nil { + t.Fatal(err) + } + + gzr, err := gzip.NewReader(file) + if err != nil { + t.Fatal(err) + } + + dec := json.NewDecoder(gzr) + + var msgs []*types.SignedMessage + baseNonces := make(map[address.Address]uint64) + +readLoop: + for { + m := new(types.SignedMessage) + err := dec.Decode(m) + switch err { + case nil: + msgs = append(msgs, m) + nonce, ok := baseNonces[m.Message.From] + if !ok || m.Message.Nonce < nonce { + baseNonces[m.Message.From] = m.Message.Nonce + } + + case io.EOF: + break readLoop + + default: + t.Fatal(err) + } + } + + actorMap := make(map[address.Address]address.Address) + actorWallets := make(map[address.Address]*wallet.Wallet) + + for _, m := range msgs { + baseNonce := baseNonces[m.Message.From] + + localActor, ok := actorMap[m.Message.From] + if !ok { + w := newWallet(t) + + a, err := w.NewAddress(context.Background(), address.SECP256K1) + if err != nil { + t.Fatal(err) + } + + actorMap[m.Message.From] = a + actorWallets[a] = w + localActor = a + } + + w, ok := actorWallets[localActor] + if !ok { + t.Fatalf("failed to lookup wallet for actor %s", localActor) + } + + m.Message.From = localActor + m.Message.Nonce -= baseNonce + + sig, err := w.WalletSign(context.TODO(), localActor, m.Message.Cid().Bytes(), types.MsgMeta{}) + if err != nil { + t.Fatal(err) + } + + m.Signature = *sig + } + + mp, tma := makeTestMpool() + + block := tma.nextBlockWithHeight(uint64(UpgradeBreezeHeight) + 10) + ts := mkTipSet(block) + tma.applyBlock(t, block) + + for _, a := range actorMap { + tma.setBalance(a, 1000000) + } + + tma.baseFee = types.NewInt(800_000_000) + + sort.Slice(msgs, func(i, j int) bool { + return msgs[i].Message.Nonce < msgs[j].Message.Nonce + }) + + // add the messages + for _, m := range msgs { + mustAdd(t, mp, m) + } + + // do message selection and check block packing + minGasLimit := int64(0.9 * float64(constants.BlockGasLimit)) + + // greedy first + start := time.Now() + selected, err := mp.SelectMessages(context.Background(), ts, 1.0) + if err != nil { + t.Fatal(err) + } + t.Logf("selected %d messages in %s", len(selected), time.Since(start)) + + gasLimit := int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=1.0; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // high quality ticket + start = time.Now() + selected, err = mp.SelectMessages(context.Background(), ts, .8) + if err != nil { + t.Fatal(err) + } + t.Logf("selected %d messages in %s", len(selected), time.Since(start)) + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.8; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // mid quality ticket + start = time.Now() + selected, err = mp.SelectMessages(context.Background(), ts, .4) + if err != nil { + t.Fatal(err) + } + t.Logf("selected %d messages in %s", len(selected), time.Since(start)) + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.4; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // low quality ticket + start = time.Now() + selected, err = mp.SelectMessages(context.Background(), ts, .1) + if err != nil { + t.Fatal(err) + } + t.Logf("selected %d messages in %s", len(selected), time.Since(start)) + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.1; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } + + // very low quality ticket + start = time.Now() + selected, err = mp.SelectMessages(context.Background(), ts, .01) + if err != nil { + t.Fatal(err) + } + t.Logf("selected %d messages in %s", len(selected), time.Since(start)) + + gasLimit = int64(0) + for _, m := range selected { + gasLimit += m.Message.GasLimit + } + if gasLimit < minGasLimit { + t.Fatalf("failed to pack with tq=0.01; packed %d, minimum packing: %d", gasLimit, minGasLimit) + } +} diff --git a/pkg/messagepool/test-messages2.json.gz b/pkg/messagepool/test-messages2.json.gz new file mode 100644 index 0000000000..9d2cfbfe4f Binary files /dev/null and b/pkg/messagepool/test-messages2.json.gz differ