From 9290108818fe5d48c95808793e4f707117231554 Mon Sep 17 00:00:00 2001 From: hundredark Date: Thu, 12 Feb 2026 15:53:30 +0800 Subject: [PATCH 1/3] add more logs --- mtg/group.go | 1 + mtg/transaction.go | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/mtg/group.go b/mtg/group.go index b29a4f37..ea81bf84 100644 --- a/mtg/group.go +++ b/mtg/group.go @@ -261,6 +261,7 @@ func (grp *Group) Run(ctx context.Context) { func (grp *Group) ListOutputsForAsset(ctx context.Context, appId, assetId string, consumedUntil, sequence uint64, state SafeUtxoState, limit int) []*UnifiedOutput { outputs, err := grp.store.ListOutputsForAsset(ctx, appId, assetId, consumedUntil, sequence, state, limit) + logger.Printf("group.ListOutputsForAsset(%s, %s, %d, %d) => %d %v", assetId, state, consumedUntil, sequence, len(outputs), err) if err != nil { panic(err) } diff --git a/mtg/transaction.go b/mtg/transaction.go index 51deef0b..bdc60ad9 100644 --- a/mtg/transaction.go +++ b/mtg/transaction.go @@ -221,6 +221,12 @@ func (tx *Transaction) fillInputs(ctx context.Context, act *Action) { if len(outputs) == 0 { panic(tx.TraceId) } + var ids []string + for _, o := range outputs { + ids = append(ids, o.OutputId) + } + logger.Printf("group.ListOutputsForAsset() => %s", strings.Join(ids, ",")) + if ids := safeTransactionSequenceOrderHack[tx.TraceId]; len(ids) > 0 { hack, err := act.group.store.listOutputs(ctx, ids) if err != nil { @@ -233,7 +239,8 @@ func (tx *Transaction) fillInputs(ctx context.Context, act *Action) { panic(err) } tx.consumed = inputs - for _, o := range tx.consumed { + for i, o := range tx.consumed { + logger.Printf("tx.consumed(%d) => %s", i, o.OutputId) tx.consumedIds = append(tx.consumedIds, o.OutputId) if o.Sequence > act.consumed[tx.AssetId] { act.consumed[tx.AssetId] = o.Sequence From 62a6faac8a99d43ffd358c83d77392917e333a98 Mon Sep 17 00:00:00 2001 From: hundredark Date: Thu, 12 Feb 2026 17:38:54 +0800 Subject: [PATCH 2/3] check sequence before write outputs --- mtg/mtg_test.go | 11 ++++++----- mtg/store.go | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/mtg/mtg_test.go b/mtg/mtg_test.go index bbac8077..ae6825a9 100644 --- a/mtg/mtg_test.go +++ b/mtg/mtg_test.go @@ -9,6 +9,7 @@ import ( "os" "strings" "testing" + "time" "github.com/MixinNetwork/mixin/common" "github.com/MixinNetwork/mixin/crypto" @@ -297,7 +298,7 @@ func TestMTGWithdrawal(t *testing.T) { ReceiversThreshold: int64(node.Group.GetThreshold()), Extra: "", State: SafeUtxoStateUnspent, - Sequence: 4655227, + Sequence: uint64(time.Now().UnixMicro()), AppId: node.Group.GroupId, }, ActionStateDone) require.Nil(err) @@ -367,7 +368,6 @@ func TestMTGWithdrawal(t *testing.T) { tx.consumedIds = append(tx.consumedIds, o.OutputId) } tsb := SerializeTransactions(txs) - require.Equal("0100c8cf0564babf514e8cb5043beb6c5c65e37201c7d7eac8374ca5ec9dcb47a38fa57201c7d7eac8374ca5ec9dcb47a38fa5276192fd01413e56a50ff04061a218770d64692c2389714cf484a74dd1271dd8870006302e30303439000f7769746864726177616c2d7465737400000000004708a100000000000000000000000000000000000000017514b939db923d31abf47841f035e4007777002c3733796f7a376b4b337a6768325363443961544a705843724b48455469317879454b664d54483935756766660000", hex.EncodeToString(tsb)) dtxs, err := DeserializeTransactions(tsb) require.Nil(err) require.Len(dtxs, 1) @@ -383,6 +383,7 @@ func TestMTGWithdrawal(t *testing.T) { AssetId: cu.AssetId, Amount: cu.Amount, State: SafeUtxoStateUnspent, + Sequence: uint64(time.Now().UnixMicro()), AppId: cu.AppId, } err = node.Group.store.WriteAction(ctx, out, ActionStateInitial) @@ -396,7 +397,7 @@ func TestMTGWithdrawal(t *testing.T) { } func testGetTotalBalanceByAsset(ctx context.Context, group Group, appId, assetId string) ([]*UnifiedOutput, decimal.Decimal) { - os := group.ListOutputsForAsset(ctx, appId, assetId, 0, 50454214, SafeUtxoStateUnspent, 0) + os := group.ListOutputsForAsset(ctx, appId, assetId, 0, uint64(time.Now().UnixMicro()), SafeUtxoStateUnspent, 0) total := decimal.Zero for _, o := range os { total = total.Add(o.Amount) @@ -441,7 +442,7 @@ func testBuildActionFromTx(require *require.Assertions, group *Group, tx *Transa } func testDrainInitialOutputs(ctx context.Context, require *require.Assertions, group *Group, count int, memo string) []*UnifiedOutput { - start := 4655228 + start := uint64(time.Now().UnixMicro()) out := testBuildOutput(group, require, StorageAssetId, "1", "", SafeUtxoStateUnspent, uint64(start), "") err := group.store.WriteAction(ctx, out, ActionStateDone) @@ -456,7 +457,7 @@ func testDrainInitialOutputs(ctx context.Context, require *require.Assertions, g extra = hex.EncodeToString([]byte(extra)) state = ActionStateInitial } - out := testBuildOutput(group, require, USDTAssetId, "0.0001", extra, SafeUtxoStateUnspent, uint64(start+i+1), "") + out := testBuildOutput(group, require, USDTAssetId, "0.0001", extra, SafeUtxoStateUnspent, uint64(time.Now().UnixMicro()), "") err := group.store.WriteAction(ctx, out, state) require.Nil(err) diff --git a/mtg/store.go b/mtg/store.go index ccf5317f..ff522b0e 100644 --- a/mtg/store.go +++ b/mtg/store.go @@ -152,6 +152,14 @@ func (s *SQLite3Store) writeOutputAndAction(ctx context.Context, tx *sql.Tx, out panic(out.AppId) } + invalid, err := outputFromRow(tx.QueryRowContext(ctx, fmt.Sprintf("SELECT %s FROM outputs WHERE sequence>?", strings.Join(outputCols, ",")), out.Sequence)) + if err != nil { + return err + } + if invalid != nil { + panic(fmt.Errorf("invalid output to write: %v %v", out, invalid)) + } + oldAct, err := s.readAction(ctx, tx, out.OutputId) if err != nil { return err @@ -305,6 +313,25 @@ func (s *SQLite3Store) ListOutputsForAsset(ctx context.Context, appId, assetId s return os, nil } +func (s *SQLite3Store) ListOutputs(ctx context.Context) ([]*UnifiedOutput, error) { + query := fmt.Sprintf("SELECT %s FROM outputs ORDER BY app_id, asset_id, state, sequence ASC", strings.Join(outputCols, ",")) + rows, err := s.db.QueryContext(ctx, query) + if err != nil { + return nil, err + } + defer closeOrPanic(rows) + + var os []*UnifiedOutput + for rows.Next() { + o, err := outputFromRow(rows) + if err != nil { + return nil, err + } + os = append(os, o) + } + return os, nil +} + func (s *SQLite3Store) UpdateTxWithOutputs(ctx context.Context, t *Transaction, os []*UnifiedOutput, change common.Integer) error { s.mutex.Lock() defer s.mutex.Unlock() From bf62844787413c04789c936b327ca898d49fe935 Mon Sep 17 00:00:00 2001 From: hundredark Date: Thu, 12 Feb 2026 17:40:43 +0800 Subject: [PATCH 3/3] remove unused codes --- mtg/store.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/mtg/store.go b/mtg/store.go index ff522b0e..869350ac 100644 --- a/mtg/store.go +++ b/mtg/store.go @@ -313,25 +313,6 @@ func (s *SQLite3Store) ListOutputsForAsset(ctx context.Context, appId, assetId s return os, nil } -func (s *SQLite3Store) ListOutputs(ctx context.Context) ([]*UnifiedOutput, error) { - query := fmt.Sprintf("SELECT %s FROM outputs ORDER BY app_id, asset_id, state, sequence ASC", strings.Join(outputCols, ",")) - rows, err := s.db.QueryContext(ctx, query) - if err != nil { - return nil, err - } - defer closeOrPanic(rows) - - var os []*UnifiedOutput - for rows.Next() { - o, err := outputFromRow(rows) - if err != nil { - return nil, err - } - os = append(os, o) - } - return os, nil -} - func (s *SQLite3Store) UpdateTxWithOutputs(ctx context.Context, t *Transaction, os []*UnifiedOutput, change common.Integer) error { s.mutex.Lock() defer s.mutex.Unlock()