From ecd4bac46c1b5078da3845447a63f1f2490ed11c Mon Sep 17 00:00:00 2001 From: GG Date: Thu, 14 Apr 2022 17:50:02 +0800 Subject: [PATCH] feat: make polka chain api lazily --- core/btc/utils_test.go | 33 +++++++++++++++++ core/wallet/chain.go | 18 +++++----- core/wallet/chain_test.go | 39 ++++++++++++++++++-- core/wallet/client.go | 75 ++++++++++++++++++++++----------------- 4 files changed, 122 insertions(+), 43 deletions(-) diff --git a/core/btc/utils_test.go b/core/btc/utils_test.go index 0d1d1e9..13e8a69 100644 --- a/core/btc/utils_test.go +++ b/core/btc/utils_test.go @@ -3,9 +3,12 @@ package btc import ( "testing" + "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/centrifuge/go-substrate-rpc-client/v4/types" + "github.com/cosmos/go-bip39" ) func TestValidAddress(t *testing.T) { @@ -113,3 +116,33 @@ func TestSbtcDetail(t *testing.T) { } t.Log(detail) } + +func TestBTCWallet_Privatekey_Publickey_Address(t *testing.T) { + // 从 coming 的 musig 库计算的测试用例 + // private key = 0x7490eb31c8fa940cfd8b0c307ae6f694e7477ea53dec6f14b682ccc960b1784f + // public key = 0x043505763c9a201e2ac34955aa73c33894731e53975990b3808f6331412159deac36e4584cf8f4044943f4684bfb3c87995cbc5d47009d368443a1c0b331558de0 + // mainnet address = bc1px5zhv0y6yq0z4s6f2k488secj3e3u5uhtxgt8qy0vvc5zg2em6kqahndud + // signet address = tb1px5zhv0y6yq0z4s6f2k488secj3e3u5uhtxgt8qy0vvc5zg2em6kq2l9zxz + + phrase := "police saddle quote salon run split notice taxi expand uniform zone excess" + data, _ := bip39.NewSeedWithErrorChecking(phrase, "") + + pri, pub := btcec.PrivKeyFromBytes(data) + priHex := types.HexEncodeToString(pri.Serialize()) + pubHex := types.HexEncodeToString(pub.SerializeUncompressed()) + t.Log("private key = ", priHex) + t.Log("public key = ", pubHex) + + pubData := pub.SerializeUncompressed() + addressHash, err := btcutil.NewAddressTaproot(pubData[1:33], &chaincfg.MainNetParams) + if err != nil { + t.Fatal(err) + } + t.Log("mainnet address = ", addressHash.EncodeAddress()) + + addressHash, err = btcutil.NewAddressTaproot(pubData[1:33], &chaincfg.SigNetParams) + if err != nil { + t.Fatal(err) + } + t.Log("signet address = ", addressHash.EncodeAddress()) +} diff --git a/core/wallet/chain.go b/core/wallet/chain.go index 7cbe647..4f0d41f 100644 --- a/core/wallet/chain.go +++ b/core/wallet/chain.go @@ -53,7 +53,7 @@ func NewPolkaChain(rpcUrl, scanUrl string) *PolkaChain { // @param rpcUrl 链端 rpc 地址 // @param scanUrl 浏览器地址(查询交易详情需要的) func NewPolkaChainWithRpc(rpcUrl, scanUrl string, metadataString string) (*PolkaChain, error) { - _, err := getPolkaClientWithMetadata(rpcUrl, metadataString) + _, err := getOrCreatePolkaClient(rpcUrl, metadataString) if err != nil { return nil, err } @@ -65,7 +65,7 @@ func NewPolkaChainWithRpc(rpcUrl, scanUrl string, metadataString string) (*Polka // 获取该链的 metadata string (如果没有会自动下载) func (c *PolkaChain) GetMetadataString() (s string, err error) { - client, err := getPolkaClient(c.RpcUrl) + client, err := getConnectedPolkaClient(c.RpcUrl) if err != nil { return } @@ -74,7 +74,7 @@ func (c *PolkaChain) GetMetadataString() (s string, err error) { // 刷新最新的 metadata (可以从返回值读取到最新的 metadata) func (c *PolkaChain) ReloadMetadata() (s string, err error) { - client, err := getPolkaClient(c.RpcUrl) + client, err := getConnectedPolkaClient(c.RpcUrl) if err != nil { return } @@ -110,7 +110,7 @@ func (c *PolkaChain) QueryBalancePubkey(pubkey string) (*PolkaBalance, error) { func (c *PolkaChain) queryBalance(pubkey []byte) (b *PolkaBalance, err error) { b = emptyBalance() - client, err := getPolkaClient(c.RpcUrl) + client, err := getConnectedPolkaClient(c.RpcUrl) if err != nil { return } @@ -167,7 +167,7 @@ func (c *PolkaChain) queryBalance(pubkey []byte) (b *PolkaBalance, err error) { func (c *PolkaChain) QueryBalanceXBTC(address string) (b *PolkaBalance, err error) { b = emptyBalance() - client, err := getPolkaClient(c.RpcUrl) + client, err := getConnectedPolkaClient(c.RpcUrl) if err != nil { return } @@ -242,7 +242,7 @@ func (c *PolkaChain) EstimateFeeForTransaction(transaction *Transaction) (s stri return } - cl, err := getPolkaClient(c.RpcUrl) + cl, err := getConnectedPolkaClient(c.RpcUrl) data := make(map[string]interface{}) err = client.CallWithBlockHash(cl.api.Client, &data, "payment_queryInfo", nil, sendTx) if err != nil { @@ -259,7 +259,7 @@ func (c *PolkaChain) EstimateFeeForTransaction(transaction *Transaction) (s stri // 发起交易 func (c *PolkaChain) SendRawTransaction(txHex string) (s string, err error) { - client, err := getPolkaClient(c.RpcUrl) + client, err := getConnectedPolkaClient(c.RpcUrl) if err != nil { return } @@ -348,7 +348,7 @@ func (c *PolkaChain) SdkBatchTransactionStatus(hashListString string) string { // 功能和 GetSignData 相同,不需要提供 nonce, version 等参数,但需要提供 chain 对象和地址 func (t *Transaction) GetSignDataFromChain(chain *PolkaChain, walletAddress string) ([]byte, error) { - cl, err := getPolkaClient(chain.RpcUrl) + cl, err := getConnectedPolkaClient(chain.RpcUrl) if err != nil { return nil, err } @@ -381,7 +381,7 @@ type MiniXScriptHash struct { // @param transferTo 转账目标地址 // @param amount 要转出的金额 func (c *PolkaChain) FetchScriptHashForMiniX(transferTo, amount string) (*MiniXScriptHash, error) { - cl, err := getPolkaClient(c.RpcUrl) + cl, err := getConnectedPolkaClient(c.RpcUrl) if err != nil { return nil, err } diff --git a/core/wallet/chain_test.go b/core/wallet/chain_test.go index 2b41516..28824d9 100644 --- a/core/wallet/chain_test.go +++ b/core/wallet/chain_test.go @@ -2,6 +2,7 @@ package wallet import ( "testing" + "time" ) func TestQueryBalance(t *testing.T) { @@ -129,8 +130,8 @@ func TestMINIScriptHash(t *testing.T) { func TestEstimatedFee(t *testing.T) { rpcUrl := "https://rpc-minichain.coming.chat" - // rpcUrl := "https://mainnet.chainx.org/rpc" - // rpcUrl := "https://mainnet.sherpax.io/rpc" + rpcUrl = "https://mainnet.chainx.org/rpc" + rpcUrl = "https://mainnet.sherpax.io/rpc" address := "5RNt3DACYRhwHyy9esTZXVvffkFL3pQHv4qoEMFVfDqeDEnH" amount := "10000" @@ -145,3 +146,37 @@ func TestEstimatedFee(t *testing.T) { } t.Log(fee) } + +func TestChainTimeCost(t *testing.T) { + rpcUrl := "wss://testnet3.chainx.org" + + t.Log("测试.............", "kjnjk") + + start := time.Now() + c1, _ := newPolkaClient(rpcUrl, "") + metadata, err := c1.MetadataString() + + cost := time.Since(start) + t.Log("metadata 是否获取成功:", err == nil) + t.Log("不使用 metadata 初始化的耗时:", cost) + + t.Log("---------------------------") + + start = time.Now() + c2, _ := newPolkaClient(rpcUrl, metadata) + _, err = c2.MetadataString() + + cost = time.Since(start) + t.Log("metadata 是否获取成功:", err == nil) + t.Log("使用 metadata 初始化的耗时:", cost) + + t.Log("--------------------------- 再测一次,不使用 metadata 初始化") + + start = time.Now() + c3, _ := newPolkaClient(rpcUrl, "") + _, err = c3.MetadataString() + + cost = time.Since(start) + t.Log("metadata 是否获取成功:", err == nil) + t.Log("第二次不使用 metadata 初始化的耗时:", cost) +} diff --git a/core/wallet/client.go b/core/wallet/client.go index 3dcfa6e..4b9f0b7 100644 --- a/core/wallet/client.go +++ b/core/wallet/client.go @@ -7,46 +7,46 @@ import ( "github.com/centrifuge/go-substrate-rpc-client/v4/types" ) -func xx() { - x, _ := gsrpc.NewSubstrateAPI("") - x.RPC.State.GetMetadataLatest() -} - type polkaclient struct { api *gsrpc.SubstrateAPI metadata *types.Metadata rpcUrl string } -func newPolkaClient(rpcUrl string, metadataString string) (*polkaclient, error) { - api, err := gsrpc.NewSubstrateAPI(rpcUrl) - if err != nil { - return nil, err - } - - var metadata *types.Metadata - if metadataString == "" { - metadata, err = api.RPC.State.GetMetadataLatest() +func newPolkaClient(rpcUrl, metadataString string) (*polkaclient, error) { + if len(metadataString) > 0 { + var metadata types.Metadata + err := types.DecodeFromHexString(metadataString, &metadata) if err != nil { - return nil, err + return nil, ErrWrongMetadata } + return &polkaclient{ + rpcUrl: rpcUrl, + metadata: &metadata, + }, nil } else { - var meta types.Metadata - err = types.DecodeFromHexString(metadataString, &meta) + return &polkaclient{ + rpcUrl: rpcUrl, + }, nil + } +} + +func (c *polkaclient) connectApiIfNeeded() error { + if c.api == nil { + api, err := gsrpc.NewSubstrateAPI(c.rpcUrl) if err != nil { - return nil, ErrWrongMetadata + return err } - metadata = &meta + c.api = api } - - return &polkaclient{ - api: api, - metadata: metadata, - rpcUrl: rpcUrl, - }, nil + return nil } func (c *polkaclient) ReloadMetadata() error { + err := c.connectApiIfNeeded() + if err != nil { + return err + } meta, err := c.api.RPC.State.GetMetadataLatest() if err != nil { return err @@ -56,10 +56,10 @@ func (c *polkaclient) ReloadMetadata() error { } func (c *polkaclient) LoadMetadataIfNotExists() error { - if c.metadata != nil { - return nil + if c.metadata == nil { + return c.ReloadMetadata() } - return c.ReloadMetadata() + return nil } func (c *polkaclient) MetadataString() (string, error) { @@ -75,12 +75,23 @@ func (c *polkaclient) MetadataString() (string, error) { var clientConnections = make(map[string]*polkaclient) var lock sync.RWMutex -// 通过 rpcUrl, 获取 eth 的连接对象 -func getPolkaClient(rpcUrl string) (*polkaclient, error) { - return getPolkaClientWithMetadata(rpcUrl, "") +// 通过 rpcUrl, 获取 polka 的连接对象 +func getConnectedPolkaClient(rpcUrl string) (*polkaclient, error) { + c, err := getOrCreatePolkaClient(rpcUrl, "") + if err != nil { + return nil, err + } + err = c.connectApiIfNeeded() + if err != nil { + return nil, err + } + return c, nil } -func getPolkaClientWithMetadata(rpcUrl, metadata string) (*polkaclient, error) { +func getOrCreatePolkaClient(rpcUrl, metadata string) (*polkaclient, error) { + // 我们不会考虑覆盖 metadata + // 假设用户只能从 sdk 里面获取到 metadata + // 那么无论如何从外部传入的 metadata 肯定不会比 sdk 内部的 metadata 更新 chain, ok := clientConnections[rpcUrl] if ok { return chain, nil