From 926e8229217cdbc4a83686128b39796cbb95b14d Mon Sep 17 00:00:00 2001 From: hundredark Date: Mon, 27 Apr 2026 14:01:09 +0800 Subject: [PATCH 1/7] fix deterministic nonce --- common/aes.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/common/aes.go b/common/aes.go index dabc15e6..fc242586 100644 --- a/common/aes.go +++ b/common/aes.go @@ -3,6 +3,8 @@ package common import ( "crypto/aes" "crypto/cipher" + "crypto/rand" + "io" "github.com/MixinNetwork/mixin/crypto" "github.com/gofrs/uuid/v5" @@ -54,7 +56,12 @@ func AESEncrypt(secret, b []byte, sid string) []byte { if err != nil { panic(err) } - nonce := b[:aead.NonceSize()] + // The nonce must be unique for all time, for a given key + nonce := make([]byte, aead.NonceSize()) + _, err = io.ReadFull(rand.Reader, nonce) + if err != nil { + panic(err) + } cipher := aead.Seal(nil, nonce, b[aead.NonceSize():], nil) return append(nonce, cipher...) } From 22363914b8ba3191ab2b04c252384ea5fabe4196 Mon Sep 17 00:00:00 2001 From: hundredark Date: Mon, 27 Apr 2026 15:04:12 +0800 Subject: [PATCH 2/7] slight fix --- observer/bitcoin.go | 3 +++ observer/ethereum.go | 3 +++ observer/holder.go | 30 +++--------------------------- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/observer/bitcoin.go b/observer/bitcoin.go index 13626897..5a228a7c 100644 --- a/observer/bitcoin.go +++ b/observer/bitcoin.go @@ -984,6 +984,9 @@ func (node *Node) httpRevokeBitcoinTransaction(ctx context.Context, txHash strin if err != nil { return err } + if tx == nil || tx.State != common.RequestStateInitial { + return fmt.Errorf("HTTP: %d", http.StatusNotAcceptable) + } sig, err := base64.RawURLEncoding.DecodeString(sigBase64) if err != nil { diff --git a/observer/ethereum.go b/observer/ethereum.go index 672d9f40..acfe54f1 100644 --- a/observer/ethereum.go +++ b/observer/ethereum.go @@ -1079,6 +1079,9 @@ func (node *Node) httpRevokeEthereumTransaction(ctx context.Context, txHash stri if err != nil { return err } + if tx == nil || tx.State != common.RequestStateInitial { + return fmt.Errorf("HTTP: %d", http.StatusNotAcceptable) + } sig, err := hex.DecodeString(sigHex) if err != nil { diff --git a/observer/holder.go b/observer/holder.go index 4c5b46c6..795b6132 100644 --- a/observer/holder.go +++ b/observer/holder.go @@ -179,15 +179,7 @@ func (node *Node) httpCreateSafeAccountRecoveryRequest(ctx context.Context, addr if hash == "" || raw == "" { return fmt.Errorf("HTTP: %d", http.StatusNotAcceptable) } - proposed, err := node.store.CheckAccountProposed(ctx, addr) - if err != nil || !proposed { - return err - } - sp, err := node.keeperStore.ReadSafeProposalByAddress(ctx, addr) - if err != nil { - return err - } - safe, err := node.keeperStore.ReadSafe(ctx, sp.Holder) + safe, err := node.keeperStore.ReadSafeByAddress(ctx, addr) if err != nil { return err } @@ -207,15 +199,7 @@ func (node *Node) httpCreateSafeAccountRecoveryRequest(ctx context.Context, addr func (node *Node) httpSignAccountRecoveryRequest(ctx context.Context, addr, raw, hash string) error { logger.Printf("node.httpSignAccountRecoveryRequest(%s, %s, %s)", addr, raw, hash) - proposed, err := node.store.CheckAccountProposed(ctx, addr) - if err != nil || !proposed { - return err - } - sp, err := node.keeperStore.ReadSafeProposalByAddress(ctx, addr) - if err != nil { - return err - } - safe, err := node.keeperStore.ReadSafe(ctx, sp.Holder) + safe, err := node.keeperStore.ReadSafeByAddress(ctx, addr) if err != nil { return err } @@ -246,15 +230,7 @@ func (node *Node) httpSignAccountRecoveryRequest(ctx context.Context, addr, raw, func (node *Node) httpCloseAccountRecoveryRequest(ctx context.Context, addr, id, sig, hash string) error { logger.Printf("node.httpCloseAccountRecoveryRequest(%s, %s, %v)", addr, sig, hash) - proposed, err := node.store.CheckAccountProposed(ctx, addr) - if err != nil || !proposed { - return err - } - sp, err := node.keeperStore.ReadSafeProposalByAddress(ctx, addr) - if err != nil { - return err - } - safe, err := node.keeperStore.ReadSafe(ctx, sp.Holder) + safe, err := node.keeperStore.ReadSafeByAddress(ctx, addr) if err != nil { return err } From 571702f58b0a97ca40fadbfccf6a7e60e7b4a74e Mon Sep 17 00:00:00 2001 From: hundredark Date: Mon, 27 Apr 2026 20:11:03 +0800 Subject: [PATCH 3/7] slight fixes --- observer/accountant.go | 16 ++++++++++++++-- observer/http.go | 4 ++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/observer/accountant.go b/observer/accountant.go index a36b4eb5..6dc0f651 100644 --- a/observer/accountant.go +++ b/observer/accountant.go @@ -30,9 +30,15 @@ func (node *Node) keeperCombineBitcoinTransactionSignatures(ctx context.Context, spsbt, _ := bitcoin.UnmarshalPartiallySignedTransaction(extra) tx, err := node.store.ReadTransactionApproval(ctx, spsbt.Hash()) - if err != nil || tx.State >= common.RequestStateDone { + if err != nil { return err } + if tx == nil { + panic(spsbt.Hash()) + } + if tx.State >= common.RequestStateDone { + return nil + } switch tx.Chain { case common.SafeChainBitcoin: case common.SafeChainLitecoin: @@ -138,9 +144,15 @@ func (node *Node) keeperVerifyEthereumTransactionSignatures(ctx context.Context, raw := hex.EncodeToString(st.Marshal()) tx, err := node.store.ReadTransactionApproval(ctx, st.TxHash) - if err != nil || tx.State >= common.RequestStateDone { + if err != nil { return err } + if tx == nil { + panic(st.TxHash) + } + if tx.State >= common.RequestStateDone { + return nil + } safe, err := node.keeperStore.ReadSafe(ctx, tx.Holder) if err != nil { return err diff --git a/observer/http.go b/observer/http.go index 23b8843d..e311bcf6 100644 --- a/observer/http.go +++ b/observer/http.go @@ -263,6 +263,10 @@ func (node *Node) httpListNodes(w http.ResponseWriter, r *http.Request, typ stri func (node *Node) httpListDeposits(w http.ResponseWriter, r *http.Request, params map[string]string) { holder := r.URL.Query().Get("holder") chain, _ := strconv.ParseInt(r.URL.Query().Get("chain"), 10, 32) + if chain == 0 { + common.RenderJSON(w, r, http.StatusBadRequest, map[string]any{"error": "chain"}) + return + } offset, _ := strconv.ParseInt(r.URL.Query().Get("offset"), 10, 64) deposits, err := node.store.ListDeposits(r.Context(), int(chain), holder, 0, offset) if err != nil { From 97c377490487c7074c9e40dda3c570cc1055a47c Mon Sep 17 00:00:00 2001 From: hundredark Date: Tue, 28 Apr 2026 10:27:20 +0800 Subject: [PATCH 4/7] should panic when ReadKernelTransactionUntilSufficient --- keeper/bitcoin.go | 10 ++++++++-- keeper/ethereum.go | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/keeper/bitcoin.go b/keeper/bitcoin.go index dbc93563..f2f032ff 100644 --- a/keeper/bitcoin.go +++ b/keeper/bitcoin.go @@ -438,9 +438,15 @@ func (node *Node) processBitcoinSafeProposeAccount(ctx context.Context, req *com panic(req.Role) } rce := req.ExtraBytes() - ver, _ := node.group.ReadKernelTransactionUntilSufficient(ctx, req.MixinHash.String()) + ver, err := node.group.ReadKernelTransactionUntilSufficient(ctx, req.MixinHash.String()) + if err != nil { + panic(err) + } if len(rce) == 32 && len(ver.References) == 1 && ver.References[0].String() == req.ExtraHEX { - stx, _ := node.group.ReadKernelTransactionUntilSufficient(ctx, ver.References[0].String()) + stx, err := node.group.ReadKernelTransactionUntilSufficient(ctx, ver.References[0].String()) + if err != nil { + panic(err) + } rce = stx.Extra } arp, err := req.ParseMixinRecipient(ctx, node.mixin, rce) diff --git a/keeper/ethereum.go b/keeper/ethereum.go index 5815ff25..aabffc86 100644 --- a/keeper/ethereum.go +++ b/keeper/ethereum.go @@ -436,9 +436,15 @@ func (node *Node) processEthereumSafeProposeAccount(ctx context.Context, req *co panic(req.Curve) } rce := req.ExtraBytes() - ver, _ := node.group.ReadKernelTransactionUntilSufficient(ctx, req.MixinHash.String()) + ver, err := node.group.ReadKernelTransactionUntilSufficient(ctx, req.MixinHash.String()) + if err != nil { + panic(err) + } if len(rce) == 32 && len(ver.References) == 1 && bytes.Equal(ver.References[0][:], rce) { - stx, _ := node.group.ReadKernelTransactionUntilSufficient(ctx, ver.References[0].String()) + stx, err := node.group.ReadKernelTransactionUntilSufficient(ctx, ver.References[0].String()) + if err != nil { + panic(err) + } rce = stx.Extra } arp, err := req.ParseMixinRecipient(ctx, node.mixin, rce) From 7394b282d18f609577695b8a8c2bf4df773f7a96 Mon Sep 17 00:00:00 2001 From: hundredark Date: Tue, 28 Apr 2026 10:49:32 +0800 Subject: [PATCH 5/7] slight fixes --- apps/bitcoin/rpc.go | 2 +- observer/node.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/bitcoin/rpc.go b/apps/bitcoin/rpc.go index 05dd0712..be1e6e7c 100644 --- a/apps/bitcoin/rpc.go +++ b/apps/bitcoin/rpc.go @@ -91,7 +91,7 @@ func RPCGetTransactionOutput(chain byte, rpc, hash string, index int64) (*RPCTra output := &Output{ Address: out.ScriptPubKey.Address, Satoshi: satoshi.IntPart(), - Coinbase: len(tx.Vin) == 0 && tx.Vin[0].Coinbase != "", + Coinbase: len(tx.Vin) > 0 && tx.Vin[0].Coinbase != "", } if tx.BlockHash == "" { // mempool diff --git a/observer/node.go b/observer/node.go index 07b9c7fd..45e40855 100644 --- a/observer/node.go +++ b/observer/node.go @@ -216,6 +216,7 @@ func (node *Node) sendAccountApprovals(ctx context.Context) { panic(err) } } + time.Sleep(5 * time.Second) } } From a3eae6a10b64212cdee7a63ef77051b02137ad96 Mon Sep 17 00:00:00 2001 From: hundredark Date: Tue, 28 Apr 2026 14:03:45 +0800 Subject: [PATCH 6/7] fix AESDecrypt --- common/aes.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/aes.go b/common/aes.go index fc242586..ebe046e6 100644 --- a/common/aes.go +++ b/common/aes.go @@ -38,7 +38,7 @@ func AESDecrypt(secret, b []byte) []byte { if err != nil { panic(err) } - return append(nonce, d...) + return d } func AESEncrypt(secret, b []byte, sid string) []byte { @@ -62,6 +62,6 @@ func AESEncrypt(secret, b []byte, sid string) []byte { if err != nil { panic(err) } - cipher := aead.Seal(nil, nonce, b[aead.NonceSize():], nil) + cipher := aead.Seal(nil, nonce, b, nil) return append(nonce, cipher...) } From 276bad6e65d9ddab4678bbd9d926e6d7aac2f830 Mon Sep 17 00:00:00 2001 From: hundredark Date: Sun, 3 May 2026 18:01:01 +0800 Subject: [PATCH 7/7] improve GetERC20TransferLogFromBlock --- apps/ethereum/rpc.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/ethereum/rpc.go b/apps/ethereum/rpc.go index b5ed3b54..2d4e4896 100644 --- a/apps/ethereum/rpc.go +++ b/apps/ethereum/rpc.go @@ -288,9 +288,14 @@ func GetERC20TransferLogFromBlock(ctx context.Context, rpc string, chain, height if err != nil { return nil, err } + defer client.Close() + + logTransferSig := []byte("Transfer(address,address,uint256)") + logTransferSigHash := crypto.Keccak256Hash(logTransferSig) query := ethereum.FilterQuery{ FromBlock: big.NewInt(height), ToBlock: big.NewInt(height), + Topics: [][]common.Hash{{logTransferSigHash}}, } contractAbi, err := ga.JSON(strings.NewReader(abi.AssetABI)) if err != nil { @@ -300,8 +305,6 @@ func GetERC20TransferLogFromBlock(ctx context.Context, rpc string, chain, height if err != nil { return nil, err } - logTransferSig := []byte("Transfer(address,address,uint256)") - logTransferSigHash := crypto.Keccak256Hash(logTransferSig) ts := []*Transfer{} for _, vLog := range logs {