Skip to content

Commit

Permalink
feat: make polka chain api lazily
Browse files Browse the repository at this point in the history
  • Loading branch information
iosguang committed Apr 15, 2022
1 parent 97ab07b commit ecd4bac
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 43 deletions.
33 changes: 33 additions & 0 deletions core/btc/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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())
}
18 changes: 9 additions & 9 deletions core/wallet/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
39 changes: 37 additions & 2 deletions core/wallet/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package wallet

import (
"testing"
"time"
)

func TestQueryBalance(t *testing.T) {
Expand Down Expand Up @@ -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"

Expand All @@ -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)
}
75 changes: 43 additions & 32 deletions core/wallet/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand All @@ -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
Expand Down

0 comments on commit ecd4bac

Please sign in to comment.